pax_global_header00006660000000000000000000000064125500316740014515gustar00rootroot0000000000000052 comment=0c58c183cf65550dd88dea247cc6de83861b87a8 gammaray-2.3.0/000077500000000000000000000000001255003167400133155ustar00rootroot00000000000000gammaray-2.3.0/.emacs-dirvars000066400000000000000000000005241255003167400160570ustar00rootroot00000000000000;; -*- emacs-lisp -*- ;; ;; This file is processed by the dirvars emacs package. Each variable ;; setting below is performed when this dirvars file is loaded. ;; indent-tabs-mode: nil tab-width: 8 c-basic-offset: 2 evaluate: (c-set-offset 'innamespace '0) evaluate: (c-set-offset 'inline-open '0) kdab-qt-version: 4 magic-parens-mode: nil gammaray-2.3.0/.gitignore000066400000000000000000000001671255003167400153110ustar00rootroot00000000000000# general *.kdev4 *~ *.rej *.orig *.out .* CMakeLists.txt.user # from kdiff3 *.BACKUP.* *.BASE.* *.LOCAL.* *.REMOTE.* gammaray-2.3.0/.kateconfig000066400000000000000000000001431255003167400154260ustar00rootroot00000000000000// kate: space-indent on; indent-width 2; remove-trailing-space on; remove-trailing-space-save on; gammaray-2.3.0/.krazy000066400000000000000000000016451255003167400144640ustar00rootroot00000000000000CHECKSETS qt4,c++,foss #KDAB-specific checks EXTRA kdabcopyright #additional checks EXTRA defines,null #EXTRA style #coding style settings STYLE_CPPSTYLE kde STYLE_OFFSET 2 STYLE_LINEMAX 100 #skip over known invalid desktop files SKIP /plugins/.*/.*\.desktop$ #no need to check 3rdparty stuff SKIP /3rdparty/ #nor Nokia's stuff SKIP /qmldebugcontrol/ SKIP /modeltest.cpp|/modeltest.h SKIP /processlist_unix.cpp|/processlist_win.cpp|/processlist.h SKIP /launcher/processlist.h|/launcher/injector/interactiveprocess.cpp|/launcher/injector/interactiveprocess.h SKIP StackWalker #if you have a build subdir, skip it SKIP /build- SKIP Doxyfile.cmake #skip the borrowed code in the cmake subdir SKIP /cmake/MacroLogFeature.cmake|/cmake/ECMQt4To5Porting.cmake|/cmake/FindGraphviz.cmake|/cmake/Toolchain-QNX65.cmake|/cmake/Toolchain-android.cmake|/cmake/Toolchain-QNX66.cmake|/cmake/ECMGeneratePriFile.cmake|/cmake/ECMQueryQmake.cmake gammaray-2.3.0/3rdparty/000077500000000000000000000000001255003167400150655ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/StackWalker/000077500000000000000000000000001255003167400173005ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/StackWalker/StackWalker.cpp000066400000000000000000001373431255003167400222320ustar00rootroot00000000000000/********************************************************************** * * StackWalker.cpp * http://stackwalker.codeplex.com/ * * * History: * 2005-07-27 v1 - First public release on http://www.codeproject.com/ * http://www.codeproject.com/threads/StackWalker.asp * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack * (to simplify the usage) * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL * (should also be enough) * - Changed to compile correctly with the PSDK of VC7.0 * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: * it uses LPSTR instead of LPCSTR as first paremeter) * - Added declarations to support VC5/6 without using 'dbghelp.h' * - Added a 'pUserData' member to the ShowCallstack function and the * PReadProcessMemoryRoutine declaration (to pass some user-defined data, * which can be used in the readMemoryFunction-callback) * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default * - Added example for doing an exception-callstack-walking in main.cpp * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx * Fixed Bug: Compiling with "/Wall" * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx * Fixed Bug: Now checking SymUseSymSrv * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx * Fixed Bug: Support for recursive function calls * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx * Fixed Bug: SymDia is number 7, not 9! * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! * Thanks to Teajay which reported the bug... * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory * Thanks to Luiz Salamon which reported this "bug"... * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx * 2009-04-10 v9 License slihtly corrected ( replaced) * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available * 2010-04-15 v12 Added support for VS2010 RTM * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx * * LICENSE (http://www.opensource.org/licenses/bsd-license.php) * * Copyright (c) 2005-2011, Jochen Kalmbach * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of Jochen Kalmbach nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ #include #include #include #include #pragma comment(lib, "version.lib") // for "VerQueryValue" #pragma warning(disable:4826) #include "StackWalker.h" // If VC7 and later, then use the shipped 'dbghelp.h'-file #pragma pack(push,8) #if _MSC_VER >= 1300 #include #else // inline the important dbghelp.h-declarations... typedef enum { SymNone = 0, SymCoff, SymCv, SymPdb, SymExport, SymDeferred, SymSym, SymDia, SymVirtual, NumSymTypes } SYM_TYPE; typedef struct _IMAGEHLP_LINE64 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) PVOID Key; // internal DWORD LineNumber; // line number in file PCHAR FileName; // full filename DWORD64 Address; // first instruction of line } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; typedef struct _IMAGEHLP_MODULE64 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module DWORD ImageSize; // virtual size of the loaded module DWORD TimeDateStamp; // date/time stamp from pe header DWORD CheckSum; // checksum from the pe header DWORD NumSyms; // number of symbols in the symbol table SYM_TYPE SymType; // type of symbols loaded CHAR ModuleName[32]; // module name CHAR ImageName[256]; // image name CHAR LoadedImageName[256]; // symbol file name } IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; typedef struct _IMAGEHLP_SYMBOL64 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) DWORD64 Address; // virtual address including dll base address DWORD Size; // estimated size of symbol, can be zero DWORD Flags; // info about the symbols, see the SYMF defines DWORD MaxNameLength; // maximum size of symbol name in 'Name' CHAR Name[1]; // symbol name (null terminated string) } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; typedef enum { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat } ADDRESS_MODE; typedef struct _tagADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; } ADDRESS64, *LPADDRESS64; typedef struct _KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 Reserved[8]; } KDHELP64, *PKDHELP64; typedef struct _tagSTACKFRAME64 { ADDRESS64 AddrPC; // program counter ADDRESS64 AddrReturn; // return address ADDRESS64 AddrFrame; // frame pointer ADDRESS64 AddrStack; // stack pointer ADDRESS64 AddrBStore; // backing store pointer PVOID FuncTableEntry; // pointer to pdata/fpo or NULL DWORD64 Params[4]; // possible arguments to the function BOOL Far; // WOW far call BOOL Virtual; // is this a virtual frame? DWORD64 Reserved[3]; KDHELP64 KdHelp; } STACKFRAME64, *LPSTACKFRAME64; typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead ); typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE hProcess, DWORD64 AddrBase ); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)( HANDLE hProcess, DWORD64 Address ); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( HANDLE hProcess, HANDLE hThread, LPADDRESS64 lpaddr ); #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_DEBUG 0x80000000 #define UNDNAME_COMPLETE (0x0000) // Enable full undecoration #define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; #endif // _MSC_VER < 1300 #pragma pack(pop) // Some missing defines (for VC5/6): #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif // secure-CRT_functions are only available starting with VC8 #if _MSC_VER < 1400 #define strcpy_s strcpy #define strncpy_s strncpy #define strcat_s(dst, len, src) strcat(dst, src) #define _snprintf_s _snprintf #define _tcscat_s _tcscat #endif static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) { if (nMaxDestSize <= 0) return; if (strlen(szSrc) < nMaxDestSize) { strcpy_s(szDest, nMaxDestSize, szSrc); } else { strncpy_s(szDest, nMaxDestSize, szSrc, nMaxDestSize); szDest[nMaxDestSize-1] = 0; } } // MyStrCpy // Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') #define USED_CONTEXT_FLAGS CONTEXT_FULL class StackWalkerInternal { public: StackWalkerInternal(StackWalker *parent, HANDLE hProcess) { m_parent = parent; m_hDbhHelp = NULL; pSC = NULL; m_hProcess = hProcess; m_szSymPath = NULL; pSFTA = NULL; pSGLFA = NULL; pSGMB = NULL; pSGMI = NULL; pSGO = NULL; pSGSFA = NULL; pSI = NULL; pSLM = NULL; pSSO = NULL; pSW = NULL; pUDSN = NULL; pSGSP = NULL; } ~StackWalkerInternal() { if (pSC != NULL) pSC(m_hProcess); // SymCleanup if (m_hDbhHelp != NULL) FreeLibrary(m_hDbhHelp); m_hDbhHelp = NULL; m_parent = NULL; if(m_szSymPath != NULL) free(m_szSymPath); m_szSymPath = NULL; } BOOL Init(LPCSTR szSymPath) { if (m_parent == NULL) return FALSE; // Dynamically load the Entry-Points for dbghelp.dll: // First try to load the newsest one from TCHAR szTemp[4096]; // But before wqe do this, we first check if the ".local" file exists if (GetModuleFileName(NULL, szTemp, 4096) > 0) { _tcscat_s(szTemp, _T(".local")); if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) { // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" // Ok, first try the new path according to the archtitecture: #ifdef _M_IX86 if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) { _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); // now check if the file exists: if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { m_hDbhHelp = LoadLibrary(szTemp); } } #elif _M_X64 if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) { _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); // now check if the file exists: if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { m_hDbhHelp = LoadLibrary(szTemp); } } #elif _M_IA64 if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) { _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); // now check if the file exists: if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { m_hDbhHelp = LoadLibrary(szTemp); } } #endif // If still not found, try the old directories... if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) { _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); // now check if the file exists: if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { m_hDbhHelp = LoadLibrary(szTemp); } } #if defined _M_X64 || defined _M_IA64 // Still not found? Then try to load the (old) 64-Bit version: if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) { _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { m_hDbhHelp = LoadLibrary(szTemp); } } #endif } } if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") ); if (m_hDbhHelp == NULL) return FALSE; pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" ); pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" ); pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" ); pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" ); pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" ); pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" ); pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" ); pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" ); pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" ); pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" ); pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" ); pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" ); if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL || pSLM == NULL ) { FreeLibrary(m_hDbhHelp); m_hDbhHelp = NULL; pSC = NULL; return FALSE; } // SymInitialize if (szSymPath != NULL) m_szSymPath = _strdup(szSymPath); if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); DWORD symOptions = this->pSGO(); // SymGetOptions symOptions |= SYMOPT_LOAD_LINES; symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; //symOptions |= SYMOPT_NO_PROMPTS; // SymSetOptions symOptions = this->pSSO(symOptions); char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; if (this->pSGSP != NULL) { if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); } char szUserName[1024] = {0}; DWORD dwSize = 1024; GetUserNameA(szUserName, &dwSize); this->m_parent->OnSymInit(buf, symOptions, szUserName); return TRUE; } StackWalker *m_parent; HMODULE m_hDbhHelp; HANDLE m_hProcess; LPSTR m_szSymPath; #pragma pack(push,8) typedef struct IMAGEHLP_MODULE64_V3 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module DWORD ImageSize; // virtual size of the loaded module DWORD TimeDateStamp; // date/time stamp from pe header DWORD CheckSum; // checksum from the pe header DWORD NumSyms; // number of symbols in the symbol table SYM_TYPE SymType; // type of symbols loaded CHAR ModuleName[32]; // module name CHAR ImageName[256]; // image name CHAR LoadedImageName[256]; // symbol file name // new elements: 07-Jun-2002 CHAR LoadedPdbName[256]; // pdb file name DWORD CVSig; // Signature of the CV record in the debug directories CHAR CVData[MAX_PATH * 3]; // Contents of the CV record DWORD PdbSig; // Signature of PDB GUID PdbSig70; // Signature of PDB (VC 7 and up) DWORD PdbAge; // DBI age of pdb BOOL PdbUnmatched; // loaded an unmatched pdb BOOL DbgUnmatched; // loaded an unmatched dbg BOOL LineNumbers; // we have line number information BOOL GlobalSymbols; // we have internal symbol information BOOL TypeInfo; // we have type information // new elements: 17-Dec-2003 BOOL SourceIndexed; // pdb supports source server BOOL Publics; // contains public symbols }; typedef struct IMAGEHLP_MODULE64_V2 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module DWORD ImageSize; // virtual size of the loaded module DWORD TimeDateStamp; // date/time stamp from pe header DWORD CheckSum; // checksum from the pe header DWORD NumSyms; // number of symbols in the symbol table SYM_TYPE SymType; // type of symbols loaded CHAR ModuleName[32]; // module name CHAR ImageName[256]; // image name CHAR LoadedImageName[256]; // symbol file name }; #pragma pack(pop) // SymCleanup() typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess ); tSC pSC; // SymFunctionTableAccess64() typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase ); tSFTA pSFTA; // SymGetLineFromAddr64() typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line ); tSGLFA pSGLFA; // SymGetModuleBase64() typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr ); tSGMB pSGMB; // SymGetModuleInfo64() typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); tSGMI pSGMI; // SymGetOptions() typedef DWORD (__stdcall *tSGO)( VOID ); tSGO pSGO; // SymGetSymFromAddr64() typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol ); tSGSFA pSGSFA; // SymInitialize() typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ); tSI pSI; // SymLoadModule64() typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ); tSLM pSLM; // SymSetOptions() typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions ); tSSO pSSO; // StackWalk64() typedef BOOL (__stdcall *tSW)( DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); tSW pSW; // UnDecorateSymbolName() typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags ); tUDSN pUDSN; typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); tSGSP pSGSP; private: // **************************************** ToolHelp32 ************************ #define MAX_MODULE_NAME32 255 #define TH32CS_SNAPMODULE 0x00000008 #pragma pack( push, 8 ) typedef struct tagMODULEENTRY32 { DWORD dwSize; DWORD th32ModuleID; // This module DWORD th32ProcessID; // owning process DWORD GlblcntUsage; // Global usage count on the module DWORD ProccntUsage; // Module usage count in th32ProcessID's context BYTE * modBaseAddr; // Base address of module in th32ProcessID's context DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr HMODULE hModule; // The hModule of this module in th32ProcessID's context char szModule[MAX_MODULE_NAME32 + 1]; char szExePath[MAX_PATH]; } MODULEENTRY32; typedef MODULEENTRY32 * PMODULEENTRY32; typedef MODULEENTRY32 * LPMODULEENTRY32; #pragma pack( pop ) BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) { // CreateToolhelp32Snapshot() typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID); // Module32First() typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); // Module32Next() typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); // try both dlls... const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") }; HINSTANCE hToolhelp = NULL; tCT32S pCT32S = NULL; tM32F pM32F = NULL; tM32N pM32N = NULL; HANDLE hSnap; MODULEENTRY32 me; me.dwSize = sizeof(me); BOOL keepGoing; size_t i; for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ) { hToolhelp = LoadLibrary( dllname[i] ); if (hToolhelp == NULL) continue; pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First"); pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next"); if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) ) break; // found the functions! FreeLibrary(hToolhelp); hToolhelp = NULL; } if (hToolhelp == NULL) return FALSE; hSnap = pCT32S( TH32CS_SNAPMODULE, pid ); if (hSnap == (HANDLE) -1) { FreeLibrary(hToolhelp); return FALSE; } keepGoing = !!pM32F( hSnap, &me ); int cnt = 0; while (keepGoing) { this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize); cnt++; keepGoing = !!pM32N( hSnap, &me ); } CloseHandle(hSnap); FreeLibrary(hToolhelp); if (cnt <= 0) return FALSE; return TRUE; } // GetModuleListTH32 // **************************************** PSAPI ************************ typedef struct _MODULEINFO { LPVOID lpBaseOfDll; DWORD SizeOfImage; LPVOID EntryPoint; } MODULEINFO, *LPMODULEINFO; BOOL GetModuleListPSAPI(HANDLE hProcess) { // EnumProcessModules() typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); // GetModuleFileNameEx() typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); // GetModuleBaseName() typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); // GetModuleInformation() typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize ); HINSTANCE hPsapi; tEPM pEPM; tGMFNE pGMFNE; tGMBN pGMBN; tGMI pGMI; DWORD i; //ModuleEntry e; DWORD cbNeeded; MODULEINFO mi; HMODULE *hMods = 0; char *tt = NULL; char *tt2 = NULL; const SIZE_T TTBUFLEN = 8096; int cnt = 0; hPsapi = LoadLibrary( _T("psapi.dll") ); if (hPsapi == NULL) return FALSE; pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" ); pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" ); pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" ); pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) { // we couldn´t find all functions FreeLibrary(hPsapi); return FALSE; } hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE)); tt = (char*) malloc(sizeof(char) * TTBUFLEN); tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) goto cleanup; if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ) { //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); goto cleanup; } if ( cbNeeded > TTBUFLEN ) { //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); goto cleanup; } for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ ) { // base address, size pGMI(hProcess, hMods[i], &mi, sizeof mi ); // image file name tt[0] = 0; pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); // module name tt2[0] = 0; pGMBN(hProcess, hMods[i], tt2, TTBUFLEN ); DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage); if (dwRes != ERROR_SUCCESS) this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); cnt++; } cleanup: if (hPsapi != NULL) FreeLibrary(hPsapi); if (tt2 != NULL) free(tt2); if (tt != NULL) free(tt); if (hMods != NULL) free(hMods); return cnt != 0; } // GetModuleListPSAPI DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) { CHAR *szImg = _strdup(img); CHAR *szMod = _strdup(mod); DWORD result = ERROR_SUCCESS; if ( (szImg == NULL) || (szMod == NULL) ) result = ERROR_NOT_ENOUGH_MEMORY; else { if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) result = GetLastError(); } ULONGLONG fileVersion = 0; if ( (m_parent != NULL) && (szImg != NULL) ) { // try to retrive the file-version: if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) { VS_FIXEDFILEINFO *fInfo = NULL; DWORD dwHandle; DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); if (dwSize > 0) { LPVOID vData = malloc(dwSize); if (vData != NULL) { if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) { UINT len; TCHAR szSubBlock[] = _T("\\"); if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0) fInfo = NULL; else { fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); } } free(vData); } } } // Retrive some additional-infos about the module IMAGEHLP_MODULE64_V3 Module; const char *szSymType = "-unknown-"; if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) { switch(Module.SymType) { case SymNone: szSymType = "-nosymbols-"; break; case SymCoff: // 1 szSymType = "COFF"; break; case SymCv: // 2 szSymType = "CV"; break; case SymPdb: // 3 szSymType = "PDB"; break; case SymExport: // 4 szSymType = "-exported-"; break; case SymDeferred: // 5 szSymType = "-deferred-"; break; case SymSym: // 6 szSymType = "SYM"; break; case 7: // SymDia: szSymType = "DIA"; break; case 8: //SymVirtual: szSymType = "Virtual"; break; } } LPCSTR pdbName = Module.LoadedImageName; if (Module.LoadedPdbName[0] != 0) pdbName = Module.LoadedPdbName; this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion); } if (szImg != NULL) free(szImg); if (szMod != NULL) free(szMod); return result; } public: BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) { // first try toolhelp32 if (GetModuleListTH32(hProcess, dwProcessId)) return true; // then try psapi return GetModuleListPSAPI(hProcess); } BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo) { memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); if(this->pSGMI == NULL) { SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } // First try to use the larger ModuleInfo-Structure pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... if (pData == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); static bool s_useV3Version = true; if (s_useV3Version) { if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) { // only copy as much memory as is reserved... memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); free(pData); return TRUE; } s_useV3Version = false; // to prevent unneccessarry calls with the larger struct... } // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) { // only copy as much memory as is reserved... memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); free(pData); return TRUE; } free(pData); SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } }; // ############################################################# StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) { this->m_options = OptionsAll; this->m_modulesLoaded = FALSE; this->m_hProcess = hProcess; this->m_sw = new StackWalkerInternal(this, this->m_hProcess); this->m_dwProcessId = dwProcessId; this->m_szSymPath = NULL; this->m_MaxRecursionCount = 1000; } StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) { this->m_options = options; this->m_modulesLoaded = FALSE; this->m_hProcess = hProcess; this->m_sw = new StackWalkerInternal(this, this->m_hProcess); this->m_dwProcessId = dwProcessId; if (szSymPath != NULL) { this->m_szSymPath = _strdup(szSymPath); this->m_options |= SymBuildPath; } else this->m_szSymPath = NULL; this->m_MaxRecursionCount = 1000; } StackWalker::~StackWalker() { if (m_szSymPath != NULL) free(m_szSymPath); m_szSymPath = NULL; if (this->m_sw != NULL) delete this->m_sw; this->m_sw = NULL; } BOOL StackWalker::LoadModules() { if (this->m_sw == NULL) { SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } if (m_modulesLoaded != FALSE) return TRUE; // Build the sym-path: char *szSymPath = NULL; if ( (this->m_options & SymBuildPath) != 0) { const size_t nSymPathLen = 4096; szSymPath = (char*) malloc(nSymPathLen); if (szSymPath == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } szSymPath[0] = 0; // Now first add the (optional) provided sympath: if (this->m_szSymPath != NULL) { strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); strcat_s(szSymPath, nSymPathLen, ";"); } strcat_s(szSymPath, nSymPathLen, ".;"); const size_t nTempLen = 1024; char szTemp[nTempLen]; // Now add the current directory: if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) { szTemp[nTempLen-1] = 0; strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); } // Now add the path for the main-module: if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) { szTemp[nTempLen-1] = 0; for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p) { // locate the rightmost path separator if ( (*p == '\\') || (*p == '/') || (*p == ':') ) { *p = 0; break; } } // for (search for path separator...) if (strlen(szTemp) > 0) { strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); } } if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) { szTemp[nTempLen-1] = 0; strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); } if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) { szTemp[nTempLen-1] = 0; strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); } if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) { szTemp[nTempLen-1] = 0; strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); // also add the "system32"-directory: strcat_s(szTemp, nTempLen, "\\system32"); strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); } if ( (this->m_options & SymUseSymSrv) != 0) { if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) { szTemp[nTempLen-1] = 0; strcat_s(szSymPath, nSymPathLen, "SRV*"); strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, "\\websymbols"); strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); } else strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); } } // if SymBuildPath // First Init the whole stuff... BOOL bRet = this->m_sw->Init(szSymPath); if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; if (bRet == FALSE) { this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); if (bRet != FALSE) m_modulesLoaded = TRUE; return bRet; } // The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction // This has to be done due to a problem with the "hProcess"-parameter in x64... // Because this class is in no case multi-threading-enabled (because of the limitations // of dbghelp.dll) it is "safe" to use a static-variable static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; static LPVOID s_readMemoryFunction_UserData = NULL; BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) { CONTEXT c; CallstackEntry csEntry; IMAGEHLP_SYMBOL64 *pSym = NULL; StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; IMAGEHLP_LINE64 Line; int frameNum; bool bLastEntryCalled = true; int curRecursionCount = 0; if (m_modulesLoaded == FALSE) this->LoadModules(); // ignore the result... if (this->m_sw->m_hDbhHelp == NULL) { SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } s_readMemoryFunction = readMemoryFunction; s_readMemoryFunction_UserData = pUserData; if (context == NULL) { // If no context is provided, capture the context if (hThread == GetCurrentThread()) { GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS); } else { SuspendThread(hThread); memset(&c, 0, sizeof(CONTEXT)); c.ContextFlags = USED_CONTEXT_FLAGS; if (GetThreadContext(hThread, &c) == FALSE) { ResumeThread(hThread); return FALSE; } } } else c = *context; // init STACKFRAME for first call STACKFRAME64 s; // in/out stackframe memset(&s, 0, sizeof(s)); DWORD imageType; #ifdef _M_IX86 // normally, call ImageNtHeader() and use machine info from PE header imageType = IMAGE_FILE_MACHINE_I386; s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Esp; s.AddrStack.Mode = AddrModeFlat; #elif _M_X64 imageType = IMAGE_FILE_MACHINE_AMD64; s.AddrPC.Offset = c.Rip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Rsp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Rsp; s.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 imageType = IMAGE_FILE_MACHINE_IA64; s.AddrPC.Offset = c.StIIP; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.IntSp; s.AddrFrame.Mode = AddrModeFlat; s.AddrBStore.Offset = c.RsBSP; s.AddrBStore.Mode = AddrModeFlat; s.AddrStack.Offset = c.IntSp; s.AddrStack.Mode = AddrModeFlat; #else #error "Platform not supported!" #endif pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); if (!pSym) goto cleanup; // not enough memory... memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; memset(&Line, 0, sizeof(Line)); Line.SizeOfStruct = sizeof(Line); memset(&Module, 0, sizeof(Module)); Module.SizeOfStruct = sizeof(Module); for (frameNum = 0; ; ++frameNum ) { // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can // assume that either you are done, or that the stack is so hosed that the next // deeper frame could not be found. // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ) { // INFO: "StackWalk64" does not set "GetLastError"... this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); break; } csEntry.offset = s.AddrPC.Offset; csEntry.name[0] = 0; csEntry.undName[0] = 0; csEntry.undFullName[0] = 0; csEntry.offsetFromSmybol = 0; csEntry.offsetFromLine = 0; csEntry.lineFileName[0] = 0; csEntry.lineNumber = 0; csEntry.loadedImageName[0] = 0; csEntry.moduleName[0] = 0; if (s.AddrPC.Offset == s.AddrReturn.Offset) { if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) ) { this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); break; } curRecursionCount++; } else curRecursionCount = 0; if (s.AddrPC.Offset != 0) { // we seem to have a valid PC // show procedure info (SymGetSymFromAddr64()) if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE) { MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); // UnDecorateSymbolName() this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY ); this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE ); } else { this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); } // show line number info, NT5.0-method (SymGetLineFromAddr64()) if (this->m_sw->pSGLFA != NULL ) { // yes, we have SymGetLineFromAddr64() if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) { csEntry.lineNumber = Line.LineNumber; MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); } else { this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); } } // yes, we have SymGetLineFromAddr64() // show module info (SymGetModuleInfo64()) if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE) { // got module info OK switch ( Module.SymType ) { case SymNone: csEntry.symTypeString = "-nosymbols-"; break; case SymCoff: csEntry.symTypeString = "COFF"; break; case SymCv: csEntry.symTypeString = "CV"; break; case SymPdb: csEntry.symTypeString = "PDB"; break; case SymExport: csEntry.symTypeString = "-exported-"; break; case SymDeferred: csEntry.symTypeString = "-deferred-"; break; case SymSym: csEntry.symTypeString = "SYM"; break; #if API_VERSION_NUMBER >= 9 case SymDia: csEntry.symTypeString = "DIA"; break; #endif case 8: //SymVirtual: csEntry.symTypeString = "Virtual"; break; default: //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType ); csEntry.symTypeString = NULL; break; } MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); csEntry.baseOfImage = Module.BaseOfImage; MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); } // got module info OK else { this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); } } // we seem to have a valid PC CallstackEntryType et = nextEntry; if (frameNum == 0) et = firstEntry; bLastEntryCalled = false; this->OnCallstackEntry(et, csEntry); if (s.AddrReturn.Offset == 0) { bLastEntryCalled = true; this->OnCallstackEntry(lastEntry, csEntry); SetLastError(ERROR_SUCCESS); break; } } // for ( frameNum ) cleanup: if (pSym) free( pSym ); if (bLastEntryCalled == false) this->OnCallstackEntry(lastEntry, csEntry); if (context == NULL) ResumeThread(hThread); return TRUE; } BOOL __stdcall StackWalker::myReadProcMem( HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead ) { if (s_readMemoryFunction == NULL) { SIZE_T st; BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st); *lpNumberOfBytesRead = (DWORD) st; //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); return bRet; } else { return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); } } void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) { CHAR buffer[STACKWALK_MAX_NAMELEN]; if (fileVersion == 0) _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); else { DWORD v4 = (DWORD) fileVersion & 0xFFFF; DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF; DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF; DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF; _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); } OnOutput(buffer); } void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) { CHAR buffer[STACKWALK_MAX_NAMELEN]; if ( (eType != lastEntry) && (entry.offset != 0) ) { if (entry.name[0] == 0) MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); if (entry.undName[0] != 0) MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); if (entry.undFullName[0] != 0) MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); if (entry.lineFileName[0] == 0) { MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); if (entry.moduleName[0] == 0) MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name); } else _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name); buffer[STACKWALK_MAX_NAMELEN-1] = 0; OnOutput(buffer); } } void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) { CHAR buffer[STACKWALK_MAX_NAMELEN]; _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr); OnOutput(buffer); } void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) { CHAR buffer[STACKWALK_MAX_NAMELEN]; _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); OnOutput(buffer); // Also display the OS-version #if _MSC_VER <= 1200 OSVERSIONINFOA ver; ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA(&ver) != FALSE) { _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); OnOutput(buffer); } #else OSVERSIONINFOEXA ver; ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) { _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); OnOutput(buffer); } #endif } void StackWalker::OnOutput(LPCSTR buffer) { OutputDebugStringA(buffer); } gammaray-2.3.0/3rdparty/StackWalker/StackWalker.h000066400000000000000000000165141255003167400216730ustar00rootroot00000000000000/********************************************************************** * * StackWalker.h * * * * LICENSE (http://www.opensource.org/licenses/bsd-license.php) * * Copyright (c) 2005-2009, Jochen Kalmbach * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of Jochen Kalmbach nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * **********************************************************************/ // #pragma once is supported starting with _MCS_VER 1000, // so we need not to check the version (because we only support _MSC_VER >= 1100)! #pragma once #include // special defines for VC5/6 (if no actual PSDK is installed): #if _MSC_VER < 1300 typedef unsigned __int64 DWORD64, *PDWORD64; #if defined(_WIN64) typedef unsigned __int64 SIZE_T, *PSIZE_T; #else typedef unsigned long SIZE_T, *PSIZE_T; #endif #endif // _MSC_VER < 1300 class StackWalkerInternal; // forward class StackWalker { public: typedef enum StackWalkOptions { // No addition info will be retrived // (only the address is available) RetrieveNone = 0, // Try to get the symbol-name RetrieveSymbol = 1, // Try to get the line for this symbol RetrieveLine = 2, // Try to retrieve the module-infos RetrieveModuleInfo = 4, // Also retrieve the version for the DLL/EXE RetrieveFileVersion = 8, // Contains all the abouve RetrieveVerbose = 0xF, // Generate a "good" symbol-search-path SymBuildPath = 0x10, // Also use the public Microsoft-Symbol-Server SymUseSymSrv = 0x20, // Contains all the abouve "Sym"-options SymAll = 0x30, // Contains all options (default) OptionsAll = 0x3F } StackWalkOptions; StackWalker( int options = OptionsAll, // 'int' is by design, to combine the enum-flags LPCSTR szSymPath = NULL, DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess() ); StackWalker(DWORD dwProcessId, HANDLE hProcess); virtual ~StackWalker(); typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead, LPVOID pUserData // optional data, which was passed in "ShowCallstack" ); BOOL LoadModules(); BOOL ShowCallstack( HANDLE hThread = GetCurrentThread(), const CONTEXT *context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback ); #if _MSC_VER >= 1300 // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" // in older compilers in order to use it... starting with VC7 we can declare it as "protected" protected: #endif enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols protected: // Entry for each Callstack-Entry typedef struct CallstackEntry { DWORD64 offset; // if 0, we have no valid entry CHAR name[STACKWALK_MAX_NAMELEN]; CHAR undName[STACKWALK_MAX_NAMELEN]; CHAR undFullName[STACKWALK_MAX_NAMELEN]; DWORD64 offsetFromSmybol; DWORD offsetFromLine; DWORD lineNumber; CHAR lineFileName[STACKWALK_MAX_NAMELEN]; DWORD symType; LPCSTR symTypeString; CHAR moduleName[STACKWALK_MAX_NAMELEN]; DWORD64 baseOfImage; CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; } CallstackEntry; typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); virtual void OnOutput(LPCSTR szText); StackWalkerInternal *m_sw; HANDLE m_hProcess; DWORD m_dwProcessId; BOOL m_modulesLoaded; LPSTR m_szSymPath; int m_options; int m_MaxRecursionCount; static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); friend StackWalkerInternal; }; // class StackWalker // The "ugly" assembler-implementation is needed for systems before XP // If you have a new PSDK and you only compile for XP and later, then you can use // the "RtlCaptureContext" // Currently there is no define which determines the PSDK-Version... // So we just use the compiler-version (and assumes that the PSDK is // the one which was installed by the VS-IDE) // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... // But I currently use it in x64/IA64 environments... //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) #if defined(_M_IX86) #ifdef CURRENT_THREAD_VIA_EXCEPTION // TODO: The following is not a "good" implementation, // because the callstack is only valid in the "__except" block... #define GET_CURRENT_CONTEXT(c, contextFlags) \ do { \ memset(&c, 0, sizeof(CONTEXT)); \ EXCEPTION_POINTERS *pExp = NULL; \ __try { \ throw 0; \ } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ if (pExp != NULL) \ memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ c.ContextFlags = contextFlags; \ } while(0); #else // The following should be enough for walking the callstack... #define GET_CURRENT_CONTEXT(c, contextFlags) \ do { \ memset(&c, 0, sizeof(CONTEXT)); \ c.ContextFlags = contextFlags; \ __asm call x \ __asm x: pop eax \ __asm mov c.Eip, eax \ __asm mov c.Ebp, ebp \ __asm mov c.Esp, esp \ } while(0); #endif #else // The following is defined for x86 (XP and higher), x64 and IA64: #define GET_CURRENT_CONTEXT(c, contextFlags) \ do { \ memset(&c, 0, sizeof(CONTEXT)); \ c.ContextFlags = contextFlags; \ RtlCaptureContext(&c); \ } while(0); #endif gammaray-2.3.0/3rdparty/kde/000077500000000000000000000000001255003167400156305ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/kde/kdebug.h000066400000000000000000000001231255003167400172360ustar00rootroot00000000000000#ifndef KDEBUG_H #define KDEBUG_H #include #define kDebug qDebug #endif gammaray-2.3.0/3rdparty/kde/kdeui_export.h000066400000000000000000000017351255003167400205110ustar00rootroot00000000000000/* This file is part of the KDE project Copyright (C) 2007 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEUI_EXPORT_H #define KDEUI_EXPORT_H #include "ui/gammaray_ui_export.h" #define KDEUI_EXPORT #endif gammaray-2.3.0/3rdparty/kde/kfilterproxysearchline.cpp000066400000000000000000000056661255003167400231510ustar00rootroot00000000000000/* * Copyright (C) 2007-2008 Omat Holding B.V. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kfilterproxysearchline.h" #include #include #include #include //#include /** * Private class that helps to provide binary compatibility between releases. * @internal */ //@cond PRIVATE class KFilterProxySearchLine::Private { public: Private( KFilterProxySearchLine* parent) : q(parent), proxy(0), searchLine(0) { timer = new QTimer( q ); timer->setSingleShot( true ); connect( timer, SIGNAL( timeout() ), q, SLOT( slotSearchLineActivate() ) ); } QTimer* timer; KFilterProxySearchLine* q; QSortFilterProxyModel* proxy; QLineEdit* searchLine; void slotSearchLineChange( const QString& newText ); void slotSearchLineActivate(); }; void KFilterProxySearchLine::Private::slotSearchLineChange( const QString& ) { timer->start( 300 ); } void KFilterProxySearchLine::Private::slotSearchLineActivate() { if ( !proxy ) return; proxy->setFilterKeyColumn( -1 ); proxy->setFilterCaseSensitivity( Qt::CaseInsensitive ); proxy->setFilterFixedString( searchLine->text() ); } //@endcond KFilterProxySearchLine::KFilterProxySearchLine( QWidget* parent ) : QWidget( parent ), d( new Private( this ) ) { d->searchLine = new QLineEdit( this ); #if QT_VERSION >= 0x050200 d->searchLine->setClearButtonEnabled(true); #endif #if QT_VERSION >= 0x040700 d->searchLine->setPlaceholderText(tr("Search")); #endif QHBoxLayout* layout = new QHBoxLayout( this ); layout->setMargin( 0 ); layout->addWidget( d->searchLine ); connect( d->searchLine, SIGNAL( textChanged( const QString& ) ), SLOT( slotSearchLineChange( const QString& ) ) ); } KFilterProxySearchLine::~KFilterProxySearchLine() { delete d; } void KFilterProxySearchLine::setText( const QString& text ) { d->searchLine->setText( text ); } void KFilterProxySearchLine::setProxy( QSortFilterProxyModel* proxy ) { d->proxy = proxy; } QLineEdit* KFilterProxySearchLine::lineEdit() const { return d->searchLine; } #include "moc_kfilterproxysearchline.cpp" gammaray-2.3.0/3rdparty/kde/kfilterproxysearchline.h000066400000000000000000000043101255003167400225770ustar00rootroot00000000000000/* * Copyright (C) 2007-2008 Omat Holding B.V. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KFILTERPROXYSEARCHLINE_H #define KFILTERPROXYSEARCHLINE_H #include "kdeui_export.h" #undef KDEUI_EXPORT #define KDEUI_EXPORT GAMMARAY_UI_EXPORT #include class QLineEdit; class QSortFilterProxyModel; /** * @class KFilterProxySearchLine * * Responsible for the quick search when you are using a QSortFilterProxyModel. * This will give you an widget which you can embed in your application, call * the setProxy() function to indicate on which QSortFilterProxyModel this * search line should operate. * * @author Tom Albers * @since 4.2 */ class KDEUI_EXPORT KFilterProxySearchLine : public QWidget { Q_OBJECT public: /** * Constructor */ explicit KFilterProxySearchLine( QWidget* parent = 0 ); /** * Destructor */ ~KFilterProxySearchLine(); /** * Associate a proxy * @param proxy The proxy to operate with. */ void setProxy( QSortFilterProxyModel* proxy ); /** * To set the search to a text. */ void setText( const QString& text ); /** * Returns the pointer of the lineedit.. */ QLineEdit* lineEdit() const; private: class Private; Private* const d; Q_DISABLE_COPY( KFilterProxySearchLine ) Q_PRIVATE_SLOT( d, void slotSearchLineChange( const QString& newText ) ) Q_PRIVATE_SLOT( d, void slotSearchLineActivate() ) }; #endif gammaray-2.3.0/3rdparty/kde/klinkitemselectionmodel.cpp000066400000000000000000000162431255003167400232600ustar00rootroot00000000000000/* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "klinkitemselectionmodel.h" #include "kmodelindexproxymapper.h" #include "kdebug.h" #include class KLinkItemSelectionModelPrivate { public: KLinkItemSelectionModelPrivate(KLinkItemSelectionModel *proxySelectionModel, QAbstractItemModel *model, QItemSelectionModel *linkedItemSelectionModel) : q_ptr(proxySelectionModel), m_model(model), m_linkedItemSelectionModel(linkedItemSelectionModel), m_ignoreCurrentChanged(false), m_indexMapper(new KModelIndexProxyMapper(model, linkedItemSelectionModel->model(), proxySelectionModel)) { } Q_DECLARE_PUBLIC(KLinkItemSelectionModel) KLinkItemSelectionModel * const q_ptr; bool assertSelectionValid(const QItemSelection &selection) const { foreach(const QItemSelectionRange &range, selection) { if (!range.isValid()) { kDebug() << selection; } Q_ASSERT(range.isValid()); } return true; } void sourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void sourceCurrentChanged(const QModelIndex& current); void slotCurrentChanged(const QModelIndex& current); QAbstractItemModel * const m_model; QItemSelectionModel * const m_linkedItemSelectionModel; bool m_ignoreCurrentChanged; KModelIndexProxyMapper * const m_indexMapper; }; KLinkItemSelectionModel::KLinkItemSelectionModel(QAbstractItemModel *model, QItemSelectionModel *proxySelector, QObject *parent) : QItemSelectionModel(model, parent), d_ptr(new KLinkItemSelectionModelPrivate(this, model, proxySelector)) { connect(proxySelector, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(sourceSelectionChanged(QItemSelection,QItemSelection))); connect(proxySelector, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(sourceCurrentChanged(QModelIndex))); connect(this, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(slotCurrentChanged(QModelIndex))); } KLinkItemSelectionModel::~KLinkItemSelectionModel() { delete d_ptr; } void KLinkItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) { Q_D(KLinkItemSelectionModel); // When an item is removed, the current index is set to the top index in the model. // That causes a selectionChanged signal with a selection which we do not want. if (d->m_ignoreCurrentChanged) { return; } // Do *not* replace next line with: QItemSelectionModel::select(index, command) // // Doing so would end up calling KLinkItemSelectionModel::select(QItemSelection, QItemSelectionModel::SelectionFlags) // // This is because the code for QItemSelectionModel::select(QModelIndex, QItemSelectionModel::SelectionFlags) looks like this: // { // QItemSelection selection(index, index); // select(selection, command); // } // So it calls KLinkItemSelectionModel overload of // select(QItemSelection, QItemSelectionModel::SelectionFlags) // // When this happens and the selection flags include Toggle, it causes the // selection to be toggled twice. QItemSelectionModel::select(QItemSelection(index, index), command); if (index.isValid()) d->m_linkedItemSelectionModel->select(d->m_indexMapper->mapSelectionLeftToRight(QItemSelection(index, index)), command); else { d->m_linkedItemSelectionModel->clearSelection(); } } // QAbstractProxyModel::mapSelectionFromSource creates invalid ranges to we filter // those out manually in a loop. Hopefully fixed in Qt 4.7.2, so we ifdef it out. // http://qt.gitorious.org/qt/qt/merge_requests/2474 // http://qt.gitorious.org/qt/qt/merge_requests/831 #if QT_VERSION < 0x040702 #define RANGE_FIX_HACK #endif #ifdef RANGE_FIX_HACK static QItemSelection klink_removeInvalidRanges(const QItemSelection &selection) { QItemSelection result; Q_FOREACH(const QItemSelectionRange &range, selection) { if (!range.isValid()) continue; result << range; } return result; } #endif void KLinkItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) { Q_D(KLinkItemSelectionModel); d->m_ignoreCurrentChanged = true; #ifdef RANGE_FIX_HACK QItemSelection _selection = klink_removeInvalidRanges(selection); #else QItemSelection _selection = selection; #endif QItemSelectionModel::select(_selection, command); Q_ASSERT(d->assertSelectionValid(_selection)); QItemSelection mappedSelection = d->m_indexMapper->mapSelectionLeftToRight(_selection); Q_ASSERT(d->assertSelectionValid(mappedSelection)); d->m_linkedItemSelectionModel->select(mappedSelection, command); d->m_ignoreCurrentChanged = false; } void KLinkItemSelectionModelPrivate::slotCurrentChanged(const QModelIndex& current) { const QModelIndex mappedCurrent = m_indexMapper->mapLeftToRight(current); if (!mappedCurrent.isValid()) { return; } m_linkedItemSelectionModel->setCurrentIndex(mappedCurrent, QItemSelectionModel::NoUpdate); } void KLinkItemSelectionModelPrivate::sourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { Q_Q(KLinkItemSelectionModel); #ifdef RANGE_FIX_HACK QItemSelection _selected = klink_removeInvalidRanges(selected); QItemSelection _deselected = klink_removeInvalidRanges(deselected); #else QItemSelection _selected = selected; QItemSelection _deselected = deselected; #endif Q_ASSERT(assertSelectionValid(_selected)); Q_ASSERT(assertSelectionValid(_deselected)); const QItemSelection mappedDeselection = m_indexMapper->mapSelectionRightToLeft(_deselected); const QItemSelection mappedSelection = m_indexMapper->mapSelectionRightToLeft(_selected); q->QItemSelectionModel::select(mappedDeselection, QItemSelectionModel::Deselect); q->QItemSelectionModel::select(mappedSelection, QItemSelectionModel::Select); } void KLinkItemSelectionModelPrivate::sourceCurrentChanged(const QModelIndex& current) { Q_Q(KLinkItemSelectionModel); const QModelIndex mappedCurrent = m_indexMapper->mapRightToLeft(current); if (!mappedCurrent.isValid()) { return; } q->setCurrentIndex(mappedCurrent, QItemSelectionModel::NoUpdate); } #include "moc_klinkitemselectionmodel.cpp" gammaray-2.3.0/3rdparty/kde/klinkitemselectionmodel.h000066400000000000000000000115601255003167400227220ustar00rootroot00000000000000/* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KLINKITEMSELECTIONMODEL_H #define KLINKITEMSELECTIONMODEL_H #include #include #include "kdeui_export.h" class KLinkItemSelectionModelPrivate; /** @brief Makes it possible to share a selection in multiple views which do not have the same source model Although multiple views can share the same QItemSelectionModel, the views then need to have the same source model. If there is a proxy model between the model and one of the views, or different proxy models in each, this class makes it possible to share the selection between the views. @image html kproxyitemselectionmodel-simple.png "Sharing a QItemSelectionModel between views on the same model is trivial" @image html kproxyitemselectionmodel-error.png "If a proxy model is used, it is no longer possible to share the QItemSelectionModel directly" @image html kproxyitemselectionmodel-solution.png "A KLinkItemSelectionModel can be used to map the selection through the proxy model" @code QAbstractItemModel *model = getModel(); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(); proxy->setSourceModel(model); QTreeView *view1 = new QTreeView(splitter); view1->setModel(model); KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy, view1->selectionModel()); QTreeView *view2 = new QTreeView(splitter); // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view view2->setModel(proxy); view2->setSelectionModel( view2SelectionModel ); @endcode @image html kproxyitemselectionmodel-complex.png "Arbitrarily complex proxy configurations on the same root model can be used" @code QAbstractItemModel *model = getModel(); QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel(); proxy1->setSourceModel(model); QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel(); proxy2->setSourceModel(proxy1); QSortFilterProxyModel *proxy3 = new QSortFilterProxyModel(); proxy3->setSourceModel(proxy2); QTreeView *view1 = new QTreeView(splitter); view1->setModel(proxy3); QSortFilterProxyModel *proxy4 = new QSortFilterProxyModel(); proxy4->setSourceModel(model); QSortFilterProxyModel *proxy5 = new QSortFilterProxyModel(); proxy5->setSourceModel(proxy4); KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy5, view1->selectionModel()); QTreeView *view2 = new QTreeView(splitter); // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view view2->setModel(proxy5); view2->setSelectionModel( view2SelectionModel ); @endcode See also kdelibs/kdeui/tests/proxymodeltestapp/proxyitemselectionwidget.cpp. @since 4.5 @author Stephen Kelly */ class KDEUI_EXPORT KLinkItemSelectionModel : public QItemSelectionModel { Q_OBJECT public: /** Constructor. */ KLinkItemSelectionModel(QAbstractItemModel *targetModel, QItemSelectionModel *linkedItemSelectionModel, QObject *parent = 0); ~KLinkItemSelectionModel(); /* reimp */ void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command); /* reimp */ void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command); protected: KLinkItemSelectionModelPrivate * const d_ptr; private: Q_DECLARE_PRIVATE(KLinkItemSelectionModel) Q_PRIVATE_SLOT( d_func(), void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)) Q_PRIVATE_SLOT( d_func(), void sourceCurrentChanged(const QModelIndex ¤t)) Q_PRIVATE_SLOT( d_func(), void slotCurrentChanged(const QModelIndex ¤t)) }; #endif gammaray-2.3.0/3rdparty/kde/kmodelindexproxymapper.cpp000066400000000000000000000225001255003167400231450ustar00rootroot00000000000000/* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kmodelindexproxymapper.h" #include #include #include #include #include "kdebug.h" class KModelIndexProxyMapperPrivate { KModelIndexProxyMapperPrivate(const QAbstractItemModel *leftModel, const QAbstractItemModel *rightModel, KModelIndexProxyMapper *qq) : q_ptr(qq), m_leftModel(leftModel), m_rightModel(rightModel) { createProxyChain(); } void createProxyChain(); bool assertValid(); bool assertSelectionValid(const QItemSelection &selection) const { foreach(const QItemSelectionRange &range, selection) { if (!range.isValid()) { kDebug() << selection << m_leftModel << m_rightModel << m_proxyChainDown << m_proxyChainUp; } Q_ASSERT(range.isValid()); } return true; } Q_DECLARE_PUBLIC(KModelIndexProxyMapper) KModelIndexProxyMapper * const q_ptr; QList > m_proxyChainUp; QList > m_proxyChainDown; QWeakPointer m_leftModel; QWeakPointer m_rightModel; }; /* The idea here is that this selection model and proxySelectionModel might be in different parts of the proxy chain. We need to build up to two chains of proxy models to create mappings between them. Example 1: Root model | / \ Proxy 1 Proxy 3 | | Proxy 2 Proxy 4 Need Proxy 1 and Proxy 2 in one chain, and Proxy 3 and 4 in the other. Example 2: Root model | Proxy 1 | Proxy 2 / \ Proxy 3 Proxy 6 | | Proxy 4 Proxy 7 | Proxy 5 We first build the chain from 1 to 5, then start building the chain from 7 to 1. We stop when we find that proxy 2 is already in the first chain. Stephen Kelly, 30 March 2010. */ void KModelIndexProxyMapperPrivate::createProxyChain() { QWeakPointer targetModel = m_rightModel; if (!targetModel) return; if (m_leftModel == targetModel) return; QList > proxyChainDown; QWeakPointer selectionTargetProxyModel = qobject_cast(targetModel.data()); while( selectionTargetProxyModel ) { proxyChainDown.prepend( selectionTargetProxyModel ); selectionTargetProxyModel = qobject_cast(selectionTargetProxyModel.data()->sourceModel()); if (selectionTargetProxyModel.data() == m_leftModel.data()) { m_proxyChainDown = proxyChainDown; return; } } QWeakPointer sourceModel = m_leftModel; QWeakPointer sourceProxyModel = qobject_cast(sourceModel.data()); while(sourceProxyModel) { m_proxyChainUp.append(sourceProxyModel); sourceProxyModel = qobject_cast(sourceProxyModel.data()->sourceModel()); const int targetIndex = proxyChainDown.indexOf(sourceProxyModel); if (targetIndex != -1) { m_proxyChainDown = proxyChainDown.mid(targetIndex + 1, proxyChainDown.size()); return; } } m_proxyChainDown = proxyChainDown; Q_ASSERT(assertValid()); } bool KModelIndexProxyMapperPrivate::assertValid() { if ( m_proxyChainDown.isEmpty()) { Q_ASSERT( !m_proxyChainUp.isEmpty() ); Q_ASSERT( m_proxyChainUp.last().data()->sourceModel() == m_rightModel.data() ); } else if ( m_proxyChainUp.isEmpty()) { Q_ASSERT( !m_proxyChainDown.isEmpty() ); Q_ASSERT( m_proxyChainDown.first().data()->sourceModel() == m_leftModel.data() ); } else { Q_ASSERT( m_proxyChainDown.first().data()->sourceModel() == m_proxyChainUp.last().data()->sourceModel() ); } return true; } KModelIndexProxyMapper::KModelIndexProxyMapper(const QAbstractItemModel* leftModel, const QAbstractItemModel* rightModel, QObject* parent) : QObject(parent), d_ptr( new KModelIndexProxyMapperPrivate(leftModel, rightModel, this) ) { } KModelIndexProxyMapper::~KModelIndexProxyMapper() { delete d_ptr; } QModelIndex KModelIndexProxyMapper::mapLeftToRight(const QModelIndex& index) const { const QItemSelection selection = mapSelectionLeftToRight(QItemSelection(index, index)); if (selection.isEmpty()) return QModelIndex(); return selection.indexes().first(); } QModelIndex KModelIndexProxyMapper::mapRightToLeft(const QModelIndex& index) const { const QItemSelection selection = mapSelectionRightToLeft(QItemSelection(index, index)); if (selection.isEmpty()) return QModelIndex(); return selection.indexes().first(); } // QAbstractProxyModel::mapSelectionFromSource creates invalid ranges to we filter // those out manually in a loop. Hopefully fixed in Qt 4.7.2, so we ifdef it out. // http://qt.gitorious.org/qt/qt/merge_requests/2474 // http://qt.gitorious.org/qt/qt/merge_requests/831 #if QT_VERSION < 0x040702 #define RANGE_FIX_HACK #endif #ifdef RANGE_FIX_HACK static QItemSelection removeInvalidRanges(const QItemSelection &selection) { QItemSelection result; Q_FOREACH(const QItemSelectionRange &range, selection) { if (!range.isValid()) continue; result << range; } return result; } #endif QItemSelection KModelIndexProxyMapper::mapSelectionLeftToRight(const QItemSelection& selection) const { Q_D(const KModelIndexProxyMapper); if (selection.isEmpty()) return QItemSelection(); if (selection.first().model() != d->m_leftModel.data()) kDebug() << "FAIL" << selection.first().model() << d->m_leftModel.data() << d->m_rightModel.data(); Q_ASSERT(selection.first().model() == d->m_leftModel.data()); QItemSelection seekSelection = selection; Q_ASSERT(d->assertSelectionValid(seekSelection)); QListIterator > iUp(d->m_proxyChainUp); while (iUp.hasNext()) { const QWeakPointer proxy = iUp.next(); if (!proxy.data()) return QItemSelection(); seekSelection = proxy.data()->mapSelectionToSource(seekSelection); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); #endif Q_ASSERT(d->assertSelectionValid(seekSelection)); } QListIterator > iDown(d->m_proxyChainDown); while (iDown.hasNext()) { const QWeakPointer proxy = iDown.next(); if (!proxy.data()) return QItemSelection(); seekSelection = proxy.data()->mapSelectionFromSource(seekSelection); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); #endif Q_ASSERT(d->assertSelectionValid(seekSelection)); } Q_ASSERT( ( !seekSelection.isEmpty() && seekSelection.first().model() == d->m_rightModel.data() ) || true ); return seekSelection; } QItemSelection KModelIndexProxyMapper::mapSelectionRightToLeft(const QItemSelection& selection) const { Q_D(const KModelIndexProxyMapper); if (selection.isEmpty()) return QItemSelection(); if (selection.first().model() != d->m_rightModel.data()) kDebug() << "FAIL" << selection.first().model() << d->m_leftModel.data() << d->m_rightModel.data(); Q_ASSERT(selection.first().model() == d->m_rightModel.data()); QItemSelection seekSelection = selection; Q_ASSERT(d->assertSelectionValid(seekSelection)); QListIterator > iDown(d->m_proxyChainDown); iDown.toBack(); while (iDown.hasPrevious()) { const QWeakPointer proxy = iDown.previous(); if (!proxy.data()) return QItemSelection(); seekSelection = proxy.data()->mapSelectionToSource(seekSelection); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); #endif Q_ASSERT(d->assertSelectionValid(seekSelection)); } QListIterator > iUp(d->m_proxyChainUp); iUp.toBack(); while (iUp.hasPrevious()) { const QWeakPointer proxy = iUp.previous(); if (!proxy.data()) return QItemSelection(); seekSelection = proxy.data()->mapSelectionFromSource(seekSelection); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); #endif Q_ASSERT(d->assertSelectionValid(seekSelection)); } Q_ASSERT( ( !seekSelection.isEmpty() && seekSelection.first().model() == d->m_leftModel.data() ) || true ); return seekSelection; } #include "moc_kmodelindexproxymapper.cpp" gammaray-2.3.0/3rdparty/kde/kmodelindexproxymapper.h000066400000000000000000000065521255003167400226230ustar00rootroot00000000000000/* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KMODELINDEXPROXYMAPPER_H #define KMODELINDEXPROXYMAPPER_H #include #include "kdeui_export.h" class QAbstractItemModel; class QModelIndex; class QItemSelection; class KModelIndexProxyMapperPrivate; /** * @brief This class facilitates easy mapping of indexes and selections through proxy models. * * In a complex system of proxy models there can be a need to map indexes and selections between them, * and sometimes to do so without knowledge of the path from one model to another. * * For example, * * @verbatim * Root model * | * / \ * Proxy 1 Proxy 3 * | | * Proxy 2 Proxy 4 * @endverbatim * * If there is a need to map indexes between proxy 2 and proxy 4, a KModelIndexProxyMapper can be created * to facilitate mapping of indexes between them. * * @code * m_indexMapper = new KModelIndexProxyMapper(proxy2, proxy4, this); * * ... * * const QModelIndex proxy4Index = m_mapLeftToRight(proxy2->index(0, 0)); * Q_ASSERT(proxy4Index.model() == proxy4); * @endcode * * Note that the aim is to achieve black box connections so that there is no need for application code to * know the structure of proxy models in the path between left and right and attempt to manually map them. * * @verbatim * Root model * | * --------------- * | Black Box | * --------------- * | | * Proxy 2 Proxy 4 * @endverbatim * * @author Stephen Kelly * */ class KDEUI_EXPORT KModelIndexProxyMapper : public QObject { Q_OBJECT public: /** * Constructor */ KModelIndexProxyMapper(const QAbstractItemModel *leftModel, const QAbstractItemModel *rightModel, QObject* parent = 0); ~KModelIndexProxyMapper(); /** * Maps the @p index from the left model to the right model. */ QModelIndex mapLeftToRight(const QModelIndex &index) const; /** * Maps the @p index from the right model to the left model. */ QModelIndex mapRightToLeft(const QModelIndex &index) const; /** * Maps the @p selection from the left model to the right model. */ QItemSelection mapSelectionLeftToRight(const QItemSelection &selection) const; /** * Maps the @p selection from the right model to the left model. */ QItemSelection mapSelectionRightToLeft(const QItemSelection &selection) const; private: //@cond PRIVATE Q_DECLARE_PRIVATE(KModelIndexProxyMapper) KModelIndexProxyMapperPrivate * const d_ptr; //@endcond }; #endif gammaray-2.3.0/3rdparty/kde/krecursivefilterproxymodel.cpp000066400000000000000000000440631255003167400240560ustar00rootroot00000000000000/* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "krecursivefilterproxymodel.h" #include // Maintainability note: // This class invokes some Q_PRIVATE_SLOTs in QSortFilterProxyModel which are // private API and could be renamed or removed at any time. // If they are renamed, the invocations can be updated with an #if (QT_VERSION(...)) // If they are removed, then layout{AboutToBe}Changed Q_SIGNALS should be used when the source model // gets new rows or has rowsremoved or moved. The Q_PRIVATE_SLOT invocation is an optimization // because layout{AboutToBe}Changed is expensive and causes the entire mapping of the tree in QSFPM // to be cleared, even if only a part of it is dirty. // Stephen Kelly, 30 April 2010. inline static bool passRolesToDataChanged() { // runtime check to ensure a KF5 built against Qt < 5.5 keeps working when Qt is updated to 5.5 and above but KF5 is not rebuild // TODO: remove once Qt 5.5 or above is required for frameworks static const bool passRoles = QT_VERSION >= 0x050500 // no runtime check required when we built against Qt 5.5 or higher || KRecursiveFilterProxyModel::staticMetaObject.indexOfMethod("_q_sourceDataChanged(QModelIndex,QModelIndex,QVector)") != -1; return passRoles; } class KRecursiveFilterProxyModelPrivate { Q_DECLARE_PUBLIC(KRecursiveFilterProxyModel) KRecursiveFilterProxyModel *q_ptr; public: KRecursiveFilterProxyModelPrivate(KRecursiveFilterProxyModel *model) : q_ptr(model), ignoreRemove(false), completeInsert(false) { qRegisterMetaType("QModelIndex"); } inline QMetaMethod findMethod(const char *signature) const { Q_Q(const KRecursiveFilterProxyModel); const int idx = q->metaObject()->indexOfMethod(signature); Q_ASSERT(idx != -1); return q->metaObject()->method(idx); } // Convenience methods for invoking the QSFPM Q_SLOTS. Those slots must be invoked with invokeMethod // because they are Q_PRIVATE_SLOTs inline void invokeDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()) { Q_Q(KRecursiveFilterProxyModel); bool success = false; if (passRolesToDataChanged()) { // required for Qt 5.5 and upwards, see commit f96baeb75fc in qtbase static const QMetaMethod m = findMethod("_q_sourceDataChanged(QModelIndex,QModelIndex,QVector)"); success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, topLeft), Q_ARG(QModelIndex, bottomRight), Q_ARG(QVector, roles)); } else { // backwards compatibility static const QMetaMethod m = findMethod("_q_sourceDataChanged(QModelIndex,QModelIndex)"); success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, topLeft), Q_ARG(QModelIndex, bottomRight)); } Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsInserted(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsRemoved(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } void sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles = QVector()); void sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end); void sourceRowsInserted(const QModelIndex &source_parent, int start, int end); void sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end); void sourceRowsRemoved(const QModelIndex &source_parent, int start, int end); /** Force QSortFilterProxyModel to re-evaluate whether to hide or show index and its parents. */ void refreshAscendantMapping(const QModelIndex &index); QModelIndex lastFilteredOutAscendant(const QModelIndex &index); bool ignoreRemove; bool completeInsert; QModelIndex lastHiddenAscendantForInsert; }; void KRecursiveFilterProxyModelPrivate::sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles) { QModelIndex source_parent = source_top_left.parent(); Q_ASSERT(source_bottom_right.parent() == source_parent); // don't know how to handle different parents in this code... // Tell the world. invokeDataChanged(source_top_left, source_bottom_right, roles); // We can't find out if the change really matters to us or not, for a lack of a dataAboutToBeChanged signal (or a cache). // TODO: add a set of roles that we care for, so we can at least ignore the rest. // Even if we knew the visibility was just toggled, we also can't find out what // was the last filtered out ascendant (on show, like sourceRowsAboutToBeInserted does) // or the last to-be-filtered-out ascendant (on hide, like sourceRowsRemoved does) // So we have to refresh all parents. QModelIndex sourceParent = source_parent; while (sourceParent.isValid()) { invokeDataChanged(sourceParent, sourceParent, roles); sourceParent = sourceParent.parent(); } } QModelIndex KRecursiveFilterProxyModelPrivate::lastFilteredOutAscendant(const QModelIndex &idx) { Q_Q(KRecursiveFilterProxyModel); QModelIndex last = idx; QModelIndex index = idx.parent(); while (index.isValid() && !q->filterAcceptsRow(index.row(), index.parent())) { last = index; index = index.parent(); } return last; } void KRecursiveFilterProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); if (!source_parent.isValid() || q->filterAcceptsRow(source_parent.row(), source_parent.parent())) { // If the parent is already in the model (directly or indirectly), we can just pass on the signal. invokeRowsAboutToBeInserted(source_parent, start, end); completeInsert = true; } else { // OK, so parent is not in the model. // Maybe the grand parent neither.. Go up until the first one that is. lastHiddenAscendantForInsert = lastFilteredOutAscendant(source_parent); } } void KRecursiveFilterProxyModelPrivate::sourceRowsInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); if (completeInsert) { // If the parent is already in the model, we can just pass on the signal. completeInsert = false; invokeRowsInserted(source_parent, start, end); return; } bool requireRow = false; for (int row = start; row <= end; ++row) { if (q->filterAcceptsRow(row, source_parent)) { requireRow = true; break; } } if (!requireRow) { // The new rows doesn't have any descendants that match the filter. Filter them out. return; } // Make QSFPM realize that lastHiddenAscendantForInsert should be shown now invokeDataChanged(lastHiddenAscendantForInsert, lastHiddenAscendantForInsert); } void KRecursiveFilterProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); bool accepted = false; for (int row = start; row <= end; ++row) { if (q->filterAcceptsRow(row, source_parent)) { accepted = true; break; } } if (!accepted) { // All removed rows are already filtered out. We don't care about the signal. ignoreRemove = true; return; } invokeRowsAboutToBeRemoved(source_parent, start, end); } void KRecursiveFilterProxyModelPrivate::sourceRowsRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); if (ignoreRemove) { ignoreRemove = false; return; } invokeRowsRemoved(source_parent, start, end); // Find out if removing this visible row means that some ascendant // row can now be hidden. // We go up until we find a row that should still be visible // and then make QSFPM re-evaluate the last one we saw before that, to hide it. QModelIndex toHide; QModelIndex sourceAscendant = source_parent; while (sourceAscendant.isValid()) { if (q->filterAcceptsRow(sourceAscendant.row(), sourceAscendant.parent())) { break; } toHide = sourceAscendant; sourceAscendant = sourceAscendant.parent(); } if (toHide.isValid()) { invokeDataChanged(toHide, toHide); } } KRecursiveFilterProxyModel::KRecursiveFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), d_ptr(new KRecursiveFilterProxyModelPrivate(this)) { setDynamicSortFilter(true); } KRecursiveFilterProxyModel::~KRecursiveFilterProxyModel() { delete d_ptr; } bool KRecursiveFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { // TODO: Implement some caching so that if one match is found on the first pass, we can return early results // when the subtrees are checked by QSFPM. if (acceptRow(sourceRow, sourceParent)) { return true; } QModelIndex source_index = sourceModel()->index(sourceRow, 0, sourceParent); Q_ASSERT(source_index.isValid()); bool accepted = false; for (int row = 0, rows = sourceModel()->rowCount(source_index); row < rows; ++row) { if (filterAcceptsRow(row, source_index)) { accepted = true; break; } } return accepted; } QModelIndexList KRecursiveFilterProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { if (role < Qt::UserRole) { return QSortFilterProxyModel::match(start, role, value, hits, flags); } QModelIndexList list; QModelIndex proxyIndex; Q_FOREACH (const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { proxyIndex = mapFromSource(idx); if (proxyIndex.isValid()) { list << proxyIndex; } } return list; } bool KRecursiveFilterProxyModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) const { return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } void KRecursiveFilterProxyModel::setSourceModel(QAbstractItemModel *model) { // Standard disconnect. if (passRolesToDataChanged()) { disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex,QVector))); } else { disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); } disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceRowsInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); QSortFilterProxyModel::setSourceModel(model); // Disconnect in the QSortFilterProxyModel. These methods will be invoked manually // in invokeDataChanged, invokeRowsInserted etc. // // The reason for that is that when the source model adds new rows for example, the new rows // May not match the filter, but maybe their child items do match. // // Source model before insert: // // - A // - B // - - C // - - D // - - - E // - - - F // - - - G // - H // - I // // If the A F and L (which doesn't exist in the source model yet) match the filter // the proxy will be: // // - A // - B // - - D // - - - F // // New rows are inserted in the source model below H: // // - A // - B // - - C // - - D // - - - E // - - - F // - - - G // - H // - - J // - - K // - - - L // - I // // As L matches the filter, it should be part of the KRecursiveFilterProxyModel. // // - A // - B // - - D // - - - F // - H // - - K // - - - L // // when the QSortFilterProxyModel gets a notification about new rows in H, it only checks // J and K to see if they match, ignoring L, and therefore not adding it to the proxy. // To work around that, we make sure that the QSFPM slot which handles that change in // the source model (_q_sourceRowsAboutToBeInserted) does not get called directly. // Instead we connect the sourceModel signal to our own slot in *this (sourceRowsAboutToBeInserted) // Inside that method, the entire new subtree is queried (J, K *and* L) to see if there is a match, // then the relevant Q_SLOTS in QSFPM are invoked. // In the example above, we need to tell the QSFPM that H should be queried again to see if // it matches the filter. It did not before, because L did not exist before. Now it does. That is // achieved by telling the QSFPM that the data changed for H, which causes it to requery this class // to see if H matches the filter (which it now does as L now exists). // That is done in sourceRowsInserted. if (passRolesToDataChanged()) { disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector))); } else { disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex))); } disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int))); // Slots for manual invoking of QSortFilterProxyModel methods. if (passRolesToDataChanged()) { connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex,QVector))); } else { connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); } connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceRowsInserted(QModelIndex,int,int))); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); } #include "moc_krecursivefilterproxymodel.cpp" gammaray-2.3.0/3rdparty/kde/krecursivefilterproxymodel.h000066400000000000000000000103331255003167400235140ustar00rootroot00000000000000/* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KRECURSIVEFILTERPROXYMODEL_H #define KRECURSIVEFILTERPROXYMODEL_H #include #include #include "ui/gammaray_ui_export.h" #define KITEMMODELS_EXPORT GAMMARAY_UI_EXPORT class KRecursiveFilterProxyModelPrivate; /** @brief Implements recursive filtering of models QSortFilterProxyModel does not recurse when invoking a filtering stage, so that if a particular row is filtered out, its children are not even checked to see if they match the filter. For example, given a source model: @verbatim - A - B - - C - - - D - - - - E - - - F - - G - - H - I @endverbatim If a QSortFilterProxyModel is used with a filter matching A, D, G and I, the QSortFilterProxyModel will contain @verbatim - A - I @endverbatim That is, even though D and E match the filter, they are not represented in the proxy model because B does not match the filter and is filtered out. The KRecursiveFilterProxyModel checks child indexes for filter matching and ensures that all matching indexes are represented in the model. In the above example, the KRecursiveFilterProxyModel will contain @verbatim - A - B - - C - - - D - - G - I @endverbatim That is, the leaves in the model match the filter, but not necessarily the inner branches. QSortFilterProxyModel provides the virtual method filterAcceptsRow to allow custom filter implementations. Custom filter implementations can be written for KRecuriveFilterProxyModel using the acceptRow virtual method. Note that using this proxy model is additional overhead compared to QSortFilterProxyModel as every index in the model must be visited and queried. @author Stephen Kelly @since 4.5 */ class KITEMMODELS_EXPORT KRecursiveFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: /** Constructor */ explicit KRecursiveFilterProxyModel(QObject *parent = 0); /** Destructor */ virtual ~KRecursiveFilterProxyModel(); /** @reimp */ void setSourceModel(QAbstractItemModel *model); /** * @reimplemented */ virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const; protected: /** Reimplement this method for custom filtering strategies. */ virtual bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const; /** @reimp */ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; KRecursiveFilterProxyModelPrivate *const d_ptr; private: //@cond PRIVATE Q_DECLARE_PRIVATE(KRecursiveFilterProxyModel) Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles = QVector())) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &source_parent, int start, int end)) //@endcond }; #endif gammaray-2.3.0/3rdparty/lz4/000077500000000000000000000000001255003167400155765ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/lz4/lz4.c000066400000000000000000001531321255003167400164600ustar00rootroot00000000000000/* LZ4 - Fast LZ compression algorithm Copyright (C) 2011-2015, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/Cyan4973/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ /************************************** * Tuning parameters **************************************/ /* * HEAPMODE : * Select how default compression functions will allocate memory for their hash table, * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). */ #define HEAPMODE 0 /* * ACCELERATION_DEFAULT : * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 */ #define ACCELERATION_DEFAULT 1 /************************************** * CPU Feature Detection **************************************/ /* * LZ4_FORCE_SW_BITCOUNT * Define this parameter if your target system or compiler does not support hardware bit count */ #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ # define LZ4_FORCE_SW_BITCOUNT #endif /************************************** * Includes **************************************/ #include "lz4.h" /************************************** * Compiler Options **************************************/ #ifdef _MSC_VER /* Visual Studio */ # define FORCE_INLINE static __forceinline # include # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ # if defined(__GNUC__) || defined(__clang__) # define FORCE_INLINE static inline __attribute__((always_inline)) # else # define FORCE_INLINE static inline # endif # else # define FORCE_INLINE static # endif /* __STDC_VERSION__ */ #endif /* _MSC_VER */ /* LZ4_GCC_VERSION is defined into lz4.h */ #if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) #endif #define likely(expr) expect((expr) != 0, 1) #define unlikely(expr) expect((expr) != 0, 0) /************************************** * Memory routines **************************************/ #include /* malloc, calloc, free */ #define ALLOCATOR(n,s) calloc(n,s) #define FREEMEM free #include /* memset, memcpy */ #define MEM_INIT memset /************************************** * Basic Types **************************************/ #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ # include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; #else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; #endif /************************************** * Reading and writing into memory **************************************/ #define STEPSIZE sizeof(size_t) static unsigned LZ4_64bits(void) { return sizeof(void*)==8; } static unsigned LZ4_isLittleEndian(void) { const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; } static U16 LZ4_read16(const void* memPtr) { U16 val16; memcpy(&val16, memPtr, 2); return val16; } static U16 LZ4_readLE16(const void* memPtr) { if (LZ4_isLittleEndian()) { return LZ4_read16(memPtr); } else { const BYTE* p = (const BYTE*)memPtr; return (U16)((U16)p[0] + (p[1]<<8)); } } static void LZ4_writeLE16(void* memPtr, U16 value) { if (LZ4_isLittleEndian()) { memcpy(memPtr, &value, 2); } else { BYTE* p = (BYTE*)memPtr; p[0] = (BYTE) value; p[1] = (BYTE)(value>>8); } } static U32 LZ4_read32(const void* memPtr) { U32 val32; memcpy(&val32, memPtr, 4); return val32; } static U64 LZ4_read64(const void* memPtr) { U64 val64; memcpy(&val64, memPtr, 8); return val64; } static size_t LZ4_read_ARCH(const void* p) { if (LZ4_64bits()) return (size_t)LZ4_read64(p); else return (size_t)LZ4_read32(p); } static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); } static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); } /* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* e = (BYTE*)dstEnd; do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); # elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctzll((U64)val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; # endif } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; _BitScanForward( &r, (U32)val ); return (int)(r>>3); # elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctz((U32)val) >> 3); # else static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; # endif } } else /* Big Endian CPU */ { if (LZ4_64bits()) { # if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse64( &r, val ); return (unsigned)(r>>3); # elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clzll((U64)val) >> 3); # else unsigned r; if (!(val>>32)) { r=4; } else { r=0; val>>=32; } if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } r += (!val); return r; # endif } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse( &r, (unsigned long)val ); return (unsigned)(r>>3); # elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clz((U32)val) >> 3); # else unsigned r; if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } r += (!val); return r; # endif } } } static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { const BYTE* const pStart = pIn; while (likely(pIn compression run slower on incompressible data */ /************************************** * Local Structures and types **************************************/ typedef struct { U32 hashTable[HASH_SIZE_U32]; U32 currentOffset; U32 initCheck; const BYTE* dictionary; BYTE* bufferStart; /* obsolete, used for slideInputBuffer */ U32 dictSize; } LZ4_stream_t_internal; typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; typedef enum { byPtr, byU32, byU16 } tableType_t; typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; typedef enum { full = 0, partial = 1 } earlyEnd_directive; /************************************** * Local Utils **************************************/ int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } int LZ4_sizeofState() { return LZ4_STREAMSIZE; } /******************************** * Compression functions ********************************/ static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } static const U64 prime5bytes = 889523592379ULL; static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; const U32 hashMask = (1<> (40 - hashLog)) & hashMask; } static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) { if (LZ4_64bits()) return LZ4_hashSequence64(sequence, tableType); return LZ4_hashSequence((U32)sequence, tableType); } static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); } static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { switch (tableType) { case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } } } static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { U32 h = LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ } static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { U32 h = LZ4_hashPosition(p, tableType); return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } FORCE_INLINE int LZ4_compress_generic( void* const ctx, const char* const source, char* const dest, const int inputSize, const int maxOutputSize, const limitedOutput_directive outputLimited, const tableType_t tableType, const dict_directive dict, const dictIssue_directive dictIssue, const U32 acceleration) { LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx; const BYTE* ip = (const BYTE*) source; const BYTE* base; const BYTE* lowLimit; const BYTE* const lowRefLimit = ip - dictPtr->dictSize; const BYTE* const dictionary = dictPtr->dictionary; const BYTE* const dictEnd = dictionary + dictPtr->dictSize; const size_t dictDelta = dictEnd - (const BYTE*)source; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimit = iend - MFLIMIT; const BYTE* const matchlimit = iend - LASTLITERALS; BYTE* op = (BYTE*) dest; BYTE* const olimit = op + maxOutputSize; U32 forwardH; size_t refDelta=0; /* Init conditions */ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ switch(dict) { case noDict: default: base = (const BYTE*)source; lowLimit = (const BYTE*)source; break; case withPrefix64k: base = (const BYTE*)source - dictPtr->currentOffset; lowLimit = (const BYTE*)source - dictPtr->dictSize; break; case usingExtDict: base = (const BYTE*)source - dictPtr->currentOffset; lowLimit = (const BYTE*)source; break; } if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ if (inputSize> LZ4_skipTrigger); if (unlikely(forwardIp > mflimit)) goto _last_literals; match = LZ4_getPositionOnHash(h, ctx, tableType, base); if (dict==usingExtDict) { if (match<(const BYTE*)source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = (const BYTE*)source; } } forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, ctx, tableType, base); } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); } /* Catch up */ while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } { /* Encode Literal length */ unsigned litLength = (unsigned)(ip - anchor); token = op++; if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) return 0; /* Check output limit */ if (litLength>=RUN_MASK) { int len = (int)litLength-RUN_MASK; *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); ip += MINMATCH + matchLength; if (ip==limit) { unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); matchLength += more; ip += more; } } else { matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); ip += MINMATCH + matchLength; } if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) return 0; /* Check output limit */ if (matchLength>=ML_MASK) { *token += ML_MASK; matchLength -= ML_MASK; for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } if (matchLength >= 255) { matchLength-=255; *op++ = 255; } *op++ = (BYTE)matchLength; } else *token += (BYTE)(matchLength); } anchor = ip; /* Test end of chunk */ if (ip > mflimit) break; /* Fill table */ LZ4_putPosition(ip-2, ctx, tableType, base); /* Test next position */ match = LZ4_getPosition(ip, ctx, tableType, base); if (dict==usingExtDict) { if (match<(const BYTE*)source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = (const BYTE*)source; } } LZ4_putPosition(ip, ctx, tableType, base); if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) && (match+MAX_DISTANCE>=ip) && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) { token=op++; *token=0; goto _next_match; } /* Prepare next loop */ forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: /* Encode Last Literals */ { const size_t lastRun = (size_t)(iend - anchor); if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRun<= LZ4_compressBound(inputSize)) { if (inputSize < LZ4_64Klimit) return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); else return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); } else { if (inputSize < LZ4_64Klimit) return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); else return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); } } int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else LZ4_stream_t ctx; void* ctxPtr = &ctx; #endif int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) FREEMEM(ctxPtr); #endif return result; } int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); } /* hidden debug function */ /* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t ctx; LZ4_resetStream(&ctx); if (inputSize < LZ4_64Klimit) return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); else return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); } /******************************** * destSize variant ********************************/ static int LZ4_compress_destSize_generic( void* const ctx, const char* const src, char* const dst, int* const srcSizePtr, const int targetDstSize, const tableType_t tableType) { const BYTE* ip = (const BYTE*) src; const BYTE* base = (const BYTE*) src; const BYTE* lowLimit = (const BYTE*) src; const BYTE* anchor = ip; const BYTE* const iend = ip + *srcSizePtr; const BYTE* const mflimit = iend - MFLIMIT; const BYTE* const matchlimit = iend - LASTLITERALS; BYTE* op = (BYTE*) dst; BYTE* const oend = op + targetDstSize; BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); BYTE* const oMaxSeq = oMaxLit - 1 /* token */; U32 forwardH; /* Init conditions */ if (targetDstSize < 1) return 0; /* Impossible to store anything */ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ if (*srcSizePtr> LZ4_skipTrigger); if (unlikely(forwardIp > mflimit)) goto _last_literals; match = LZ4_getPositionOnHash(h, ctx, tableType, base); forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, ctx, tableType, base); } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) || (LZ4_read32(match) != LZ4_read32(ip)) ); } /* Catch up */ while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } { /* Encode Literal length */ unsigned litLength = (unsigned)(ip - anchor); token = op++; if (op + ((litLength+240)/255) + litLength > oMaxLit) { /* Not enough space for a last match */ op--; goto _last_literals; } if (litLength>=RUN_MASK) { unsigned len = litLength - RUN_MASK; *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } else *token = (BYTE)(litLength< oMaxMatch) { /* Match description too long : reduce it */ matchLength = (15-1) + (oMaxMatch-op) * 255; } //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH); ip += MINMATCH + matchLength; if (matchLength>=ML_MASK) { *token += ML_MASK; matchLength -= ML_MASK; while (matchLength >= 255) { matchLength-=255; *op++ = 255; } *op++ = (BYTE)matchLength; } else *token += (BYTE)(matchLength); } anchor = ip; /* Test end of block */ if (ip > mflimit) break; if (op > oMaxSeq) break; /* Fill table */ LZ4_putPosition(ip-2, ctx, tableType, base); /* Test next position */ match = LZ4_getPosition(ip, ctx, tableType, base); LZ4_putPosition(ip, ctx, tableType, base); if ( (match+MAX_DISTANCE>=ip) && (LZ4_read32(match)==LZ4_read32(ip)) ) { token=op++; *token=0; goto _next_match; } /* Prepare next loop */ forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: /* Encode Last Literals */ { size_t lastRunSize = (size_t)(iend - anchor); if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { /* adapt lastRunSize to fill 'dst' */ lastRunSize = (oend-op) - 1; lastRunSize -= (lastRunSize+240)/255; } ip = anchor + lastRunSize; if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */ { return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); } else { if (*srcSizePtr < LZ4_64Klimit) return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16); else return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr); } } int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (HEAPMODE) void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else LZ4_stream_t ctxBody; void* ctx = &ctxBody; #endif int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); #if (HEAPMODE) FREEMEM(ctx); #endif return result; } /******************************** * Streaming functions ********************************/ LZ4_stream_t* LZ4_createStream(void) { LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ LZ4_resetStream(lz4s); return lz4s; } void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { FREEMEM(LZ4_stream); return (0); } #define HASH_UNIT sizeof(size_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; const BYTE* p = (const BYTE*)dictionary; const BYTE* const dictEnd = p + dictSize; const BYTE* base; if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ LZ4_resetStream(LZ4_dict); if (dictSize < (int)HASH_UNIT) { dict->dictionary = NULL; dict->dictSize = 0; return 0; } if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; dict->currentOffset += 64 KB; base = p - dict->currentOffset; dict->dictionary = p; dict->dictSize = (U32)(dictEnd - p); dict->currentOffset += dict->dictSize; while (p <= dictEnd-HASH_UNIT) { LZ4_putPosition(p, dict->hashTable, byU32, base); p+=3; } return dict->dictSize; } static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) { if ((LZ4_dict->currentOffset > 0x80000000) || ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ { /* rescale hash table */ U32 delta = LZ4_dict->currentOffset - 64 KB; const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; else LZ4_dict->hashTable[i] -= delta; } LZ4_dict->currentOffset = 64 KB; if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; } } int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; const BYTE* smallest = (const BYTE*) source; if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; LZ4_renormDictT(streamPtr, smallest); if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; /* Check overlapping input/dictionary space */ { const BYTE* sourceEnd = (const BYTE*) source + inputSize; if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; streamPtr->dictionary = dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ if (dictEnd == (const BYTE*)source) { int result; if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); else result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); streamPtr->dictSize += (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; return result; } /* external dictionary mode */ { int result; if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); else result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; return result; } } /* Hidden debug function, to force external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) { LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; int result; const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; const BYTE* smallest = dictEnd; if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; return result; } int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; memmove(safeBuffer, previousDictEnd - dictSize, dictSize); dict->dictionary = (const BYTE*)safeBuffer; dict->dictSize = (U32)dictSize; return dictSize; } /******************************* * Decompression functions *******************************/ /* * This generic decompression function cover all use cases. * It shall be instantiated several times, using different sets of directives * Note that it is essential this generic function is really inlined, * in order to remove useless branches during compilation optimization. */ FORCE_INLINE int LZ4_decompress_generic( const char* const source, char* const dest, int inputSize, int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ int endOnInput, /* endOnOutputSize, endOnInputSize */ int partialDecoding, /* full, partial */ int targetOutputSize, /* only used if partialDecoding==partial */ int dict, /* noDict, withPrefix64k, usingExtDict */ const BYTE* const lowPrefix, /* == dest if dict == noDict */ const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { /* Local Variables */ const BYTE* ip = (const BYTE*) source; const BYTE* const iend = ip + inputSize; BYTE* op = (BYTE*) dest; BYTE* const oend = op + outputSize; BYTE* cpy; BYTE* oexit = op + targetOutputSize; const BYTE* const lowLimit = lowPrefix - dictSize; const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; const int safeDecode = (endOnInput==endOnInputSize); const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); /* Special cases */ if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); /* Main Loop */ while (1) { unsigned token; size_t length; const BYTE* match; /* get literal length */ token = *ip++; if ((length=(token>>ML_BITS)) == RUN_MASK) { unsigned s; do { s = *ip++; length += s; } while (likely((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) || ((!endOnInput) && (cpy>oend-COPYLENGTH))) { if (partialDecoding) { if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ } else { if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ } memcpy(op, ip, length); ip += length; op += length; break; /* Necessarily EOF, due to parsing restrictions */ } LZ4_wildCopy(op, ip, cpy); ip += length; op = cpy; /* get offset */ match = cpy - LZ4_readLE16(ip); ip+=2; if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ /* get matchlength */ length = token & ML_MASK; if (length == ML_MASK) { unsigned s; do { if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; s = *ip++; length += s; } while (s==255); if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ } length += MINMATCH; /* check external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ if (length <= (size_t)(lowPrefix-match)) { /* match can be copied as a single segment from external dictionary */ match = dictEnd - (lowPrefix-match); memmove(op, match, length); op += length; } else { /* match encompass external dictionary and current segment */ size_t copySize = (size_t)(lowPrefix-match); memcpy(op, dictEnd - copySize, copySize); op += copySize; copySize = length - copySize; if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */ { BYTE* const endOfMatch = op + copySize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; } else { memcpy(op, lowPrefix, copySize); op += copySize; } } continue; } /* copy repeated sequence */ cpy = op + length; if (unlikely((op-match)<8)) { const size_t dec64 = dec64table[op-match]; op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += dec32table[op-match]; LZ4_copy4(op+4, match); op += 8; match -= dec64; } else { LZ4_copy8(op, match); op+=8; match+=8; } if (unlikely(cpy>oend-12)) { if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */ if (op < oend-8) { LZ4_wildCopy(op, match, oend-8); match += (oend-8) - op; op = oend-8; } while (opprefixSize = (size_t) dictSize; lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; } /* *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks must still be available at the memory position where they were decoded. If it's not possible, save the relevant part of decoded data into a safe buffer, and indicate where it stands using LZ4_setStreamDecode() */ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; int result; if (lz4sd->prefixEnd == (BYTE*)dest) { result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += result; lz4sd->prefixEnd += result; } else { lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = result; lz4sd->prefixEnd = (BYTE*)dest + result; } return result; } int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) { LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; int result; if (lz4sd->prefixEnd == (BYTE*)dest) { result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += originalSize; lz4sd->prefixEnd += originalSize; } else { lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = originalSize; lz4sd->prefixEnd = (BYTE*)dest + originalSize; } return result; } /* Advanced decoding functions : *_usingDict() : These decoding functions work the same as "_continue" ones, the dictionary must be explicitly provided within parameters */ FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) { if (dictSize==0) return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); if (dictStart+dictSize == dest) { if (dictSize >= (int)(64 KB - 1)) return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); } return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); } int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); } /* debug function */ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } /*************************************************** * Obsolete Functions ***************************************************/ /* obsolete compression functions */ int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } /* These function names are deprecated and should no longer be used. They are only provided here for compatibility with older user programs. - LZ4_uncompress is totally equivalent to LZ4_decompress_fast - LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe */ int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } /* Obsolete Streaming functions */ int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base) { MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); lz4ds->bufferStart = base; } int LZ4_resetStreamState(void* state, char* inputBuffer) { if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer); return 0; } void* LZ4_create (char* inputBuffer) { void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64); LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer); return lz4ds; } char* LZ4_slideInputBuffer (void* LZ4_Data) { LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data; int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); return (char*)(ctx->bufferStart + dictSize); } /* Obsolete streaming decompression functions */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } #endif /* LZ4_COMMONDEFS_ONLY */ gammaray-2.3.0/3rdparty/lz4/lz4.h000066400000000000000000000446161255003167400164730ustar00rootroot00000000000000/* LZ4 - Fast LZ compression algorithm Header File Copyright (C) 2011-2015, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/Cyan4973/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ #pragma once #if defined (__cplusplus) extern "C" { #endif /* * lz4.h provides block compression functions, and gives full buffer control to programmer. * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), * and can let the library handle its own memory, please use lz4frame.h instead. */ /************************************** * Version **************************************/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ #define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) int LZ4_versionNumber (void); /************************************** * Tuning parameter **************************************/ /* * LZ4_MEMORY_USAGE : * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) * Increasing memory usage improves compression ratio * Reduced memory usage can improve speed, due to cache effect * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ #define LZ4_MEMORY_USAGE 14 /************************************** * Simple Functions **************************************/ int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); /* LZ4_compress_default() : Compresses 'sourceSize' bytes from buffer 'source' into already allocated 'dest' buffer of size 'maxDestSize'. Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). It also runs faster, so it's a recommended setting. If the function cannot compress 'source' into a more limited 'dest' budget, compression stops *immediately*, and the function result is zero. As a consequence, 'dest' content is not valid. This function never writes outside 'dest' buffer, nor read outside 'source' buffer. sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) or 0 if compression fails LZ4_decompress_safe() : compressedSize : is the precise full size of the compressed block. maxDecompressedSize : is the size of destination buffer, which must be already allocated. return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) If destination buffer is not large enough, decoding will stop and output an error code (<0). If the source stream is detected malformed, the function will stop decoding and return a negative result. This function is protected against buffer overflow exploits, including malicious data packets. It never writes outside output buffer, nor reads outside input buffer. */ /************************************** * Advanced Functions **************************************/ #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) /* LZ4_compressBound() : Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) This function is primarily useful for memory allocation purposes (destination buffer size). Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) inputSize : max supported value is LZ4_MAX_INPUT_SIZE return : maximum output size in a "worst case" scenario or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) */ int LZ4_compressBound(int inputSize); /* LZ4_compress_fast() : Same as LZ4_compress_default(), but allows to select an "acceleration" factor. The larger the acceleration value, the faster the algorithm, but also the lesser the compression. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. An acceleration value of "1" is the same as regular LZ4_compress_default() Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. */ int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); /* LZ4_compress_fast_extState() : Same compression function, just using an externally allocated memory space to store compression state. Use LZ4_sizeofState() to know how much memory must be allocated, and allocate it on 8-bytes boundaries (using malloc() typically). Then, provide it as 'void* state' to compression function. */ int LZ4_sizeofState(void); int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); /* LZ4_compress_destSize() : Reverse the logic, by compressing as much data as possible from 'source' buffer into already allocated buffer 'dest' of size 'targetDestSize'. This function either compresses the entire 'source' content into 'dest' if it's large enough, or fill 'dest' buffer completely with as much data as possible from 'source'. *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. New value is necessarily <= old value. return : Nb bytes written into 'dest' (necessarily <= targetDestSize) or 0 if compression fails */ int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); /* LZ4_decompress_fast() : originalSize : is the original and therefore uncompressed size return : the number of bytes read from the source buffer (in other words, the compressed size) If the source stream is detected malformed, the function will stop decoding and return a negative result. Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. note : This function fully respect memory boundaries for properly formed compressed data. It is a bit faster than LZ4_decompress_safe(). However, it does not provide any protection against intentionally modified data stream (malicious input). Use this function in trusted environment only (data to decode comes from a trusted source). */ int LZ4_decompress_fast (const char* source, char* dest, int originalSize); /* LZ4_decompress_safe_partial() : This function decompress a compressed block of size 'compressedSize' at position 'source' into destination buffer 'dest' of size 'maxDecompressedSize'. The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, reducing decompression time. return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. Always control how many bytes were decoded. If the source stream is detected malformed, the function will stop decoding and return a negative result. This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets */ int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); /*********************************************** * Streaming Compression Functions ***********************************************/ #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) /* * LZ4_stream_t * information structure to track an LZ4 stream. * important : init this structure content before first use ! * note : only allocated directly the structure if you are statically linking LZ4 * If you are using liblz4 as a DLL, please use below construction methods instead. */ typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; /* * LZ4_resetStream * Use this function to init an allocated LZ4_stream_t structure */ void LZ4_resetStream (LZ4_stream_t* streamPtr); /* * LZ4_createStream will allocate and initialize an LZ4_stream_t structure * LZ4_freeStream releases its memory. * In the context of a DLL (liblz4), please use these methods rather than the static struct. * They are more future proof, in case of a change of LZ4_stream_t size. */ LZ4_stream_t* LZ4_createStream(void); int LZ4_freeStream (LZ4_stream_t* streamPtr); /* * LZ4_loadDict * Use this function to load a static dictionary into LZ4_stream. * Any previous data will be forgotten, only 'dictionary' will remain in memory. * Loading a size of 0 is allowed. * Return : dictionary size, in bytes (necessarily <= 64 KB) */ int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); /* * LZ4_compress_fast_continue * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. * Important : Previous data blocks are assumed to still be present and unmodified ! * 'dst' buffer must be already allocated. * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. */ int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); /* * LZ4_saveDict * If previously compressed data block is not guaranteed to remain available at its memory location * save it into a safer place (char* safeBuffer) * Note : you don't need to call LZ4_loadDict() afterwards, * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error */ int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); /************************************************ * Streaming Decompression Functions ************************************************/ #define LZ4_STREAMDECODESIZE_U64 4 #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; /* * LZ4_streamDecode_t * information structure to track an LZ4 stream. * init this structure content using LZ4_setStreamDecode or memset() before first use ! * * In the context of a DLL (liblz4) please prefer usage of construction methods below. * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure * LZ4_freeStreamDecode releases its memory. */ LZ4_streamDecode_t* LZ4_createStreamDecode(void); int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); /* * LZ4_setStreamDecode * Use this function to instruct where to find the dictionary. * Setting a size of 0 is allowed (same effect as reset). * Return : 1 if OK, 0 if error */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); /* *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) In the case of a ring buffers, decoding buffer must be either : - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. In which case, encoding and decoding buffers do not need to be synchronized, and encoding ring buffer can have any size, including small ones ( < 64 KB). - _At least_ 64 KB + 8 bytes + maxBlockSize. In which case, encoding and decoding buffers do not need to be synchronized, and encoding ring buffer can have any size, including larger than decoding buffer. Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, and indicate where it is saved using LZ4_setStreamDecode() */ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); /* Advanced decoding functions : *_usingDict() : These decoding functions work the same as a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. */ int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); /************************************** * Obsolete Functions **************************************/ /* Deprecate Warnings */ /* Should these warnings messages be a problem, it is generally possible to disable them, with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual for example. You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ #ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK # define LZ4_DEPRECATE_WARNING_DEFBLOCK # define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # if (LZ4_GCC_VERSION >= 405) || defined(__clang__) # define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) # elif (LZ4_GCC_VERSION >= 301) # define LZ4_DEPRECATED(message) __attribute__((deprecated)) # elif defined(_MSC_VER) # define LZ4_DEPRECATED(message) __declspec(deprecated(message)) # else # pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") # define LZ4_DEPRECATED(message) # endif #endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ /* Obsolete compression functions */ /* These functions are planned to start generate warnings by r131 approximately */ int LZ4_compress (const char* source, char* dest, int sourceSize); int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); /* Obsolete decompression functions */ /* These function names are completely deprecated and must no longer be used. They are only provided here for compatibility with older programs. - LZ4_uncompress is the same as LZ4_decompress_fast - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe These function prototypes are now disabled; uncomment them only if you really need them. It is highly recommended to stop using these prototypes and migrate to maintained ones */ /* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ /* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ /* Obsolete streaming functions; use new streaming interface whenever possible */ LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer); LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer); LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state); /* Obsolete streaming decoding functions */ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); #if defined (__cplusplus) } #endif gammaray-2.3.0/3rdparty/qt/000077500000000000000000000000001255003167400155115ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/qt/4.8/000077500000000000000000000000001255003167400160225ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/qt/4.8/private/000077500000000000000000000000001255003167400174745ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/qt/4.8/private/qguiplatformplugin_p.h000066400000000000000000000106741255003167400241250ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QGUIPLATFORM_P_H #define QGUIPLATFORM_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 #include #include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Gui) class QStyle; class QPalette; class QIcon; class QFileDialog; class QColorDialog; class QFileInfo; struct Q_GUI_EXPORT QGuiPlatformPluginInterface : public QFactoryInterface { }; #define QGuiPlatformPluginInterface_iid "com.nokia.qt.QGuiPlatformPluginInterface" Q_DECLARE_INTERFACE(QGuiPlatformPluginInterface, QGuiPlatformPluginInterface_iid) class Q_GUI_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformPluginInterface { Q_OBJECT Q_INTERFACES(QGuiPlatformPluginInterface:QFactoryInterface) public: explicit QGuiPlatformPlugin(QObject *parent = 0); ~QGuiPlatformPlugin(); virtual QStringList keys() const { return QStringList() << QLatin1String("default"); }; virtual QString styleName(); virtual QPalette palette(); virtual QString systemIconThemeName(); virtual QStringList iconThemeSearchPaths(); virtual QIcon fileSystemIcon(const QFileInfo &); enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; virtual int platformHint(PlatformHint hint); virtual void fileDialogDelete(QFileDialog *) {} virtual bool fileDialogSetVisible(QFileDialog *, bool) { return false; } virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *) { return QDialog::Rejected; } virtual void fileDialogSetDirectory(QFileDialog *, const QString &) {} virtual QString fileDialogDirectory(const QFileDialog *) const { return QString(); } virtual void fileDialogSelectFile(QFileDialog *, const QString &) {} virtual QStringList fileDialogSelectedFiles(const QFileDialog *) const { return QStringList(); } virtual void fileDialogSetFilter(QFileDialog *) {} virtual void fileDialogSetNameFilters(QFileDialog *, const QStringList &) {} virtual void fileDialogSelectNameFilter(QFileDialog *, const QString &) {} virtual QString fileDialogSelectedNameFilter(const QFileDialog *) const { return QString(); } virtual void colorDialogDelete(QColorDialog *) {} virtual bool colorDialogSetVisible(QColorDialog *, bool) { return false; } virtual void colorDialogSetCurrentColor(QColorDialog *, const QColor &) {} }; //internal QGuiPlatformPlugin *qt_guiPlatformPlugin(); QT_END_NAMESPACE QT_END_HEADER #endif // QGUIPLATFORMPLUGIN_H gammaray-2.3.0/3rdparty/qt/5.5/000077500000000000000000000000001255003167400160205ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/qt/5.5/private/000077500000000000000000000000001255003167400174725ustar00rootroot00000000000000gammaray-2.3.0/3rdparty/qt/5.5/private/qpaintbuffer.cpp000066400000000000000000002320441255003167400226710ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include //#include #include #include #include #include #include #include // #define QPAINTBUFFER_DEBUG_DRAW QT_BEGIN_NAMESPACE extern void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, int tabstops, int* tabarray, int tabarraylen, QPainter *painter); QTextItemIntCopy::QTextItemIntCopy(const QTextItem &item) : m_item(static_cast(item)) { QChar *chars = new QChar[m_item.num_chars]; unsigned short *logClusters = new unsigned short[m_item.num_chars]; memcpy(chars, m_item.chars, m_item.num_chars * sizeof(QChar)); memcpy(logClusters, m_item.logClusters, m_item.num_chars * sizeof(unsigned short)); m_item.chars = chars; m_item.logClusters = logClusters; char *glyphLayoutData = new char[m_item.glyphs.numGlyphs * QGlyphLayout::SpaceNeeded]; QGlyphLayout glyphs(glyphLayoutData, m_item.glyphs.numGlyphs); memcpy(glyphs.offsets, m_item.glyphs.offsets, m_item.glyphs.numGlyphs * sizeof(QFixedPoint)); memcpy(glyphs.glyphs, m_item.glyphs.glyphs, m_item.glyphs.numGlyphs * sizeof(glyph_t)); memcpy(glyphs.advances, m_item.glyphs.advances, m_item.glyphs.numGlyphs * sizeof(QFixed)); memcpy(glyphs.justifications, m_item.glyphs.justifications, m_item.glyphs.numGlyphs * sizeof(QGlyphJustification)); memcpy(glyphs.attributes, m_item.glyphs.attributes, m_item.glyphs.numGlyphs * sizeof(QGlyphAttributes)); m_item.glyphs = glyphs; m_font = *m_item.f; m_item.f = &m_font; m_item.fontEngine->ref.ref(); // Increment reference count. } QTextItemIntCopy::~QTextItemIntCopy() { delete [] m_item.chars; delete [] m_item.logClusters; delete [] m_item.glyphs.data(); if (!m_item.fontEngine->ref.deref()) delete m_item.fontEngine; } /************************************************************************ * * QPaintBufferPrivate * ************************************************************************/ QPaintBufferPrivate::QPaintBufferPrivate() : ref(1), engine(0), penWidthAdjustment(0) , calculateBoundingRect(true) , cache(0) { } QPaintBufferPrivate::~QPaintBufferPrivate() { for (int i = 0; i < commands.size(); ++i) { const QPaintBufferCommand &cmd = commands.at(i); if (cmd.id == QPaintBufferPrivate::Cmd_DrawTextItem) delete reinterpret_cast(qvariant_cast(variants.at(cmd.offset))); } } inline void QPaintBufferPrivate::updateBoundingRect(const QRectF &br) { // transform to device coords and adjust for pen width Q_ASSERT(engine && engine->painter()); QPainter *painter = engine->painter(); const QTransform transform = painter->transform(); QRectF devRect = transform.mapRect(br); if (penWidthAdjustment > 0) { devRect = devRect.adjusted(-penWidthAdjustment, -penWidthAdjustment, penWidthAdjustment, penWidthAdjustment); } if (boundingRect.isEmpty()) { boundingRect = devRect; } else { qreal min_x = qMin(devRect.left(), boundingRect.left()); qreal min_y = qMin(devRect.top(), boundingRect.top()); qreal max_x = qMax(devRect.right(), boundingRect.right()); qreal max_y = qMax(devRect.bottom(), boundingRect.bottom()); boundingRect = QRectF(min_x, min_y, max_x - min_x, max_y - min_y); } if (painter->hasClipping()) boundingRect &= transform.mapRect(painter->clipRegion().boundingRect()); } /************************************************************************ * * QPaintBuffer * ************************************************************************/ QPaintBuffer::QPaintBuffer() : d_ptr(new QPaintBufferPrivate) { } QPaintBuffer::~QPaintBuffer() { if (!d_ptr->ref.deref()) delete d_ptr; } QPaintBuffer::QPaintBuffer(const QPaintBuffer &other) : QPaintDevice(), d_ptr(other.d_ptr) { d_ptr->ref.ref(); } QPaintEngine *QPaintBuffer::paintEngine() const { QPaintBufferPrivate *d = const_cast(this)->d_ptr; if (!d->engine) d->engine = new QPaintBufferEngine(d); return d->engine; } int QPaintBuffer::metric(PaintDeviceMetric metric) const { int val = 0; switch (metric) { case PdmWidth: val = qCeil(d_ptr->boundingRect.width()); break; case PdmHeight: val = qCeil(d_ptr->boundingRect.height()); break; case PdmDpiX: case PdmPhysicalDpiX: val = qt_defaultDpiX(); break; case PdmDpiY: case PdmPhysicalDpiY: val = qt_defaultDpiY(); break; default: val = QPaintDevice::metric(metric); } return val; } int QPaintBuffer::devType() const { return QInternal::PaintBuffer; } QPaintBuffer &QPaintBuffer::operator=(const QPaintBuffer &other) { if (other.d_ptr != d_ptr) { QPaintBufferPrivate *data = other.d_ptr; data->ref.ref(); if (d_ptr->ref.deref()) delete d_ptr; d_ptr = data; } return *this; } bool QPaintBuffer::isEmpty() const { return d_ptr->commands.isEmpty(); } void QPaintBuffer::draw(QPainter *painter, int frame) const { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBuffer::draw() --------------------------------"; Q_D(const QPaintBuffer); printf("Float buffer:"); for (int i=0; ifloats.size(); i++) { if ((i % 10) == 0) { printf("\n%4d-%4d: ", i, i+9); } printf("%4.2f ", d->floats[i]); } printf("\n"); printf("Int Buffer:"); for (int i=0; iints.size(); i++) { if ((i % 10) == 0) { printf("\n%4d-%4d: ", i, i+10); } printf("%5d", d->ints[i]); } printf("\n"); #endif processCommands(painter, frameStartIndex(frame), frameEndIndex(frame)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBuffer::draw() -------------------------------- DONE!"; #endif } int QPaintBuffer::frameStartIndex(int frame) const { return (frame == 0) ? 0 : d_ptr->frames.at(frame - 1); } int QPaintBuffer::frameEndIndex(int frame) const { return (frame == d_ptr->frames.size()) ? d_ptr->commands.size() : d_ptr->frames.at(frame); } int QPaintBuffer::processCommands(QPainter *painter, int begin, int end) const { if (!painter || !painter->isActive()) return 0; QPaintEngineEx *xengine = painter->paintEngine()->isExtended() ? (QPaintEngineEx *) painter->paintEngine() : 0; if (xengine) { QPaintEngineExReplayer player; player.processCommands(*this, painter, begin, end); } else { QPainterReplayer player; player.processCommands(*this, painter, begin, end); } int depth = 0; for (int i = begin; i < end; ++i) { const QPaintBufferCommand &cmd = d_ptr->commands.at(i); if (cmd.id == QPaintBufferPrivate::Cmd_Save) ++depth; else if (cmd.id == QPaintBufferPrivate::Cmd_Restore) --depth; } return depth; } #ifndef QT_NO_DEBUG_STREAM QString QPaintBuffer::commandDescription(int command) const { QString desc; QDebug debug(&desc); const QPaintBufferCommand &cmd = d_ptr->commands.at(command); switch (cmd.id) { case QPaintBufferPrivate::Cmd_Save: { debug << "Cmd_Save"; break; } case QPaintBufferPrivate::Cmd_Restore: { debug << "Cmd_Restore"; break; } case QPaintBufferPrivate::Cmd_SetBrush: { QBrush brush = qvariant_cast(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetBrush: " << brush; break; } case QPaintBufferPrivate::Cmd_SetBrushOrigin: { debug << "Cmd_SetBrushOrigin: " << d_ptr->variants.at(cmd.offset).toPointF(); break; } case QPaintBufferPrivate::Cmd_SetCompositionMode: { QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; debug << "ExCmd_SetCompositionMode, mode: " << mode; break; } case QPaintBufferPrivate::Cmd_SetOpacity: { debug << "ExCmd_SetOpacity: " << d_ptr->variants.at(cmd.offset).toDouble(); break; } case QPaintBufferPrivate::Cmd_DrawVectorPath: { debug << "ExCmd_DrawVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2; break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { QPen pen = qvariant_cast(d_ptr->variants.at(cmd.extra)); debug << "ExCmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << pen; break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { QBrush brush = qvariant_cast(d_ptr->variants.at(cmd.extra)); debug << "ExCmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << brush; break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { QBrush brush = qvariant_cast(d_ptr->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; break; } case QPaintBufferPrivate::Cmd_FillRectColor: { QColor color = qvariant_cast(d_ptr->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; break; } case QPaintBufferPrivate::Cmd_DrawPolygonF: { debug << "ExCmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d_ptr->floats.at(cmd.offset) << d_ptr->floats.at(cmd.offset+1); break; } case QPaintBufferPrivate::Cmd_DrawPolygonI: { debug << "ExCmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d_ptr->ints.at(cmd.offset) << d_ptr->ints.at(cmd.offset+1); break; } case QPaintBufferPrivate::Cmd_DrawEllipseF: { debug << "ExCmd_DrawEllipseF, offset: " << cmd.offset; break; } case QPaintBufferPrivate::Cmd_DrawLineF: { debug << "ExCmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawLineI: { debug << "ExCmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawPointsF: { debug << "ExCmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawPointsI: { debug << "ExCmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawPolylineF: { debug << "ExCmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawPolylineI: { debug << "ExCmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawRectF: { debug << "ExCmd_DrawRectF, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawRectI: { debug << "ExCmd_DrawRectI, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_SetClipEnabled: { bool clipEnabled = d_ptr->variants.at(cmd.offset).toBool(); debug << "ExCmd_SetClipEnabled:" << clipEnabled; break; } case QPaintBufferPrivate::Cmd_ClipVectorPath: { QVectorPathCmd path(d_ptr, cmd); debug << "ExCmd_ClipVectorPath:" << path().elementCount(); break; } case QPaintBufferPrivate::Cmd_ClipRect: { QRect rect(QPoint(d_ptr->ints.at(cmd.offset), d_ptr->ints.at(cmd.offset + 1)), QPoint(d_ptr->ints.at(cmd.offset + 2), d_ptr->ints.at(cmd.offset + 3))); debug << "ExCmd_ClipRect:" << rect << cmd.extra; break; } case QPaintBufferPrivate::Cmd_ClipRegion: { QRegion region(d_ptr->variants.at(cmd.offset).value()); debug << "ExCmd_ClipRegion:" << region.boundingRect() << cmd.extra; break; } case QPaintBufferPrivate::Cmd_SetPen: { QPen pen = qvariant_cast(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetPen: " << pen; break; } case QPaintBufferPrivate::Cmd_SetTransform: { QTransform xform = qvariant_cast(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetTransform, offset: " << cmd.offset << xform; break; } case QPaintBufferPrivate::Cmd_SetRenderHints: { debug << "Cmd_SetRenderHints, hints: " << cmd.extra; break; } case QPaintBufferPrivate::Cmd_SetBackgroundMode: { debug << "Cmd_SetBackgroundMode: " << cmd.extra; break; } case QPaintBufferPrivate::Cmd_DrawConvexPolygonF: { debug << "Cmd_DrawConvexPolygonF, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawConvexPolygonI: { debug << "Cmd_DrawConvexPolygonI, offset: " << cmd.offset << " size: " << cmd.size; break; } case QPaintBufferPrivate::Cmd_DrawEllipseI: { debug << "Cmd_DrawEllipseI, offset: " << cmd.offset; break; } case QPaintBufferPrivate::Cmd_DrawPixmapRect: { QPixmap pm(d_ptr->variants.at(cmd.offset).value()); QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5), d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7)); debug << "Cmd_DrawPixmapRect:" << r << sr << pm.size(); break; } case QPaintBufferPrivate::Cmd_DrawPixmapPos: { QPixmap pm(d_ptr->variants.at(cmd.offset).value()); QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); debug << "Cmd_DrawPixmapPos:" << pos << pm.size(); break; } case QPaintBufferPrivate::Cmd_DrawTiledPixmap: { QPixmap pm(d_ptr->variants.at(cmd.offset).value()); QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); QPointF offset(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5)); debug << "Cmd_DrawTiledPixmap:" << r << offset << pm.size(); break; } case QPaintBufferPrivate::Cmd_DrawImageRect: { QImage image(d_ptr->variants.at(cmd.offset).value()); QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5), d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7)); debug << "Cmd_DrawImageRect:" << r << sr << image.size(); break; } case QPaintBufferPrivate::Cmd_DrawImagePos: { QImage image(d_ptr->variants.at(cmd.offset).value()); QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); debug << "Cmd_DrawImagePos:" << pos << image.size(); break; } case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); QList variants(d_ptr->variants.at(cmd.offset).value >()); QFont font(variants.at(0).value()); QString text(variants.at(1).value()); debug << "Cmd_DrawText:" << pos << text << font.family(); break; } case QPaintBufferPrivate::Cmd_DrawTextItem: { QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); QTextItemIntCopy *tiCopy = reinterpret_cast(qvariant_cast(d_ptr->variants.at(cmd.offset))); QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); debug << "Cmd_DrawTextItem:" << pos << " " << text; break; } case QPaintBufferPrivate::Cmd_SystemStateChanged: { QRegion systemClip(d_ptr->variants.at(cmd.offset).value()); debug << "Cmd_SystemStateChanged:" << systemClip; break; } case QPaintBufferPrivate::Cmd_Translate: { QPointF delta(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); debug << "Cmd_Translate:" << delta; break; } case QPaintBufferPrivate::Cmd_DrawStaticText: { debug << "Cmd_DrawStaticText"; break; } } return desc; } #endif QRectF QPaintBuffer::boundingRect() const { return d_ptr->boundingRect; } void QPaintBuffer::setBoundingRect(const QRectF &rect) { d_ptr->boundingRect = rect; d_ptr->calculateBoundingRect = false; } class QPaintBufferEnginePrivate : public QPaintEngineExPrivate { Q_DECLARE_PUBLIC(QPaintBufferEngine) public: void systemStateChanged() { Q_Q(QPaintBufferEngine); q->buffer->addCommand(QPaintBufferPrivate::Cmd_SystemStateChanged, QVariant(systemClip)); } QTransform last; }; /************************************************************************ * * QPaintBufferEngine * ************************************************************************/ QPaintBufferEngine::QPaintBufferEngine(QPaintBufferPrivate *b) : QPaintEngineEx(*(new QPaintBufferEnginePrivate)) , buffer(b) , m_begin_detected(false) , m_save_detected(false) , m_stream_raw_text_items(false) { } bool QPaintBufferEngine::begin(QPaintDevice *) { Q_D(QPaintBufferEngine); painter()->save(); d->systemStateChanged(); return true; } bool QPaintBufferEngine::end() { painter()->restore(); m_created_state = 0; return true; } QPainterState *QPaintBufferEngine::createState(QPainterState *orig) const { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: createState, orig=" << orig << ", current=" << state(); #endif Q_ASSERT(!m_begin_detected); Q_ASSERT(!m_save_detected); if (orig == 0) { m_begin_detected = true; return new QPainterState(); } else { m_save_detected = true; return new QPainterState(orig); } } void QPaintBufferEngine::clip(const QVectorPath &path, Qt::ClipOperation op) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: clip vpath:" << path.elementCount() << "op:" << op; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_ClipVectorPath, path); cmd->extra = op; } void QPaintBufferEngine::clip(const QRect &rect, Qt::ClipOperation op) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: clip rect:" << rect << "op:" << op; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_ClipRect, (int *) &rect, 4, 1); cmd->extra = op; } void QPaintBufferEngine::clip(const QRegion ®ion, Qt::ClipOperation op) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: clip region br:" << region.boundingRect() << "op:" << op; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_ClipRegion, QVariant(region)); cmd->extra = op; } void QPaintBufferEngine::clip(const QPainterPath &path, Qt::ClipOperation op) { // ### TODO // QPaintBufferCommand *cmd = // buffer->addCommand(QPaintBufferPrivate::Cmd_ClipPath, QVariant(path)); // cmd->extra = op; QPaintEngineEx::clip(path, op); } void QPaintBufferEngine::clipEnabledChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: clip enable change" << state()->clipEnabled; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetClipEnabled, state()->clipEnabled); } void QPaintBufferEngine::penChanged() { const QPen &pen = state()->pen; if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetPen) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: penChanged (compressed)" << state()->pen; #endif buffer->variants[buffer->commands.last().offset] = pen; return; } if (buffer->calculateBoundingRect) { if (pen.style() == Qt::NoPen) { buffer->penWidthAdjustment = 0; } else { qreal penWidth = (pen.widthF() == 0) ? 1 : pen.widthF(); QPointF transformedWidth(penWidth, penWidth); if (!qt_pen_is_cosmetic(pen, state()->renderHints)) transformedWidth = painter()->transform().map(transformedWidth); buffer->penWidthAdjustment = transformedWidth.x() / 2.0; } } #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: penChanged" << state()->pen; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetPen, pen); } void QPaintBufferEngine::brushChanged() { const QBrush &brush = state()->brush; if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetBrush) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: brushChanged (compressed)" << state()->brush; #endif buffer->variants[buffer->commands.last().offset] = brush; return; } #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: brushChanged" << state()->brush; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetBrush, brush); } void QPaintBufferEngine::brushOriginChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: brush origin changed" << state()->brushOrigin; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetBrushOrigin, state()->brushOrigin); } void QPaintBufferEngine::opacityChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: opacity changed" << state()->opacity; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetOpacity, state()->opacity); } void QPaintBufferEngine::compositionModeChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: composition mode" << state()->composition_mode; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_SetCompositionMode); cmd->extra = state()->composition_mode; } void QPaintBufferEngine::renderHintsChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: render hints changed" << state()->renderHints; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_SetRenderHints); cmd->extra = state()->renderHints; } void QPaintBufferEngine::transformChanged() { Q_D(QPaintBufferEngine); const QTransform &transform = state()->matrix; QTransform delta; bool invertible = false; if (transform.type() <= QTransform::TxScale && transform.type() == d->last.type()) delta = transform * d->last.inverted(&invertible); d->last = transform; if (invertible && delta.type() == QTransform::TxNone) return; if (invertible && delta.type() == QTransform::TxTranslate) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: transformChanged (translate only) " << state()->matrix; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_Translate); qreal data[] = { delta.dx(), delta.dy() }; cmd->extra = buffer->addData((qreal *) data, 2); return; } // ### accumulate, like in QBrush case... if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: transformChanged (compressing) " << state()->matrix; #endif buffer->variants[buffer->commands.last().offset] = state()->matrix; return; } #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: transformChanged:" << state()->matrix; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetTransform, state()->matrix); } void QPaintBufferEngine::backgroundModeChanged() { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintEngineBuffer: background mode changed" << state()->bgMode; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_SetBackgroundMode); cmd->extra = state()->bgMode; } void QPaintBufferEngine::draw(const QVectorPath &path) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: draw vpath:" << path.elementCount(); #endif bool hasBrush = qbrush_style(state()->brush) != Qt::NoBrush; bool hasPen = qpen_style(state()->pen) != Qt::NoPen && qbrush_style(qpen_brush(state()->pen)) != Qt::NoBrush; if (hasPen || hasBrush) buffer->addCommand(QPaintBufferPrivate::Cmd_DrawVectorPath, path); #ifdef QPAINTBUFFER_DEBUG_DRAW else qDebug() << " - no pen or brush active, discarded...\n"; #endif // if (buffer->calculateBoundingRect) { // QRealRect r = path.controlPointRect(); // buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1)); // } } void QPaintBufferEngine::fill(const QVectorPath &path, const QBrush &brush) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: fill vpath:" << path.elementCount() << brush; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_FillVectorPath, path); cmd->extra = buffer->addData(QVariant(brush)); // if (buffer->calculateBoundingRect) { // QRealRect r = path.controlPointRect(); // buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1)); // } } void QPaintBufferEngine::stroke(const QVectorPath &path, const QPen &pen) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: stroke vpath:" << path.elementCount() << pen; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_StrokeVectorPath, path); cmd->extra = buffer->addData(QVariant(pen)); // if (buffer->calculateBoundingRect) { // QRealRect r = path.controlPointRect(); // buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1)); // } } void QPaintBufferEngine::fillRect(const QRectF &rect, const QBrush &brush) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: fillRect brush:" << rect << brush; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_FillRectBrush, (qreal *) &rect, 4, 1); cmd->extra = buffer->addData(brush); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(rect); } void QPaintBufferEngine::fillRect(const QRectF &rect, const QColor &color) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: fillRect color:" << rect << color; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_FillRectColor, (qreal *) &rect, 4, 1); cmd->extra = buffer->addData(color); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(rect); } void QPaintBufferEngine::drawRects(const QRect *rects, int rectCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawRectsI:" << rectCount; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawRectI, (int *) rects, 4 * rectCount, rectCount); cmd->extra = rectCount; if (buffer->calculateBoundingRect) { if (rectCount == 1) { buffer->updateBoundingRect(rects[0]); } else { int min_x = rects[0].left(); int min_y = rects[0].top(); int max_x = rects[0].left() + rects[0].width(); int max_y = rects[0].top() + rects[0].height(); for (int i=1; i< rectCount; ++i) { if (rects[i].left() < min_x) min_x = rects[i].left(); if (rects[i].top() < min_y) min_y = rects[i].top(); if (rects[i].right() > max_x) max_x = rects[i].left() + rects[i].width(); if (rects[i].bottom() > max_y) max_y = rects[i].top() + rects[i].height(); } buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } } void QPaintBufferEngine::drawRects(const QRectF *rects, int rectCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawRectsF:" << rectCount; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawRectF, (qreal *) rects, 4 * rectCount, rectCount); cmd->extra = rectCount; if (buffer->calculateBoundingRect) { if (rectCount == 1) { buffer->updateBoundingRect(rects[0]); } else { qreal min_x = rects[0].left(); qreal min_y = rects[0].top(); qreal max_x = rects[0].right(); qreal max_y = rects[0].bottom(); for (int i=1; i< rectCount; ++i) { if (rects[i].left() < min_x) min_x = rects[i].left(); if (rects[i].top() < min_y) min_y = rects[i].top(); if (rects[i].right() > max_x) max_x = rects[i].right(); if (rects[i].bottom() > max_y) max_y = rects[i].bottom(); } buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } } void QPaintBufferEngine::drawLines(const QLine *lines, int lineCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawLinesI:" << lineCount; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawLineI, (int *) lines, 4 * lineCount, lineCount); cmd->extra = lineCount; if (buffer->calculateBoundingRect) { int min_x = lines[0].p1().x(); int min_y = lines[0].p1().y(); int max_x = lines[0].p2().x(); int max_y = lines[0].p2().y(); if (min_x > max_x) qSwap(min_x, max_x); if (min_y > max_y) qSwap(min_y, max_y); for (int i=1; i < lineCount; ++i) { int p1_x = lines[i].p1().x(); int p1_y = lines[i].p1().y(); int p2_x = lines[i].p2().x(); int p2_y = lines[i].p2().y(); if (p1_x > p2_x) { min_x = qMin(p2_x, min_x); max_x = qMax(p1_x, max_x); } else { min_x = qMin(p1_x, min_x); max_x = qMax(p2_x, max_x); } if (p1_y > p2_y) { min_y = qMin(p2_y, min_y); max_y = qMax(p1_y, max_y); } else { min_y = qMin(p1_y, min_y); max_y = qMax(p2_y, max_y); } } buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawLines(const QLineF *lines, int lineCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawLinesF:" << lineCount; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawLineF, (qreal *) lines, 4 * lineCount, lineCount); cmd->extra = lineCount; if (buffer->calculateBoundingRect) { qreal min_x = lines[0].p1().x(); qreal min_y = lines[0].p1().y(); qreal max_x = lines[0].p2().x(); qreal max_y = lines[0].p2().y(); if (min_x > max_x) qSwap(min_x, max_x); if (min_y > max_y) qSwap(min_y, max_y); for (int i=1; i < lineCount; ++i) { qreal p1_x = lines[i].p1().x(); qreal p1_y = lines[i].p1().y(); qreal p2_x = lines[i].p2().x(); qreal p2_y = lines[i].p2().y(); if (p1_x > p2_x) { min_x = qMin(p2_x, min_x); max_x = qMax(p1_x, max_x); } else { min_x = qMin(p1_x, min_x); max_x = qMax(p2_x, max_x); } if (p1_y > p2_y) { min_y = qMin(p2_y, min_y); max_y = qMax(p1_y, max_y); } else { min_y = qMin(p1_y, min_y); max_y = qMax(p2_y, max_y); } } buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawEllipse(const QRectF &r) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawEllipseF:" << r; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_DrawEllipseF, (qreal *) &r, 4, 1); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(r); } void QPaintBufferEngine::drawEllipse(const QRect &r) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawEllipseI:" << r; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_DrawEllipseI, (int *) &r, 4, 1); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(r); } void QPaintBufferEngine::drawPath(const QPainterPath &path) { // #ifdef QPAINTBUFFER_DEBUG_DRAW // qDebug() << "QPaintBufferEngine: drawPath: element count:" << path.elementCount(); // #endif // // ### Path -> QVariant // // buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPath, QVariant(path)); QPaintEngineEx::drawPath(path); // if (buffer->calculateBoundingRect) // buffer->updateBoundingRect(path.boundingRect()); } void QPaintBufferEngine::drawPoints(const QPoint *points, int pointCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPointsI: " << pointCount; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPointsI, (int *) points, 2 * pointCount, pointCount); if (buffer->calculateBoundingRect) { int min_x = points[0].x(); int min_y = points[0].y(); int max_x = points[0].x()+1; int max_y = points[0].y()+1; for (int i=1; iupdateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawPoints(const QPointF *points, int pointCount) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPointsF: " << pointCount; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPointsF, (qreal *) points, 2 * pointCount, pointCount); if (buffer->calculateBoundingRect) { qreal min_x = points[0].x(); qreal min_y = points[0].y(); qreal max_x = points[0].x()+1; qreal max_y = points[0].y()+1; for (int i=1; iupdateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawPolygon(const QPoint *pts, int count, PolygonDrawMode mode) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPolygonI: size:" << count << ", mode:" << mode; #endif if (mode == QPaintEngine::OddEvenMode || mode == QPaintEngine::WindingMode) { QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolygonI, (int *) pts, 2 * count, count); cmd->extra = mode; } else if (mode == QPaintEngine::PolylineMode) { buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolylineI, (int *) pts, 2 * count, count); } else { buffer->addCommand(QPaintBufferPrivate::Cmd_DrawConvexPolygonI, (int *) pts, 2 * count, count); } if (buffer->calculateBoundingRect) { int min_x = pts[0].x(); int min_y = pts[0].y(); int max_x = pts[0].x(); int max_y = pts[0].y(); for (int i=1; iupdateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawPolygon(const QPointF *pts, int count, PolygonDrawMode mode) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPolygonF: size:" << count << ", mode:" << mode; #endif if (mode == QPaintEngine::OddEvenMode || mode == QPaintEngine::WindingMode) { QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolygonF, (qreal *) pts, 2 * count, count); cmd->extra = mode; } else if (mode == QPaintEngine::PolylineMode) { buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolylineF, (qreal *) pts, 2 * count, count); } else { buffer->addCommand(QPaintBufferPrivate::Cmd_DrawConvexPolygonF, (qreal *) pts, 2 * count, count); } if (buffer->calculateBoundingRect) { qreal min_x = pts[0].x(); qreal min_y = pts[0].y(); qreal max_x = pts[0].x(); qreal max_y = pts[0].y(); for (int i=1; iupdateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y)); } } void QPaintBufferEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPixmap: src/dest rects " << r << sr; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPixmapRect, QVariant(pm)); cmd->extra = buffer->addData((qreal *) &r, 4); buffer->addData((qreal *) &sr, 4); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(r); } void QPaintBufferEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawPixmap: pos:" << pos; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPixmapPos, QVariant(pm)); cmd->extra = buffer->addData((qreal *) &pos, 2); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(QRectF(pos, pm.size())); } static inline QImage qpaintbuffer_storable_image(const QImage &src) { QImageData *d = const_cast(src).data_ptr(); return d->own_data ? src : src.copy(); } void QPaintBufferEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags /*flags */) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawImage: src/dest rects " << r << sr; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImageRect, QVariant(qpaintbuffer_storable_image(image))); cmd->extra = buffer->addData((qreal *) &r, 4); buffer->addData((qreal *) &sr, 4); // ### flags... if (buffer->calculateBoundingRect) buffer->updateBoundingRect(r); } void QPaintBufferEngine::drawImage(const QPointF &pos, const QImage &image) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawImage: pos:" << pos; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImagePos, QVariant(qpaintbuffer_storable_image(image))); cmd->extra = buffer->addData((qreal *) &pos, 2); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(QRectF(pos, image.size())); } void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &s) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawTiledPixmap: src rect/offset:" << r << s; #endif QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTiledPixmap, QVariant(pm)); cmd->extra = buffer->addData((qreal *) &r, 4); buffer->addData((qreal *) &s, 2); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(r); } void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) { if (staticTextItem->usesRawFont) { QPaintEngineEx::drawStaticTextItem(staticTextItem); // Draw as path return; } QVariantList variants; variants << QVariant(staticTextItem->font); for (int i=0; inumGlyphs; ++i) { variants.append(staticTextItem->glyphs[i]); variants.append(staticTextItem->glyphPositions[i].toPointF()); } buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); } void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: drawTextItem: pos:" << pos << ti.text(); #endif if (m_stream_raw_text_items) { QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTextItem, QVariant::fromValue(new QTextItemIntCopy(ti))); QFont font(ti.font()); font.setUnderline(false); font.setStrikeOut(false); font.setOverline(false); const QTextItemInt &si = static_cast(ti); qreal justificationWidth = 0; if (si.justified) justificationWidth = si.width.toReal(); int renderFlags = ti.renderFlags(); qreal scaleFactor = font.d->dpi/qreal(qt_defaultDpiY()); buffer->addData(QVariant(font)); cmd->extra = buffer->addData((qreal *) &pos, 2); buffer->addData((qreal *) &justificationWidth, 1); buffer->addData((qreal *) &scaleFactor, 1); cmd->offset2 = buffer->addData((int *) &renderFlags, 1); } else { QList variants; variants << QVariant(ti.font()) << QVariant(ti.text()); QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawText, QVariant(variants)); cmd->extra = buffer->addData((qreal *) &pos, 2); } if (buffer->calculateBoundingRect) buffer->updateBoundingRect(QRectF(pos, QSize(ti.width(), ti.ascent() + ti.descent() + 1))); } void QPaintBufferEngine::setState(QPainterState *s) { Q_D(QPaintBufferEngine); if (m_begin_detected) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: setState: begin, ignoring."; #endif m_begin_detected = false; } else if (m_save_detected) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: setState: save."; #endif m_save_detected = false; buffer->addCommand(QPaintBufferPrivate::Cmd_Save); } else { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: setState: restore."; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_Restore); } d->last = s->matrix; QPaintEngineEx::setState(s); } /*********************************************************************** * * class QPaintBufferPlayback_Painter * */ // QFakeDevice is used to create fonts with a custom DPI // class QFakeDevice : public QPaintDevice { public: QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); } void setDpiX(int dpi) { dpi_x = dpi; } void setDpiY(int dpi) { dpi_y = dpi; } QPaintEngine *paintEngine() const { return 0; } int metric(PaintDeviceMetric m) const { switch(m) { case PdmPhysicalDpiX: case PdmDpiX: return dpi_x; case PdmPhysicalDpiY: case PdmDpiY: return dpi_y; default: return QPaintDevice::metric(m); } } private: int dpi_x; int dpi_y; }; void QPainterReplayer::setupTransform(QPainter *_painter) { painter = _painter; m_world_matrix = painter->transform(); m_world_matrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()), qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY())); painter->setTransform(m_world_matrix); } void QPainterReplayer::processCommands(const QPaintBuffer &buffer, QPainter *p, int begin, int end) { d = buffer.d_ptr; painter = p; for (int cmdIndex = begin; cmdIndex < end; ++cmdIndex) { const QPaintBufferCommand &cmd = d->commands.at(cmdIndex); process(cmd); } } void QPaintBuffer::beginNewFrame() { if (!d_ptr->commands.isEmpty()) d_ptr->frames << d_ptr->commands.size(); } int QPaintBuffer::numFrames() const { return d_ptr->frames.size() + 1; } void QPainterReplayer::process(const QPaintBufferCommand &cmd) { switch (cmd.id) { case QPaintBufferPrivate::Cmd_Save: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_Save"; #endif painter->save(); break; } case QPaintBufferPrivate::Cmd_Restore: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_Restore"; #endif painter->restore(); break; } case QPaintBufferPrivate::Cmd_SetPen: { QPen pen = qvariant_cast(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetPen: " << pen; #endif painter->setPen(pen); break; } case QPaintBufferPrivate::Cmd_SetBrush: { QBrush brush = qvariant_cast(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetBrush: " << brush; #endif painter->setBrush(brush); break; } case QPaintBufferPrivate::Cmd_SetBrushOrigin: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetBrushOrigin: " << d->variants.at(cmd.offset).toPointF(); #endif painter->setBrushOrigin(d->variants.at(cmd.offset).toPointF()); break; } case QPaintBufferPrivate::Cmd_SetTransform: { QTransform xform = qvariant_cast(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetTransform, offset: " << cmd.offset << xform; #endif painter->setTransform(xform * m_world_matrix); break; } case QPaintBufferPrivate::Cmd_Translate: { QPointF delta(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_Translate, offset: " << cmd.offset << delta; #endif painter->translate(delta.x(), delta.y()); return; } case QPaintBufferPrivate::Cmd_SetCompositionMode: { QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetCompositionMode, mode: " << mode; #endif painter->setCompositionMode(mode); break; } case QPaintBufferPrivate::Cmd_SetRenderHints: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetRenderHints, hints: " << cmd.extra; #endif QPainter::RenderHints ph = painter->renderHints(); QPainter::RenderHints nh = (QPainter::RenderHints) cmd.extra; QPainter::RenderHints xored = ph ^ nh; if (xored & QPainter::Antialiasing) painter->setRenderHint(QPainter::Antialiasing, nh & QPainter::Antialiasing); if (xored & QPainter::HighQualityAntialiasing) painter->setRenderHint(QPainter::HighQualityAntialiasing, nh & QPainter::HighQualityAntialiasing); if (xored & QPainter::TextAntialiasing) painter->setRenderHint(QPainter::TextAntialiasing, nh & QPainter::TextAntialiasing); if (xored & QPainter::SmoothPixmapTransform) painter->setRenderHint(QPainter::SmoothPixmapTransform, nh & QPainter::SmoothPixmapTransform); if (xored & QPainter::NonCosmeticDefaultPen) painter->setRenderHint(QPainter::NonCosmeticDefaultPen, nh & QPainter::NonCosmeticDefaultPen); if (xored & QPainter::Qt4CompatiblePainting) painter->setRenderHint(QPainter::Qt4CompatiblePainting, nh & QPainter::Qt4CompatiblePainting); break; } case QPaintBufferPrivate::Cmd_SetOpacity: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetOpacity: " << d->variants.at(cmd.offset).toDouble(); #endif painter->setOpacity(d->variants.at(cmd.offset).toDouble()); break; } case QPaintBufferPrivate::Cmd_SetBackgroundMode: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetBackgroundMode: " << cmd.extra; #endif painter->setBackgroundMode((Qt::BGMode)cmd.extra); break; } case QPaintBufferPrivate::Cmd_DrawVectorPath: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2; #endif QVectorPathCmd path(d, cmd); painter->drawPath(path().convertToPainterPath()); break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { QPen pen = qvariant_cast(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2; #endif QVectorPathCmd path(d, cmd); painter->strokePath(path().convertToPainterPath(), pen); break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { QBrush brush = qvariant_cast(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << brush; #endif QVectorPathCmd path(d, cmd); painter->fillPath(path().convertToPainterPath(), brush); break; } case QPaintBufferPrivate::Cmd_DrawPolygonF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d->floats.at(cmd.offset) << d->floats.at(cmd.offset+1); #endif Qt::FillRule fill = (QPaintEngine::PolygonDrawMode) cmd.extra == QPaintEngine::OddEvenMode ? Qt::OddEvenFill : Qt::WindingFill; painter->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size, fill); break; } case QPaintBufferPrivate::Cmd_DrawPolygonI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d->ints.at(cmd.offset) << d->ints.at(cmd.offset+1); #endif Qt::FillRule fill = (QPaintEngine::PolygonDrawMode) cmd.extra == QPaintEngine::OddEvenMode ? Qt::OddEvenFill : Qt::WindingFill; painter->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size, fill); break; } case QPaintBufferPrivate::Cmd_DrawPolylineF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawPolyline((QPointF *) (d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPolylineI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawPolyline((QPoint *) (d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawConvexPolygonF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawConvexPolygonF, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawConvexPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawConvexPolygonI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawConvexPolygonI, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawConvexPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawEllipseF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawEllipseF, offset: " << cmd.offset; #endif painter->drawEllipse(*(QRectF *)(d->floats.constData() + cmd.offset)); break; } case QPaintBufferPrivate::Cmd_DrawEllipseI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawEllipseI, offset: " << cmd.offset; #endif painter->drawEllipse(*(QRect *)(d->ints.constData() + cmd.offset)); break; } case QPaintBufferPrivate::Cmd_DrawLineF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawLines((QLineF *)(d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawLineI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawLines((QLine *)(d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPointsF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawPoints((QPointF *)(d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPointsI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size; #endif painter->drawPoints((QPoint *)(d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPixmapRect: { QPixmap pm(d->variants.at(cmd.offset).value()); QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1), d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3)); QRectF sr(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5), d->floats.at(cmd.extra+6), d->floats.at(cmd.extra+7)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPixmapRect:" << r << sr; #endif painter->drawPixmap(r, pm, sr); break; } case QPaintBufferPrivate::Cmd_DrawPixmapPos: { QPixmap pm(d->variants.at(cmd.offset).value()); QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawPixmapPos:" << pos; #endif painter->drawPixmap(pos, pm); break; } case QPaintBufferPrivate::Cmd_DrawTiledPixmap: { QPixmap pm(d->variants.at(cmd.offset).value()); QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1), d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3)); QPointF offset(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawTiledPixmap:" << r << offset; #endif painter->drawTiledPixmap(r, pm, offset); break; } case QPaintBufferPrivate::Cmd_DrawImageRect: { QImage image(d->variants.at(cmd.offset).value()); QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1), d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3)); QRectF sr(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5), d->floats.at(cmd.extra+6), d->floats.at(cmd.extra+7)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawImageRect:" << r << sr; #endif painter->drawImage(r, image, sr); break; } case QPaintBufferPrivate::Cmd_DrawImagePos: { QImage image(d->variants.at(cmd.offset).value()); QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawImagePos:" << pos; #endif painter->drawImage(pos, image); break; } case QPaintBufferPrivate::Cmd_DrawRectF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawRectF, offset: " << cmd.offset; #endif painter->drawRects((QRectF *)(d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawRectI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawRectI, offset: " << cmd.offset; #endif painter->drawRects((QRect *)(d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { QBrush brush = qvariant_cast(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; #endif painter->fillRect(*rect, brush); break; } case QPaintBufferPrivate::Cmd_FillRectColor: { QColor color = qvariant_cast(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; #endif painter->fillRect(*rect, color); break; } case QPaintBufferPrivate::Cmd_SetClipEnabled: { bool clipEnabled = d->variants.at(cmd.offset).toBool(); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetClipEnabled:" << clipEnabled; #endif painter->setClipping(clipEnabled); break; } case QPaintBufferPrivate::Cmd_ClipVectorPath: { QVectorPathCmd path(d, cmd); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_ClipVectorPath:" << path().elementCount(); #endif painter->setClipPath(path().convertToPainterPath(), Qt::ClipOperation(cmd.extra)); break; } case QPaintBufferPrivate::Cmd_ClipRect: { QRect rect(QPoint(d->ints.at(cmd.offset), d->ints.at(cmd.offset + 1)), QPoint(d->ints.at(cmd.offset + 2), d->ints.at(cmd.offset + 3))); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_ClipRect:" << rect << cmd.extra; #endif painter->setClipRect(rect, Qt::ClipOperation(cmd.extra)); break; } case QPaintBufferPrivate::Cmd_ClipRegion: { QRegion region(d->variants.at(cmd.offset).value()); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_ClipRegion:" << region.boundingRect() << cmd.extra; #endif painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } #if !defined(QT_NO_RAWFONT) case QPaintBufferPrivate::Cmd_DrawStaticText: { QVariantList variants(d->variants.at(cmd.offset).value()); QFont font = variants.at(0).value(); QVector glyphIndexes; QVector positions; for (int i=0; i<(variants.size() - 1) / 2; ++i) { glyphIndexes.append(variants.at(i*2 + 1).toUInt()); positions.append(variants.at(i*2 + 2).toPointF()); } painter->setFont(font); QGlyphRun glyphs; glyphs.setRawFont(QRawFont::fromFont(font, QFontDatabase::Any)); glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(positions); painter->drawGlyphRun(QPointF(), glyphs); break; } #endif case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); QList variants(d->variants.at(cmd.offset).value >()); QFont font(variants.at(0).value()); QString text(variants.at(1).value()); painter->setFont(font); painter->drawText(pos, text); break; } case QPaintBufferPrivate::Cmd_DrawTextItem: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); QTextItemIntCopy *tiCopy = reinterpret_cast(qvariant_cast(d->variants.at(cmd.offset))); QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); QFont font(ti.font()); font.setUnderline(false); font.setStrikeOut(false); font.setOverline(false); const QTextItemInt &si = static_cast(ti); qreal justificationWidth = 0; if (si.justified) justificationWidth = si.width.toReal(); qreal scaleFactor = font.d->dpi/qreal(qt_defaultDpiY()); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_DrawTextItem:" << pos << " " << text << " " << scaleFactor; #endif if (scaleFactor != 1.0) { QFont fnt(font); QFakeDevice fake; fake.setDpiX(qRound(scaleFactor*qt_defaultDpiX())); fake.setDpiY(qRound(scaleFactor*qt_defaultDpiY())); font = QFont(fnt, &fake); } int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight; QSizeF size(1, 1); if (justificationWidth > 0) { size.setWidth(justificationWidth); flags |= Qt::TextJustificationForced; flags |= Qt::AlignJustify; } QFontMetrics fm(font); QPointF pt(pos.x(), pos.y() - fm.ascent()); // ### this does not work outside of Qt code, so we need to emulate it with the following QPainter calls // qt_format_text(font, QRectF(pt, size), flags, /*opt*/0, // text, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter); painter->save(); painter->drawText(QRectF(pt, size), flags, text); painter->restore(); break; } case QPaintBufferPrivate::Cmd_SystemStateChanged: { QRegion systemClip(d->variants.at(cmd.offset).value()); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SystemStateChanged:" << systemClip; #endif painter->paintEngine()->setSystemClip(systemClip); painter->paintEngine()->d_ptr->systemStateChanged(); break; } } } void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd) { Q_ASSERT(painter->paintEngine()->isExtended()); QPaintEngineEx *xengine = static_cast(painter->paintEngine()); switch (cmd.id) { case QPaintBufferPrivate::Cmd_SetBrushOrigin: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_SetBrushOrigin: " << d->variants.at(cmd.offset).toPointF(); #endif xengine->state()->brushOrigin = d->variants.at(cmd.offset).toPointF(); xengine->brushOriginChanged(); break; } case QPaintBufferPrivate::Cmd_SetCompositionMode: { QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_SetCompositionMode, mode: " << mode; #endif xengine->state()->composition_mode = mode; xengine->compositionModeChanged(); break; } case QPaintBufferPrivate::Cmd_SetOpacity: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_SetOpacity: " << d->variants.at(cmd.offset).toDouble(); #endif xengine->state()->opacity = d->variants.at(cmd.offset).toDouble(); xengine->opacityChanged(); break; } case QPaintBufferPrivate::Cmd_DrawVectorPath: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2; #endif QVectorPathCmd path(d, cmd); xengine->draw(path()); break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { QPen pen = qvariant_cast(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2; #endif QVectorPathCmd path(d, cmd); xengine->stroke(path(), pen); break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { QBrush brush = qvariant_cast(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << brush; #endif QVectorPathCmd path(d, cmd); xengine->fill(path(), brush); break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { QBrush brush = qvariant_cast(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; #endif xengine->fillRect(*rect, brush); break; } case QPaintBufferPrivate::Cmd_FillRectColor: { QColor color = qvariant_cast(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; #endif xengine->fillRect(*rect, color); break; } case QPaintBufferPrivate::Cmd_DrawPolygonF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d->floats.at(cmd.offset) << d->floats.at(cmd.offset+1); #endif xengine->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size, (QPaintEngine::PolygonDrawMode) cmd.extra); break; } case QPaintBufferPrivate::Cmd_DrawPolygonI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size << " mode: " << cmd.extra << d->ints.at(cmd.offset) << d->ints.at(cmd.offset+1); #endif xengine->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size, (QPaintEngine::PolygonDrawMode) cmd.extra); break; } case QPaintBufferPrivate::Cmd_DrawEllipseF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawEllipseF, offset: " << cmd.offset; #endif xengine->drawEllipse(*(QRectF *)(d->floats.constData() + cmd.offset)); break; } case QPaintBufferPrivate::Cmd_DrawEllipseI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawEllipseI, offset: " << cmd.offset; #endif xengine->drawEllipse(*(QRect *)(d->ints.constData() + cmd.offset)); break; } case QPaintBufferPrivate::Cmd_DrawLineF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawLines((QLineF *)(d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawLineI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawLines((QLine *)(d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPointsF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawPoints((QPointF *)(d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPointsI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawPoints((QPoint *)(d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawPolylineF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size, QPaintEngine::PolylineMode); break; } case QPaintBufferPrivate::Cmd_DrawPolylineI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size, QPaintEngine::PolylineMode); break; } case QPaintBufferPrivate::Cmd_DrawRectF: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawRectF, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawRects((QRectF *) (d->floats.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_DrawRectI: { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_DrawRectI, offset: " << cmd.offset << " size: " << cmd.size; #endif xengine->drawRects((QRect *) (d->ints.constData() + cmd.offset), cmd.size); break; } case QPaintBufferPrivate::Cmd_SetClipEnabled: { bool clipEnabled = d->variants.at(cmd.offset).toBool(); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_SetClipEnabled:" << clipEnabled; #endif xengine->state()->clipEnabled = clipEnabled; xengine->clipEnabledChanged(); break; } case QPaintBufferPrivate::Cmd_ClipVectorPath: { QVectorPathCmd path(d, cmd); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_ClipVectorPath:" << path().elementCount(); #endif xengine->clip(path(), Qt::ClipOperation(cmd.extra)); break; } case QPaintBufferPrivate::Cmd_ClipRect: { QRect rect(QPoint(d->ints.at(cmd.offset), d->ints.at(cmd.offset + 1)), QPoint(d->ints.at(cmd.offset + 2), d->ints.at(cmd.offset + 3))); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_ClipRect:" << rect << cmd.extra; #endif xengine->clip(rect, Qt::ClipOperation(cmd.extra)); break; } case QPaintBufferPrivate::Cmd_ClipRegion: { QRegion region(d->variants.at(cmd.offset).value()); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_ClipRegion:" << region.boundingRect() << cmd.extra; #endif xengine->clip(region, Qt::ClipOperation(cmd.extra)); break; } default: QPainterReplayer::process(cmd); break; } } QDataStream &operator<<(QDataStream &stream, const QPaintBufferCommand &command) { quint32 id = command.id; quint32 size = command.size; stream << id << size; stream << command.offset << command.offset2 << command.extra; return stream; } QDataStream &operator>>(QDataStream &stream, QPaintBufferCommand &command) { quint32 id; quint32 size; stream >> id >> size; stream >> command.offset >> command.offset2 >> command.extra; command.id = id; command.size = size; return stream; } struct QPaintBufferCacheEntry { QVariant::Type type; quint64 cacheKey; }; struct QPaintBufferCacheEntryV2 { enum Type { ImageKey, PixmapKey }; struct Flags { uint type : 8; uint key : 24; }; union { Flags flags; uint bits; }; }; QT_END_NAMESPACE Q_DECLARE_METATYPE(QPaintBufferCacheEntry) Q_DECLARE_METATYPE(QPaintBufferCacheEntryV2) QT_BEGIN_NAMESPACE QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry) { return stream << entry.type << entry.cacheKey; } QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntry &entry) { return stream >> entry.type >> entry.cacheKey; } QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntryV2 &entry) { return stream << entry.bits; } QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntryV2 &entry) { return stream >> entry.bits; } static void qRegisterPaintBufferMetaTypes() { qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); } Q_CONSTRUCTOR_FUNCTION(qRegisterPaintBufferMetaTypes) QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer) { QHash pixmapKeys; QHash imageKeys; QHash pixmaps; QHash images; QVector variants = buffer.d_ptr->variants; for (int i = 0; i < variants.size(); ++i) { const QVariant &v = variants.at(i); if (v.type() == QVariant::Image) { const QImage image(v.value()); QPaintBufferCacheEntryV2 entry; entry.flags.type = QPaintBufferCacheEntryV2::ImageKey; QHash::iterator it = imageKeys.find(image.cacheKey()); if (it != imageKeys.end()) { entry.flags.key = *it; } else { imageKeys[image.cacheKey()] = entry.flags.key = images.size(); images[images.size()] = image; } variants[i] = QVariant::fromValue(entry); } else if (v.type() == QVariant::Pixmap) { const QPixmap pixmap(v.value()); QPaintBufferCacheEntryV2 entry; entry.flags.type = QPaintBufferCacheEntryV2::PixmapKey; QHash::iterator it = pixmapKeys.find(pixmap.cacheKey()); if (it != pixmapKeys.end()) { entry.flags.key = *it; } else { pixmapKeys[pixmap.cacheKey()] = entry.flags.key = pixmaps.size(); pixmaps[pixmaps.size()] = pixmap; } variants[i] = QVariant::fromValue(entry); } } stream << pixmaps; stream << images; stream << buffer.d_ptr->ints; stream << buffer.d_ptr->floats; stream << variants; stream << buffer.d_ptr->commands; stream << buffer.d_ptr->boundingRect; stream << buffer.d_ptr->frames; return stream; } QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer) { QHash pixmaps; QHash images; stream >> pixmaps; stream >> images; stream >> buffer.d_ptr->ints; stream >> buffer.d_ptr->floats; stream >> buffer.d_ptr->variants; stream >> buffer.d_ptr->commands; stream >> buffer.d_ptr->boundingRect; stream >> buffer.d_ptr->frames; QVector &variants = buffer.d_ptr->variants; for (int i = 0; i < variants.size(); ++i) { const QVariant &v = variants.at(i); if (v.canConvert()) { QPaintBufferCacheEntry entry = v.value(); if (entry.type == QVariant::Image) variants[i] = QVariant(images.value(entry.cacheKey)); else variants[i] = QVariant(pixmaps.value(entry.cacheKey)); } else if (v.canConvert()) { QPaintBufferCacheEntryV2 entry = v.value(); if (entry.flags.type == QPaintBufferCacheEntryV2::ImageKey) variants[i] = QVariant(images.value(entry.flags.key)); else if (entry.flags.type == QPaintBufferCacheEntryV2::PixmapKey) variants[i] = QVariant(pixmaps.value(entry.flags.key)); else qWarning() << "operator<<(QDataStream &stream, QPaintBuffer &buffer): unrecognized cache entry type:" << entry.flags.type; } } return stream; } QT_END_NAMESPACE gammaray-2.3.0/3rdparty/qt/5.5/private/qpaintbuffer_p.h000066400000000000000000000303501255003167400226510ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QPAINTBUFFER_P_H #define QPAINTBUFFER_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 #include #include #include #undef Q_GUI_EXPORT #define Q_GUI_EXPORT QT_BEGIN_NAMESPACE class QPaintBufferPrivate; class QPaintBufferPlayback; class Q_GUI_EXPORT QPaintBuffer : public QPaintDevice { Q_DECLARE_PRIVATE(QPaintBuffer) public: QPaintBuffer(); QPaintBuffer(const QPaintBuffer &other); ~QPaintBuffer(); bool isEmpty() const; void beginNewFrame(); int numFrames() const; void draw(QPainter *painter, int frame = 0) const; int frameStartIndex(int frame) const; int frameEndIndex(int frame) const; int processCommands(QPainter *painter, int begin, int end) const; #ifndef QT_NO_DEBUG_STREAM QString commandDescription(int command) const; #endif void setBoundingRect(const QRectF &rect); QRectF boundingRect() const; virtual QPaintEngine *paintEngine() const; virtual int metric(PaintDeviceMetric m) const; virtual int devType() const; QPaintBuffer &operator=(const QPaintBuffer &other); private: friend class QPainterReplayer; friend class QOpenGLReplayer; friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer); QPaintBufferPrivate *d_ptr; }; Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer); Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer); class QPaintBufferEngine; class QTextItemIntCopy { public: QTextItemIntCopy(const QTextItem &item); ~QTextItemIntCopy(); QTextItemInt &operator () () {return m_item;} private: QTextItemInt m_item; QFont m_font; }; struct QPaintBufferCommand { uint id : 8; uint size : 24; int offset; int offset2; int extra; }; QDataStream &operator<<(QDataStream &stream, const QPaintBufferCommand &command); QDataStream &operator>>(QDataStream &stream, QPaintBufferCommand &command); Q_DECLARE_TYPEINFO(QPaintBufferCommand, Q_MOVABLE_TYPE); class QPaintBufferPrivate { public: enum Command { Cmd_Save, Cmd_Restore, Cmd_SetBrush, Cmd_SetBrushOrigin, Cmd_SetClipEnabled, Cmd_SetCompositionMode, Cmd_SetOpacity, Cmd_SetPen, Cmd_SetRenderHints, Cmd_SetTransform, Cmd_SetBackgroundMode, Cmd_ClipPath, Cmd_ClipRect, Cmd_ClipRegion, Cmd_ClipVectorPath, Cmd_DrawVectorPath, Cmd_FillVectorPath, Cmd_StrokeVectorPath, Cmd_DrawConvexPolygonF, Cmd_DrawConvexPolygonI, Cmd_DrawEllipseF, Cmd_DrawEllipseI, Cmd_DrawLineF, Cmd_DrawLineI, Cmd_DrawPath, Cmd_DrawPointsF, Cmd_DrawPointsI, Cmd_DrawPolygonF, Cmd_DrawPolygonI, Cmd_DrawPolylineF, Cmd_DrawPolylineI, Cmd_DrawRectF, Cmd_DrawRectI, Cmd_FillRectBrush, Cmd_FillRectColor, Cmd_DrawText, Cmd_DrawTextItem, Cmd_DrawImagePos, Cmd_DrawImageRect, Cmd_DrawPixmapPos, Cmd_DrawPixmapRect, Cmd_DrawTiledPixmap, Cmd_SystemStateChanged, Cmd_Translate, Cmd_DrawStaticText, // new commands must be added above this line Cmd_LastCommand }; QPaintBufferPrivate(); ~QPaintBufferPrivate(); int addData(const int *data, int count) { if (count <= 0) return 0; int pos = ints.size(); ints.resize(pos + count); memcpy(ints.data() + pos, data, count * sizeof(int)); return pos; } int addData(const qreal *data, int count) { if (count <= 0) return 0; int pos = floats.size(); floats.resize(pos + count); memcpy(floats.data() + pos, data, count * sizeof(qreal)); return pos; } int addData(const QVariant &var) { variants << var; return variants.size() - 1; } QPaintBufferCommand *addCommand(Command command) { QPaintBufferCommand cmd; cmd.id = command; cmd.size = cmd.offset = cmd.offset2 = cmd.extra = 0; commands << cmd; return &commands.last(); } QPaintBufferCommand *addCommand(Command command, const QVariant &var) { QPaintBufferCommand cmd; cmd.id = command; cmd.offset = addData(var); cmd.size = cmd.offset2 = cmd.extra = 0; commands << cmd; return &commands.last(); } QPaintBufferCommand *addCommand(Command command, const QVectorPath &path) { QPaintBufferCommand cmd; cmd.id = command; cmd.offset = addData(path.points(), path.elementCount() * 2); cmd.offset2 = ints.size(); ints << path.hints(); // The absence of path elements is indicated by setting the highest bit in 'cmd.offset2'. if (path.elements()) addData((const int *) path.elements(), path.elementCount()); else cmd.offset2 |= 0x80000000; cmd.size = path.elementCount(); cmd.extra = 0; commands << cmd; return &commands.last(); } QPaintBufferCommand *addCommand(Command command , const qreal *pts, int arrayLength, int elementCount) { QPaintBufferCommand cmd; cmd.id = command; cmd.offset = addData(pts, arrayLength); cmd.size = elementCount; cmd.offset2 = cmd.extra = 0; commands << cmd; return &commands.last(); } QPaintBufferCommand *addCommand(Command command , const int *pts, int arrayLength, int elementCount) { QPaintBufferCommand cmd; cmd.id = command; cmd.offset = addData(pts, arrayLength); cmd.size = elementCount; cmd.offset2 = cmd.extra = 0; commands << cmd; return &commands.last(); } inline void updateBoundingRect(const QRectF &rect); QAtomicInt ref; QVector ints; QVector floats; QVector variants; QVector commands; QList frames; QPaintBufferEngine *engine; QRectF boundingRect; qreal penWidthAdjustment; uint calculateBoundingRect : 1; void *cache; }; struct QVectorPathCmd { // The absence of path elements is indicated by setting the highest bit in 'cmd.offset2'. QVectorPathCmd(QPaintBufferPrivate *d, const QPaintBufferCommand &cmd) : vectorPath(d->floats.constData() + cmd.offset, cmd.size, cmd.offset2 & 0x80000000 ? 0 : (const QPainterPath::ElementType *) (d->ints.constData() + cmd.offset2 + 1), *(d->ints.constData() + (cmd.offset2 & 0x7fffffff))) {} inline const QVectorPath &operator()() const { return vectorPath; } QVectorPath vectorPath; }; class Q_GUI_EXPORT QPainterReplayer { public: QPainterReplayer() { } virtual ~QPainterReplayer() { } void setupTransform(QPainter *painter); virtual void process(const QPaintBufferCommand &cmd); void processCommands(const QPaintBuffer &buffer, QPainter *painter, int begin, int end); protected: QPaintBufferPrivate *d; QTransform m_world_matrix; QPainter *painter; }; class Q_GUI_EXPORT QPaintEngineExReplayer : public QPainterReplayer { public: QPaintEngineExReplayer() { } virtual void process(const QPaintBufferCommand &cmd); }; class QPaintBufferEnginePrivate; class QPaintBufferEngine : public QPaintEngineEx { Q_DECLARE_PRIVATE(QPaintBufferEngine) public: QPaintBufferEngine(QPaintBufferPrivate *buffer); virtual bool begin(QPaintDevice *device); virtual bool end(); virtual Type type() const { return QPaintEngine::PaintBuffer; } virtual QPainterState *createState(QPainterState *orig) const; virtual void draw(const QVectorPath &path); virtual void fill(const QVectorPath &path, const QBrush &brush); virtual void stroke(const QVectorPath &path, const QPen &pen); virtual void clip(const QVectorPath &path, Qt::ClipOperation op); virtual void clip(const QRect &rect, Qt::ClipOperation op); virtual void clip(const QRegion ®ion, Qt::ClipOperation op); virtual void clip(const QPainterPath &path, Qt::ClipOperation op); virtual void clipEnabledChanged(); virtual void penChanged(); virtual void brushChanged(); virtual void brushOriginChanged(); virtual void opacityChanged(); virtual void compositionModeChanged(); virtual void renderHintsChanged(); virtual void transformChanged(); virtual void backgroundModeChanged(); virtual void fillRect(const QRectF &rect, const QBrush &brush); virtual void fillRect(const QRectF &rect, const QColor &color); virtual void drawRects(const QRect *rects, int rectCount); virtual void drawRects(const QRectF *rects, int rectCount); virtual void drawLines(const QLine *lines, int lineCount); virtual void drawLines(const QLineF *lines, int lineCount); virtual void drawEllipse(const QRectF &r); virtual void drawEllipse(const QRect &r); virtual void drawPath(const QPainterPath &path); virtual void drawPoints(const QPointF *points, int pointCount); virtual void drawPoints(const QPoint *points, int pointCount); virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); virtual void drawPixmap(const QPointF &pos, const QPixmap &pm); virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor); virtual void drawImage(const QPointF &pos, const QImage &image); virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); virtual void drawTextItem(const QPointF &pos, const QTextItem &ti); virtual void drawStaticTextItem(QStaticTextItem *staticTextItem); virtual void setState(QPainterState *s); virtual uint flags() const {return QPaintEngineEx::DoNotEmulate;} QPaintBufferPrivate *buffer; mutable int m_begin_detected : 1; mutable int m_save_detected : 1; mutable int m_stream_raw_text_items : 1; mutable int m_unused : 29; mutable QPainterState *m_created_state; }; QT_END_NAMESPACE #endif // QPAINTBUFFER_P_H gammaray-2.3.0/3rdparty/qt/modeltest.cpp000066400000000000000000000534431255003167400202260ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software 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://www.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 "modeltest.h" #include #include /*! Connect to all of the models signals. Whenever anything happens recheck everything. */ ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject ( parent ), model ( _model ), fetchingMore ( false ) { if (!model) qFatal("%s: model must not be null", Q_FUNC_INFO); connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(runAllTests()) ); connect(model, SIGNAL(layoutChanged()), this, SLOT(runAllTests()) ); connect(model, SIGNAL(modelReset()), this, SLOT(runAllTests()) ); connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(runAllTests()) ); connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(runAllTests()) ); // Special checks for changes connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(layoutAboutToBeChanged()) ); connect(model, SIGNAL(layoutChanged()), this, SLOT(layoutChanged()) ); connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)) ); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)) ); connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)) ); connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)) ); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)) ); connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(headerDataChanged(Qt::Orientation,int,int)) ); runAllTests(); } void ModelTest::runAllTests() { if ( fetchingMore ) return; nonDestructiveBasicTest(); rowCount(); columnCount(); hasIndex(); index(); parent(); data(); } /*! nonDestructiveBasicTest tries to call a number of the basic functions (not all) to make sure the model doesn't outright segfault, testing the functions that makes sense. */ void ModelTest::nonDestructiveBasicTest() { QVERIFY( model->buddy ( QModelIndex() ) == QModelIndex() ); model->canFetchMore ( QModelIndex() ); QVERIFY( model->columnCount ( QModelIndex() ) >= 0 ); QVERIFY( model->data ( QModelIndex() ) == QVariant() ); fetchingMore = true; model->fetchMore ( QModelIndex() ); fetchingMore = false; Qt::ItemFlags flags = model->flags ( QModelIndex() ); QVERIFY( flags == Qt::ItemIsDropEnabled || flags == 0 ); model->hasChildren ( QModelIndex() ); model->hasIndex ( 0, 0 ); model->headerData ( 0, Qt::Horizontal ); model->index ( 0, 0 ); model->itemData ( QModelIndex() ); QVariant cache; model->match ( QModelIndex(), -1, cache ); model->mimeTypes(); QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); QVERIFY( model->rowCount() >= 0 ); QVariant variant; model->setData ( QModelIndex(), variant, -1 ); model->setHeaderData ( -1, Qt::Horizontal, QVariant() ); model->setHeaderData ( 999999, Qt::Horizontal, QVariant() ); QMap roles; model->sibling ( 0, 0, QModelIndex() ); model->span ( QModelIndex() ); model->supportedDropActions(); } /*! Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() Models that are dynamically populated are not as fully tested here. */ void ModelTest::rowCount() { // qDebug() << "rc"; // check top row QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); int rows = model->rowCount ( topIndex ); QVERIFY( rows >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( topIndex ) ); QModelIndex secondLevelIndex = model->index ( 0, 0, topIndex ); if ( secondLevelIndex.isValid() ) { // not the top level // check a row count where parent is valid rows = model->rowCount ( secondLevelIndex ); QVERIFY( rows >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( secondLevelIndex ) ); } // The models rowCount() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() */ void ModelTest::columnCount() { // check top row QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); QVERIFY( model->columnCount ( topIndex ) >= 0 ); // check a column count where parent is valid QModelIndex childIndex = model->index ( 0, 0, topIndex ); if ( childIndex.isValid() ) QVERIFY( model->columnCount ( childIndex ) >= 0 ); // columnCount() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::hasIndex() */ void ModelTest::hasIndex() { // qDebug() << "hi"; // Make sure that invalid values returns an invalid index QVERIFY( !model->hasIndex ( -2, -2 ) ); QVERIFY( !model->hasIndex ( -2, 0 ) ); QVERIFY( !model->hasIndex ( 0, -2 ) ); int rows = model->rowCount(); int columns = model->columnCount(); // check out of bounds QVERIFY( !model->hasIndex ( rows, columns ) ); QVERIFY( !model->hasIndex ( rows + 1, columns + 1 ) ); if ( rows > 0 ) QVERIFY( model->hasIndex ( 0, 0 ) ); // hasIndex() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::index() */ void ModelTest::index() { // qDebug() << "i"; // Make sure that invalid values returns an invalid index QVERIFY( model->index ( -2, -2 ) == QModelIndex() ); QVERIFY( model->index ( -2, 0 ) == QModelIndex() ); QVERIFY( model->index ( 0, -2 ) == QModelIndex() ); int rows = model->rowCount(); int columns = model->columnCount(); if ( rows == 0 ) return; // Catch off by one errors QVERIFY( model->index ( rows, columns ) == QModelIndex() ); QVERIFY( model->index ( 0, 0 ).isValid() ); // Make sure that the same index is *always* returned QModelIndex a = model->index ( 0, 0 ); QModelIndex b = model->index ( 0, 0 ); QVERIFY( a == b ); // index() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::parent() */ void ModelTest::parent() { // qDebug() << "p"; // Make sure the model won't crash and will return an invalid QModelIndex // when asked for the parent of an invalid index. QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); if ( model->rowCount() == 0 ) return; // Column 0 | Column 1 | // QModelIndex() | | // \- topIndex | topIndex1 | // \- childIndex | childIndex1 | // Common error test #1, make sure that a top level index has a parent // that is a invalid QModelIndex. QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); QVERIFY( model->parent ( topIndex ) == QModelIndex() ); // Common error test #2, make sure that a second level index has a parent // that is the first level index. if ( model->rowCount ( topIndex ) > 0 ) { QModelIndex childIndex = model->index ( 0, 0, topIndex ); QVERIFY( model->parent ( childIndex ) == topIndex ); } // Common error test #3, the second column should NOT have the same children // as the first column in a row. // Usually the second column shouldn't have children. QModelIndex topIndex1 = model->index ( 0, 1, QModelIndex() ); if ( model->rowCount ( topIndex1 ) > 0 ) { QModelIndex childIndex = model->index ( 0, 0, topIndex ); QModelIndex childIndex1 = model->index ( 0, 0, topIndex1 ); QVERIFY( childIndex != childIndex1 ); } // Full test, walk n levels deep through the model making sure that all // parent's children correctly specify their parent. checkChildren ( QModelIndex() ); } /*! Called from the parent() test. A model that returns an index of parent X should also return X when asking for the parent of the index. This recursive function does pretty extensive testing on the whole model in an effort to catch edge cases. This function assumes that rowCount(), columnCount() and index() already work. If they have a bug it will point it out, but the above tests should have already found the basic bugs because it is easier to figure out the problem in those tests then this one. */ void ModelTest::checkChildren ( const QModelIndex &parent, int currentDepth ) { // First just try walking back up the tree. QModelIndex p = parent; while ( p.isValid() ) p = p.parent(); // For models that are dynamically populated if ( model->canFetchMore ( parent ) ) { fetchingMore = true; model->fetchMore ( parent ); fetchingMore = false; } int rows = model->rowCount ( parent ); int columns = model->columnCount ( parent ); if ( rows > 0 ) QVERIFY( model->hasChildren ( parent ) ); // Some further testing against rows(), columns(), and hasChildren() QVERIFY( rows >= 0 ); QVERIFY( columns >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( parent ) ); //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows // << "columns:" << columns << "parent column:" << parent.column(); const QModelIndex topLeftChild = model->index( 0, 0, parent ); QVERIFY( !model->hasIndex ( rows + 1, 0, parent ) ); for ( int r = 0; r < rows; ++r ) { if ( model->canFetchMore ( parent ) ) { fetchingMore = true; model->fetchMore ( parent ); fetchingMore = false; } QVERIFY( !model->hasIndex ( r, columns + 1, parent ) ); for ( int c = 0; c < columns; ++c ) { QVERIFY( model->hasIndex ( r, c, parent ) ); QModelIndex index = model->index ( r, c, parent ); // rowCount() and columnCount() said that it existed... QVERIFY( index.isValid() ); // index() should always return the same index when called twice in a row QModelIndex modifiedIndex = model->index ( r, c, parent ); QVERIFY( index == modifiedIndex ); // Make sure we get the same index if we request it twice in a row QModelIndex a = model->index ( r, c, parent ); QModelIndex b = model->index ( r, c, parent ); QVERIFY( a == b ); { const QModelIndex sibling = model->sibling( r, c, topLeftChild ); QVERIFY( index == sibling ); } { const QModelIndex sibling = topLeftChild.sibling( r, c ); QVERIFY( index == sibling ); } // Some basic checking on the index that is returned QVERIFY( index.model() == model ); QCOMPARE( index.row(), r ); QCOMPARE( index.column(), c ); // While you can technically return a QVariant usually this is a sign // of a bug in data(). Disable if this really is ok in your model. // QVERIFY( model->data ( index, Qt::DisplayRole ).isValid() ); // If the next test fails here is some somewhat useful debug you play with. if (model->parent(index) != parent) { qDebug() << r << c << currentDepth << model->data(index).toString() << model->data(parent).toString(); qDebug() << index << parent << model->parent(index); // And a view that you can even use to show the model. // QTreeView view; // view.setModel(model); // view.show(); } // Check that we can get back our real parent. QCOMPARE( model->parent ( index ), parent ); // recursively go down the children if ( model->hasChildren ( index ) && currentDepth < 10 ) { //qDebug() << r << c << "has children" << model->rowCount(index); checkChildren ( index, ++currentDepth ); }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ // make sure that after testing the children that the index doesn't change. QModelIndex newerIndex = model->index ( r, c, parent ); QVERIFY( index == newerIndex ); } } } /*! Tests model's implementation of QAbstractItemModel::data() */ void ModelTest::data() { // Invalid index should return an invalid qvariant QVERIFY( !model->data ( QModelIndex() ).isValid() ); if ( model->rowCount() == 0 ) return; // A valid index should have a valid QVariant data QVERIFY( model->index ( 0, 0 ).isValid() ); // shouldn't be able to set data on an invalid index QVERIFY( !model->setData ( QModelIndex(), QLatin1String ( "foo" ), Qt::DisplayRole ) ); // General Purpose roles that should return a QString QVariant variant = model->data ( model->index ( 0, 0 ), Qt::ToolTipRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } variant = model->data ( model->index ( 0, 0 ), Qt::StatusTipRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } variant = model->data ( model->index ( 0, 0 ), Qt::WhatsThisRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } // General Purpose roles that should return a QSize variant = model->data ( model->index ( 0, 0 ), Qt::SizeHintRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } // General Purpose roles that should return a QFont QVariant fontVariant = model->data ( model->index ( 0, 0 ), Qt::FontRole ); if ( fontVariant.isValid() ) { QVERIFY( fontVariant.canConvert() ); } // Check that the alignment is one we know about QVariant textAlignmentVariant = model->data ( model->index ( 0, 0 ), Qt::TextAlignmentRole ); if ( textAlignmentVariant.isValid() ) { int alignment = textAlignmentVariant.toInt(); QCOMPARE( alignment, ( alignment & ( Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask ) ) ); } // General Purpose roles that should return a QColor QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundColorRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } colorVariant = model->data ( model->index ( 0, 0 ), Qt::TextColorRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } // Check that the "check state" is one we know about. QVariant checkStateVariant = model->data ( model->index ( 0, 0 ), Qt::CheckStateRole ); if ( checkStateVariant.isValid() ) { int state = checkStateVariant.toInt(); QVERIFY( state == Qt::Unchecked || state == Qt::PartiallyChecked || state == Qt::Checked ); } } /*! Store what is about to be inserted to make sure it actually happens \sa rowsInserted() */ void ModelTest::rowsAboutToBeInserted ( const QModelIndex &parent, int start, int /* end */) { // Q_UNUSED(end); // qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString() // << "current count of parent=" << model->rowCount ( parent ); // << "display of last=" << model->data( model->index(start-1, 0, parent) ); // qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) ); Changing c; c.parent = parent; c.oldSize = model->rowCount ( parent ); c.last = model->data ( model->index ( start - 1, 0, parent ) ); c.next = model->data ( model->index ( start, 0, parent ) ); insert.push ( c ); } /*! Confirm that what was said was going to happen actually did \sa rowsAboutToBeInserted() */ void ModelTest::rowsInserted ( const QModelIndex & parent, int start, int end ) { Changing c = insert.pop(); QVERIFY( c.parent == parent ); // qDebug() << "rowsInserted" << "start=" << start << "end=" << end << "oldsize=" << c.oldSize // << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent ); // for (int ii=start; ii <= end; ii++) // { // qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent )); // } // qDebug(); QVERIFY( c.oldSize + ( end - start + 1 ) == model->rowCount ( parent ) ); QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); if (c.next != model->data(model->index(end + 1, 0, c.parent))) { qDebug() << start << end; for (int i=0; i < model->rowCount(); ++i) qDebug() << model->index(i, 0).data().toString(); qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); } QVERIFY( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) ); } void ModelTest::layoutAboutToBeChanged() { for ( int i = 0; i < qBound ( 0, model->rowCount(), 100 ); ++i ) changing.append ( QPersistentModelIndex ( model->index ( i, 0 ) ) ); } void ModelTest::layoutChanged() { for ( int i = 0; i < changing.count(); ++i ) { QPersistentModelIndex p = changing[i]; QVERIFY( p == model->index ( p.row(), p.column(), p.parent() ) ); } changing.clear(); } /*! Store what is about to be inserted to make sure it actually happens \sa rowsRemoved() */ void ModelTest::rowsAboutToBeRemoved ( const QModelIndex &parent, int start, int end ) { qDebug() << "ratbr" << parent << start << end; Changing c; c.parent = parent; c.oldSize = model->rowCount ( parent ); c.last = model->data ( model->index ( start - 1, 0, parent ) ); c.next = model->data ( model->index ( end + 1, 0, parent ) ); remove.push ( c ); } /*! Confirm that what was said was going to happen actually did \sa rowsAboutToBeRemoved() */ void ModelTest::rowsRemoved ( const QModelIndex & parent, int start, int end ) { qDebug() << "rr" << parent << start << end; Changing c = remove.pop(); QVERIFY( c.parent == parent ); QVERIFY( c.oldSize - ( end - start + 1 ) == model->rowCount ( parent ) ); QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); QVERIFY( c.next == model->data ( model->index ( start, 0, c.parent ) ) ); } void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { QVERIFY(topLeft.isValid()); QVERIFY(bottomRight.isValid()); QModelIndex commonParent = bottomRight.parent(); QVERIFY(topLeft.parent() == commonParent); QVERIFY(topLeft.row() <= bottomRight.row()); QVERIFY(topLeft.column() <= bottomRight.column()); int rowCount = model->rowCount(commonParent); int columnCount = model->columnCount(commonParent); QVERIFY(bottomRight.row() < rowCount); QVERIFY(bottomRight.column() < columnCount); } void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end) { QVERIFY(start >= 0); QVERIFY(end >= 0); QVERIFY(start <= end); int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount(); QVERIFY(start < itemCount); QVERIFY(end < itemCount); } gammaray-2.3.0/3rdparty/qt/modeltest.h000066400000000000000000000055061255003167400176700ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software 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://www.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$ ** ****************************************************************************/ #ifndef MODELTEST_H #define MODELTEST_H #include #include #include class ModelTest : public QObject { Q_OBJECT public: ModelTest( QAbstractItemModel *model, QObject *parent = 0 ); private Q_SLOTS: void nonDestructiveBasicTest(); void rowCount(); void columnCount(); void hasIndex(); void index(); void parent(); void data(); protected Q_SLOTS: void runAllTests(); void layoutAboutToBeChanged(); void layoutChanged(); void rowsAboutToBeInserted( const QModelIndex &parent, int start, int end ); void rowsInserted( const QModelIndex & parent, int start, int end ); void rowsAboutToBeRemoved( const QModelIndex &parent, int start, int end ); void rowsRemoved( const QModelIndex & parent, int start, int end ); void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void headerDataChanged(Qt::Orientation orientation, int start, int end); private: void checkChildren( const QModelIndex &parent, int currentDepth = 0 ); QAbstractItemModel *model; struct Changing { QModelIndex parent; int oldSize; QVariant last; QVariant next; }; QStack insert; QStack remove; bool fetchingMore; QList changing; }; #endif gammaray-2.3.0/3rdparty/qt/resourcemodel.cpp000066400000000000000000001154241255003167400210740ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** 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 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "resourcemodel.h" #include #include #include #include #include #include #include #include #include #include #include /*! \enum ResourceModel::Roles \value FilePathRole \value FileNameRole */ QT_BEGIN_NAMESPACE class ResourceModelPrivate { Q_DECLARE_PUBLIC(ResourceModel) ResourceModel * const q_ptr; public: struct QDirNode { QDirNode() : parent(0), populated(false), stat(false) {} ~QDirNode() { children.clear(); } QDirNode *parent; QFileInfo info; mutable QVector children; mutable bool populated; // have we read the children mutable bool stat; }; ResourceModelPrivate(ResourceModel *qq) : q_ptr(qq), resolveSymlinks(true), readOnly(true), lazyChildCount(false), allowAppendChild(true), shouldStat(true) // ### This is set to false by QFileDialog { } bool indexValid(const QModelIndex &index) const { return index.isValid(); } void init(); QDirNode *node(int row, QDirNode *parent) const; QVector children(QDirNode *parent, bool stat) const; void _q_refresh(); void savePersistentIndexes(); void restorePersistentIndexes(); QFileInfoList entryInfoList(const QString &path) const; QStringList entryList(const QString &path) const; QString name(const QModelIndex &index) const; QString size(const QModelIndex &index) const; QString type(const QModelIndex &index) const; QString time(const QModelIndex &index) const; void appendChild(ResourceModelPrivate::QDirNode *parent, const QString &path) const; static QFileInfo resolvedInfo(QFileInfo info); inline QDirNode *node(const QModelIndex &index) const; inline void populate(QDirNode *parent) const; inline void clear(QDirNode *parent) const; void invalidate(); mutable QDirNode root; bool resolveSymlinks; bool readOnly; bool lazyChildCount; bool allowAppendChild; QDir::Filters filters; QDir::SortFlags sort; QStringList nameFilters; struct SavedPersistent { QString path; int column; QPersistentModelIndexData *data; QPersistentModelIndex index; }; QList savedPersistent; QPersistentModelIndex toBeRefreshed; bool shouldStat; // use the "carefull not to stat directories" mode }; void qt_setDirModelShouldNotStat(ResourceModelPrivate *modelPrivate) { modelPrivate->shouldStat = false; } ResourceModelPrivate::QDirNode *ResourceModelPrivate::node(const QModelIndex &index) const { ResourceModelPrivate::QDirNode *n = static_cast(index.internalPointer()); Q_ASSERT(n); return n; } void ResourceModelPrivate::populate(QDirNode *parent) const { Q_ASSERT(parent); parent->children = children(parent, parent->stat); parent->populated = true; } void ResourceModelPrivate::clear(QDirNode *parent) const { Q_ASSERT(parent); parent->children.clear(); parent->populated = false; } void ResourceModelPrivate::invalidate() { QStack nodes; nodes.push(&root); while (!nodes.empty()) { const QDirNode *current = nodes.pop(); current->stat = false; const QVector children = current->children; for (int i = 0; i < children.count(); ++i) nodes.push(&children.at(i)); } } /*! \class ResourceModel \obsolete \brief The ResourceModel class provides a data model for the local filesystem. \ingroup model-view The usage of ResourceModel is not recommended anymore. The QFileSystemModel class is a more performant alternative. This class provides access to the local filesystem, providing functions for renaming and removing files and directories, and for creating new directories. In the simplest case, it can be used with a suitable display widget as part of a browser or filer. ResourceModel keeps a cache with file information. The cache needs to be updated with refresh(). ResourceModel can be accessed using the standard interface provided by QAbstractItemModel, but it also provides some convenience functions that are specific to a directory model. The fileInfo() and isDir() functions provide information about the underlying files and directories related to items in the model. Directories can be created and removed using mkdir(), rmdir(), and the model will be automatically updated to take the changes into account. \note ResourceModel requires an instance of a GUI application. \sa nameFilters(), setFilter(), filter(), QListView, QTreeView, QFileSystemModel, {Dir View Example}, {Model Classes} */ /*! Constructs a new directory model with the given \a parent. Only those files matching the \a nameFilters and the \a filters are included in the model. The sort order is given by the \a sort flags. */ ResourceModel::ResourceModel(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort, QObject *parent) : QAbstractItemModel(parent), d_ptr(new ResourceModelPrivate(this)) { Q_D(ResourceModel); // we always start with QDir::drives() d->nameFilters = nameFilters.isEmpty() ? QStringList(QLatin1String("*")) : nameFilters; d->filters = filters; d->sort = sort; d->root.parent = 0; d->root.info = QFileInfo(); d->clear(&d->root); } /*! Constructs a directory model with the given \a parent. */ ResourceModel::ResourceModel(QObject *parent) : QAbstractItemModel(parent), d_ptr(new ResourceModelPrivate(this)) { Q_D(ResourceModel); d->init(); } /*! Destroys this directory model. */ ResourceModel::~ResourceModel() { } /*! Returns the model item index for the item in the \a parent with the given \a row and \a column. */ QModelIndex ResourceModel::index(int row, int column, const QModelIndex &parent) const { Q_D(const ResourceModel); // note that rowCount does lazy population if (column < 0 || column >= columnCount(parent) || row < 0 || parent.column() > 0) return QModelIndex(); // make sure the list of children is up to date ResourceModelPrivate::QDirNode *p = (d->indexValid(parent) ? d->node(parent) : &d->root); Q_ASSERT(p); if (!p->populated) d->populate(p); // populate without stat'ing if (row >= p->children.count()) return QModelIndex(); // now get the internal pointer for the index ResourceModelPrivate::QDirNode *n = d->node(row, d->indexValid(parent) ? p : 0); Q_ASSERT(n); return createIndex(row, column, n); } /*! Return the parent of the given \a child model item. */ QModelIndex ResourceModel::parent(const QModelIndex &child) const { Q_D(const ResourceModel); if (!d->indexValid(child)) return QModelIndex(); ResourceModelPrivate::QDirNode *node = d->node(child); ResourceModelPrivate::QDirNode *par = (node ? node->parent : 0); if (par == 0) // parent is the root node return QModelIndex(); // get the parent's row const QVector children = par->parent ? par->parent->children : d->root.children; Q_ASSERT(children.count() > 0); int row = (par - &(children.at(0))); Q_ASSERT(row >= 0); return createIndex(row, 0, par); } /*! Returns the number of rows in the \a parent model item. */ int ResourceModel::rowCount(const QModelIndex &parent) const { Q_D(const ResourceModel); if (parent.column() > 0) return 0; if (!parent.isValid()) { // qDebug() << "Root" << d->root; if (!d->root.populated) // lazy population d->populate(&d->root); return d->root.children.count(); } if (parent.model() != this) return 0; ResourceModelPrivate::QDirNode *p = d->node(parent); if (p->info.isDir() && !p->populated) // lazy population d->populate(p); return p->children.count(); } /*! Returns the number of columns in the \a parent model item. */ int ResourceModel::columnCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; return 4; } /*! Returns the data for the model item \a index with the given \a role. */ QVariant ResourceModel::data(const QModelIndex &index, int role) const { Q_D(const ResourceModel); if (!d->indexValid(index)) return QVariant(); if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.column()) { case 0: return d->name(index); case 1: return d->size(index); case 2: return d->type(index); case 3: return d->time(index); default: qWarning("data: invalid display value column %d", index.column()); return QVariant(); } } if (index.column() == 0) { if (role == FilePathRole) return filePath(index); if (role == FileNameRole) return fileName(index); } if (index.column() == 1 && Qt::TextAlignmentRole == role) { return Qt::AlignRight; } return QVariant(); } /*! Sets the data for the model item \a index with the given \a role to the data referenced by the \a value. Returns true if successful; otherwise returns false. \sa Qt::ItemDataRole */ bool ResourceModel::setData(const QModelIndex &index, const QVariant &value, int role) { Q_D(ResourceModel); if (!d->indexValid(index) || index.column() != 0 || (flags(index) & Qt::ItemIsEditable) == 0 || role != Qt::EditRole) return false; ResourceModelPrivate::QDirNode *node = d->node(index); QDir dir = node->info.dir(); QString name = value.toString(); if (dir.rename(node->info.fileName(), name)) { node->info = QFileInfo(dir, name); QModelIndex sibling = index.sibling(index.row(), 3); emit dataChanged(index, sibling); d->toBeRefreshed = index.parent(); QMetaObject::invokeMethod(this, "_q_refresh", Qt::QueuedConnection); return true; } return false; } /*! Returns the data stored under the given \a role for the specified \a section of the header with the given \a orientation. */ QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role != Qt::DisplayRole) return QVariant(); switch (section) { case 0: return tr("Name"); case 1: return tr("Size"); case 2: return #ifdef Q_OS_MAC tr("Kind", "Match OS X Finder"); #else tr("Type", "All other platforms"); #endif // Windows - Type // OS X - Kind // Konqueror - File Type // Nautilus - Type case 3: return tr("Date Modified"); default: return QVariant(); } } return QAbstractItemModel::headerData(section, orientation, role); } QMap ResourceModel::itemData(const QModelIndex &index) const { QMap map = QAbstractItemModel::itemData(index); map.insert(ResourceModel::FilePathRole, data(index, ResourceModel::FilePathRole)); map.insert(ResourceModel::FileNameRole, data(index, ResourceModel::FileNameRole)); return map; } /*! Returns true if the \a parent model item has children; otherwise returns false. */ bool ResourceModel::hasChildren(const QModelIndex &parent) const { Q_D(const ResourceModel); if (parent.column() > 0) return false; if (!parent.isValid()) // the invalid index is the "My Computer" item return true; // the drives ResourceModelPrivate::QDirNode *p = d->node(parent); Q_ASSERT(p); if (d->lazyChildCount) // optimization that only checks for children if the node has been populated return p->info.isDir(); return p->info.isDir() && rowCount(parent) > 0; } /*! Returns the item flags for the given \a index in the model. \sa Qt::ItemFlags */ Qt::ItemFlags ResourceModel::flags(const QModelIndex &index) const { Q_D(const ResourceModel); Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (!d->indexValid(index)) return flags; flags |= Qt::ItemIsDragEnabled; if (d->readOnly) return flags; ResourceModelPrivate::QDirNode *node = d->node(index); if ((index.column() == 0) && node->info.isWritable()) { flags |= Qt::ItemIsEditable; if (fileInfo(index).isDir()) // is directory and is editable flags |= Qt::ItemIsDropEnabled; } return flags; } /*! Sort the model items in the \a column using the \a order given. The order is a value defined in \l Qt::SortOrder. */ void ResourceModel::sort(int column, Qt::SortOrder order) { QDir::SortFlags sort = QDir::DirsFirst | QDir::IgnoreCase; if (order == Qt::DescendingOrder) sort |= QDir::Reversed; switch (column) { case 0: sort |= QDir::Name; break; case 1: sort |= QDir::Size; break; case 2: sort |= QDir::Type; break; case 3: sort |= QDir::Time; break; default: break; } setSorting(sort); } /*! Returns a list of MIME types that can be used to describe a list of items in the model. */ QStringList ResourceModel::mimeTypes() const { return QStringList(QLatin1String("text/uri-list")); } /*! Returns an object that contains a serialized description of the specified \a indexes. The format used to describe the items corresponding to the indexes is obtained from the mimeTypes() function. If the list of indexes is empty, 0 is returned rather than a serialized empty list. */ QMimeData *ResourceModel::mimeData(const QModelIndexList &indexes) const { QList urls; QList::const_iterator it = indexes.begin(); for (; it != indexes.end(); ++it) if ((*it).column() == 0) urls << QUrl::fromLocalFile(filePath(*it)); QMimeData *data = new QMimeData(); data->setUrls(urls); return data; } /*! Handles the \a data supplied by a drag and drop operation that ended with the given \a action over the row in the model specified by the \a row and \a column and by the \a parent index. \sa supportedDropActions() */ bool ResourceModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int /* row */, int /* column */, const QModelIndex &parent) { Q_D(ResourceModel); if (!d->indexValid(parent) || isReadOnly()) return false; bool success = true; QString to = filePath(parent) + QDir::separator(); QModelIndex _parent = parent; QList urls = data->urls(); QList::const_iterator it = urls.constBegin(); switch (action) { case Qt::CopyAction: for (; it != urls.constEnd(); ++it) { QString path = (*it).toLocalFile(); success = QFile::copy(path, to + QFileInfo(path).fileName()) && success; } break; case Qt::LinkAction: for (; it != urls.constEnd(); ++it) { QString path = (*it).toLocalFile(); success = QFile::link(path, to + QFileInfo(path).fileName()) && success; } break; case Qt::MoveAction: for (; it != urls.constEnd(); ++it) { QString path = (*it).toLocalFile(); if (QFile::copy(path, to + QFileInfo(path).fileName()) && QFile::remove(path)) { QModelIndex idx=index(QFileInfo(path).path()); if (idx.isValid()) { refresh(idx); //the previous call to refresh may invalidate the _parent. so recreate a new QModelIndex _parent = index(to); } } else { success = false; } } break; default: return false; } if (success) refresh(_parent); return success; } /*! Returns the drop actions supported by this model. \sa Qt::DropActions */ Qt::DropActions ResourceModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; // FIXME: LinkAction is not supported yet } /*! Sets the name \a filters for the directory model. */ void ResourceModel::setNameFilters(const QStringList &filters) { Q_D(ResourceModel); d->nameFilters = filters; emit layoutAboutToBeChanged(); if (d->shouldStat) refresh(QModelIndex()); else d->invalidate(); emit layoutChanged(); } /*! Returns a list of filters applied to the names in the model. */ QStringList ResourceModel::nameFilters() const { Q_D(const ResourceModel); return d->nameFilters; } /*! Sets the directory model's filter to that specified by \a filters. Note that the filter you set should always include the QDir::AllDirs enum value, otherwise ResourceModel won't be able to read the directory structure. \sa QDir::Filters */ void ResourceModel::setFilter(QDir::Filters filters) { Q_D(ResourceModel); d->filters = filters; emit layoutAboutToBeChanged(); if (d->shouldStat) refresh(QModelIndex()); else d->invalidate(); emit layoutChanged(); } /*! Returns the filter specification for the directory model. \sa QDir::Filters */ QDir::Filters ResourceModel::filter() const { Q_D(const ResourceModel); return d->filters; } /*! Sets the directory model's sorting order to that specified by \a sort. \sa QDir::SortFlags */ void ResourceModel::setSorting(QDir::SortFlags sort) { Q_D(ResourceModel); d->sort = sort; emit layoutAboutToBeChanged(); if (d->shouldStat) refresh(QModelIndex()); else d->invalidate(); emit layoutChanged(); } /*! Returns the sorting method used for the directory model. \sa QDir::SortFlags */ QDir::SortFlags ResourceModel::sorting() const { Q_D(const ResourceModel); return d->sort; } /*! \property ResourceModel::resolveSymlinks \brief Whether the directory model should resolve symbolic links This is only relevant on operating systems that support symbolic links. */ void ResourceModel::setResolveSymlinks(bool enable) { Q_D(ResourceModel); d->resolveSymlinks = enable; } bool ResourceModel::resolveSymlinks() const { Q_D(const ResourceModel); return d->resolveSymlinks; } /*! \property ResourceModel::readOnly \brief Whether the directory model allows writing to the file system If this property is set to false, the directory model will allow renaming, copying and deleting of files and directories. This property is true by default */ void ResourceModel::setReadOnly(bool enable) { Q_D(ResourceModel); d->readOnly = enable; } bool ResourceModel::isReadOnly() const { Q_D(const ResourceModel); return d->readOnly; } /*! \property ResourceModel::lazyChildCount \brief Whether the directory model optimizes the hasChildren function to only check if the item is a directory. If this property is set to false, the directory model will make sure that a directory actually containes any files before reporting that it has children. Otherwise the directory model will report that an item has children if the item is a directory. This property is false by default */ void ResourceModel::setLazyChildCount(bool enable) { Q_D(ResourceModel); d->lazyChildCount = enable; } bool ResourceModel::lazyChildCount() const { Q_D(const ResourceModel); return d->lazyChildCount; } /*! ResourceModel caches file information. This function updates the cache. The \a parent parameter is the directory from which the model is updated; the default value will update the model from root directory of the file system (the entire model). */ void ResourceModel::refresh(const QModelIndex &parent) { Q_D(ResourceModel); ResourceModelPrivate::QDirNode *n = d->indexValid(parent) ? d->node(parent) : &(d->root); int rows = n->children.count(); if (rows == 0) { emit layoutAboutToBeChanged(); n->stat = true; // make sure that next time we read all the info n->populated = false; emit layoutChanged(); return; } beginResetModel(); // emit layoutAboutToBeChanged(); d->savePersistentIndexes(); // d->rowsAboutToBeRemoved(parent, 0, rows - 1); n->stat = true; // make sure that next time we read all the info d->clear(n); // d->rowsRemoved(parent, 0, rows - 1); d->restorePersistentIndexes(); // emit layoutChanged(); endResetModel(); } /*! \overload Returns the model item index for the given \a path. */ QModelIndex ResourceModel::index(const QString &path, int column) const { Q_D(const ResourceModel); if (path.isEmpty() || path == QCoreApplication::translate("QFileDialog", "My Computer")) return QModelIndex(); QString absolutePath = QDir(path).absolutePath(); #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) absolutePath = absolutePath.toLower(); #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) // On Windows, "filename......." and "filename" are equivalent if (absolutePath.endsWith(QLatin1Char('.'))) { int i; for (i = absolutePath.count() - 1; i >= 0; --i) { if (absolutePath.at(i) != QLatin1Char('.')) break; } absolutePath = absolutePath.left(i+1); } #endif QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts); if ((pathElements.isEmpty() || !QFileInfo(path).exists()) #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) && path != QLatin1String("/") #endif ) return QModelIndex(); QModelIndex idx; // start with "My Computer" if (!d->root.populated) // make sure the root is populated d->populate(&d->root); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path QString host = pathElements.first(); int r = 0; for (; r < d->root.children.count(); ++r) if (d->root.children.at(r).info.fileName() == host) break; bool childAppended = false; if (r >= d->root.children.count() && d->allowAppendChild) { d->appendChild(&d->root, QLatin1String("//") + host); childAppended = true; } idx = index(r, 0, QModelIndex()); pathElements.pop_front(); if (childAppended) emit const_cast(this)->layoutChanged(); } else #endif #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (pathElements.at(0).endsWith(QLatin1Char(':'))) { pathElements[0] += QLatin1Char('/'); } #else // add the "/" item, since it is a valid path element on unix pathElements.prepend(QLatin1String("/")); #endif for (int i = 0; i < pathElements.count(); ++i) { Q_ASSERT(!pathElements.at(i).isEmpty()); QString element = pathElements.at(i); ResourceModelPrivate::QDirNode *parent = (idx.isValid() ? d->node(idx) : &d->root); Q_ASSERT(parent); if (!parent->populated) d->populate(parent); // search for the element in the child nodes first int row = -1; for (int j = parent->children.count() - 1; j >= 0; --j) { const QFileInfo& fi = parent->children.at(j).info; QString childFileName; childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) childFileName = childFileName.toLower(); #endif if (childFileName == element) { if (i == pathElements.count() - 1) parent->children[j].stat = true; row = j; break; } } // we couldn't find the path element, we create a new node since we _know_ that the path is valid if (row == -1) { #if defined(Q_OS_WINCE) QString newPath; if (parent->info.isRoot()) newPath = parent->info.absoluteFilePath() + element; else newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #else QString newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #endif if (!d->allowAppendChild || !QFileInfo(newPath).isDir()) return QModelIndex(); d->appendChild(parent, newPath); row = parent->children.count() - 1; if (i == pathElements.count() - 1) // always stat children of the last element parent->children[row].stat = true; emit const_cast(this)->layoutChanged(); } Q_ASSERT(row >= 0); idx = createIndex(row, 0, static_cast(&parent->children[row])); Q_ASSERT(idx.isValid()); } if (column != 0) return idx.sibling(idx.row(), column); return idx; } /*! Returns true if the model item \a index represents a directory; otherwise returns false. */ bool ResourceModel::isDir(const QModelIndex &index) const { Q_D(const ResourceModel); Q_ASSERT(d->indexValid(index)); ResourceModelPrivate::QDirNode *node = d->node(index); return node->info.isDir(); } /*! Create a directory with the \a name in the \a parent model item. */ QModelIndex ResourceModel::mkdir(const QModelIndex &parent, const QString &name) { Q_D(ResourceModel); if (!d->indexValid(parent) || isReadOnly()) return QModelIndex(); ResourceModelPrivate::QDirNode *p = d->node(parent); QString path = p->info.absoluteFilePath(); // For the indexOf() method to work, the new directory has to be a direct child of // the parent directory. QDir newDir(name); QDir dir(path); if (newDir.isRelative()) newDir = QDir(path + QLatin1Char('/') + name); QString childName = newDir.dirName(); // Get the singular name of the directory newDir.cdUp(); if (newDir.absolutePath() != dir.absolutePath() || !dir.mkdir(name)) return QModelIndex(); // nothing happened refresh(parent); QStringList entryList = d->entryList(path); int r = entryList.indexOf(childName); QModelIndex i = index(r, 0, parent); // return an invalid index return i; } /*! Removes the directory corresponding to the model item \a index in the directory model and \bold{deletes the corresponding directory from the file system}, returning true if successful. If the directory cannot be removed, false is returned. \warning This function deletes directories from the file system; it does \bold{not} move them to a location where they can be recovered. \sa remove() */ bool ResourceModel::rmdir(const QModelIndex &index) { Q_D(ResourceModel); if (!d->indexValid(index) || isReadOnly()) return false; ResourceModelPrivate::QDirNode *n = d_func()->node(index); if (!n->info.isDir()) { qWarning("rmdir: the node is not a directory"); return false; } QModelIndex par = parent(index); ResourceModelPrivate::QDirNode *p = d_func()->node(par); QDir dir = p->info.dir(); // parent dir QString path = n->info.absoluteFilePath(); if (!dir.rmdir(path)) return false; refresh(par); return true; } /*! Removes the model item \a index from the directory model and \bold{deletes the corresponding file from the file system}, returning true if successful. If the item cannot be removed, false is returned. \warning This function deletes files from the file system; it does \bold{not} move them to a location where they can be recovered. \sa rmdir() */ bool ResourceModel::remove(const QModelIndex &index) { Q_D(ResourceModel); if (!d->indexValid(index) || isReadOnly()) return false; ResourceModelPrivate::QDirNode *n = d_func()->node(index); if (n->info.isDir()) return false; QModelIndex par = parent(index); ResourceModelPrivate::QDirNode *p = d_func()->node(par); QDir dir = p->info.dir(); // parent dir QString path = n->info.absoluteFilePath(); if (!dir.remove(path)) return false; refresh(par); return true; } /*! Returns the path of the item stored in the model under the \a index given. */ QString ResourceModel::filePath(const QModelIndex &index) const { Q_D(const ResourceModel); if (d->indexValid(index)) { QFileInfo fi = fileInfo(index); if (d->resolveSymlinks && fi.isSymLink()) fi = d->resolvedInfo(fi); return QDir::cleanPath(fi.absoluteFilePath()); } return QString(); // root path } /*! Returns the name of the item stored in the model under the \a index given. */ QString ResourceModel::fileName(const QModelIndex &index) const { Q_D(const ResourceModel); if (!d->indexValid(index)) return QString(); QFileInfo info = fileInfo(index); if (info.isRoot()) return info.absoluteFilePath(); if (d->resolveSymlinks && info.isSymLink()) info = d->resolvedInfo(info); return info.fileName(); } /*! Returns the file information for the specified model \a index. \bold{Note:} If the model index represents a symbolic link in the underlying filing system, the file information returned will contain information about the symbolic link itself, regardless of whether resolveSymlinks is enabled or not. \sa QFileInfo::symLinkTarget() */ QFileInfo ResourceModel::fileInfo(const QModelIndex &index) const { Q_D(const ResourceModel); Q_ASSERT(d->indexValid(index)); ResourceModelPrivate::QDirNode *node = d->node(index); return node->info; } /*! \fn QObject *ResourceModel::parent() const \internal */ /* The root node is never seen outside the model. */ void ResourceModelPrivate::init() { Q_Q(ResourceModel); filters = QDir::AllEntries | QDir::NoDotAndDotDot; sort = QDir::Name; nameFilters << QLatin1String("*"); root.parent = 0; root.info = QFileInfo(":"); clear(&root); QHash roles = q->roleNames(); roles.insert(ResourceModel::FilePathRole, "filePath"); roles.insert(ResourceModel::FileNameRole, "fileName"); q->setRoleNames(roles); } ResourceModelPrivate::QDirNode *ResourceModelPrivate::node(int row, QDirNode *parent) const { if (row < 0) return 0; bool isDir = !parent || parent->info.isDir(); QDirNode *p = (parent ? parent : &root); if (isDir && !p->populated) populate(p); // will also resolve symlinks if (row >= p->children.count()) { qWarning("node: the row does not exist"); return 0; } return const_cast(&p->children.at(row)); } QVector ResourceModelPrivate::children(QDirNode *parent, bool stat) const { Q_ASSERT(parent); QFileInfoList infoList; if (parent == &root) { parent = 0; infoList.append(root.info); } else if (parent->info.isDir()) { //resolve directory links only if requested. if (parent->info.isSymLink() && resolveSymlinks) { QString link = parent->info.symLinkTarget(); if (link.size() > 1 && link.at(link.size() - 1) == QDir::separator()) link.chop(1); if (stat) infoList = entryInfoList(link); else infoList = QDir(link).entryInfoList(nameFilters, QDir::AllEntries | QDir::System); } else { if (stat) infoList = entryInfoList(parent->info.absoluteFilePath()); else infoList = QDir(parent->info.absoluteFilePath()).entryInfoList(nameFilters, QDir::AllEntries | QDir::System); } } QVector nodes(infoList.count()); for (int i = 0; i < infoList.count(); ++i) { QDirNode &node = nodes[i]; node.parent = parent; node.info = infoList.at(i); node.populated = false; node.stat = shouldStat; } return nodes; } void ResourceModelPrivate::_q_refresh() { Q_Q(ResourceModel); q->refresh(toBeRefreshed); toBeRefreshed = QModelIndex(); } void ResourceModelPrivate::savePersistentIndexes() { // Q_Q(ResourceModel); savedPersistent.clear(); // foreach (QPersistentModelIndexData *data, q->persistentIndexes()) { // SavedPersistent saved; // QModelIndex index = data->index; // saved.path = q->filePath(index); // saved.column = index.column(); // saved.data = data; // saved.index = index; // savedPersistent.append(saved); // } } void ResourceModelPrivate::restorePersistentIndexes() { // Q_Q(ResourceModel); // bool allow = allowAppendChild; // allowAppendChild = false; // for (int i = 0; i < savedPersistent.count(); ++i) { // QPersistentModelIndexData *data = savedPersistent.at(i).data; // QString path = savedPersistent.at(i).path; // int column = savedPersistent.at(i).column; // QModelIndex idx = q->index(path, column); // if (idx != data->index || data->model == 0) { // //data->model may be equal to 0 if the model is getting destroyed // persistent.indexes.remove(data->index); // data->index = idx; // data->model = q; // if (idx.isValid()) // persistent.indexes.insert(idx, data); // } // } savedPersistent.clear(); // allowAppendChild = allow; } QFileInfoList ResourceModelPrivate::entryInfoList(const QString &path) const { const QDir dir(path); return dir.entryInfoList(nameFilters, filters, sort); } QStringList ResourceModelPrivate::entryList(const QString &path) const { const QDir dir(path); return dir.entryList(nameFilters, filters, sort); } QString ResourceModelPrivate::name(const QModelIndex &index) const { const QDirNode *n = node(index); const QFileInfo info = n->info; if (info.isRoot()) { QString name = info.absoluteFilePath(); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (name.startsWith(QLatin1Char('/'))) // UNC host return info.fileName(); #endif #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (name.endsWith(QLatin1Char('/'))) name.chop(1); #endif return name; } return info.fileName(); } QString ResourceModelPrivate::size(const QModelIndex &index) const { const QDirNode *n = node(index); if (n->info.isDir()) { #ifdef Q_OS_MAC return QLatin1String("--"); #else return QLatin1String(""); #endif // Windows - "" // OS X - "--" // Konqueror - "4 KB" // Nautilus - "9 items" (the number of children) } // According to the Si standard KB is 1000 bytes, KiB is 1024 // but on windows sizes are calulated by dividing by 1024 so we do what they do. const quint64 kb = 1024; const quint64 mb = 1024 * kb; const quint64 gb = 1024 * mb; const quint64 tb = 1024 * gb; quint64 bytes = n->info.size(); if (bytes >= tb) return QObject::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3)); if (bytes >= gb) return QObject::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2)); if (bytes >= mb) return QObject::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1)); if (bytes >= kb) return QObject::tr("%1 KB").arg(QLocale().toString(bytes / kb)); return QObject::tr("%1 byte(s)").arg(QLocale().toString(bytes)); } QString ResourceModelPrivate::type(const QModelIndex &index) const { // poor interpolation of what QFileIconProvider::type() did // TODO: for Qt5 QMimeType might actually be a better choice here if (!index.parent().isValid()) return QObject::tr("Root"); if (node(index)->info.isDir()) return QObject::tr("Folder"); return QObject::tr("%1 File").arg(node(index)->info.suffix()); } QString ResourceModelPrivate::time(const QModelIndex &index) const { #ifndef QT_NO_DATESTRING return node(index)->info.lastModified().toString(Qt::LocalDate); #else Q_UNUSED(index); return QString(); #endif } void ResourceModelPrivate::appendChild(ResourceModelPrivate::QDirNode *parent, const QString &path) const { ResourceModelPrivate::QDirNode node; node.populated = false; node.stat = shouldStat; node.parent = (parent == &root ? 0 : parent); node.info = QFileInfo(path); node.info.setCaching(true); // The following append(node) may reallocate the vector, thus // we need to update the pointers to the childnodes parent. ResourceModelPrivate *that = const_cast(this); that->savePersistentIndexes(); parent->children.append(node); for (int i = 0; i < parent->children.count(); ++i) { QDirNode *childNode = &parent->children[i]; for (int j = 0; j < childNode->children.count(); ++j) childNode->children[j].parent = childNode; } that->restorePersistentIndexes(); } QFileInfo ResourceModelPrivate::resolvedInfo(QFileInfo info) { #ifdef Q_OS_WIN // On windows, we cannot create a shortcut to a shortcut. return QFileInfo(info.symLinkTarget()); #else QStringList paths; do { QFileInfo link(info.symLinkTarget()); if (link.isRelative()) info.setFile(info.absolutePath(), link.filePath()); else info = link; if (paths.contains(info.absoluteFilePath())) return QFileInfo(); paths.append(info.absoluteFilePath()); } while (info.isSymLink()); return info; #endif } QT_END_NAMESPACE #include "moc_resourcemodel.cpp" gammaray-2.3.0/3rdparty/qt/resourcemodel.h000066400000000000000000000115461255003167400205410ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** 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 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef RESOURCEMODELMODEL_H #define RESOURCEMODELMODEL_H #include #include QT_BEGIN_NAMESPACE QT_MODULE(Gui) class ResourceModelPrivate; class ResourceModel : public QAbstractItemModel { Q_OBJECT Q_PROPERTY(bool resolveSymlinks READ resolveSymlinks WRITE setResolveSymlinks) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(bool lazyChildCount READ lazyChildCount WRITE setLazyChildCount) public: enum Roles { // Qt4 uses 32, Qt5 256, for Qt::UserRole - use the latter globaly to allow combining Qt4/5 client/servers. FilePathRole = 256 + 1, FileNameRole }; ResourceModel(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort, QObject *parent = 0); explicit ResourceModel(QObject *parent = 0); ~ResourceModel(); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(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; QMap itemData(const QModelIndex &index) const; bool hasChildren(const QModelIndex &index = QModelIndex()) const; Qt::ItemFlags flags(const QModelIndex &index) const; void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); QStringList mimeTypes() const; QMimeData *mimeData(const QModelIndexList &indexes) const; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); Qt::DropActions supportedDropActions() const; // ResourceModel specific API void setNameFilters(const QStringList &filters); QStringList nameFilters() const; void setFilter(QDir::Filters filters); QDir::Filters filter() const; void setSorting(QDir::SortFlags sort); QDir::SortFlags sorting() const; void setResolveSymlinks(bool enable); bool resolveSymlinks() const; void setReadOnly(bool enable); bool isReadOnly() const; void setLazyChildCount(bool enable); bool lazyChildCount() const; QModelIndex index(const QString &path, int column = 0) const; bool isDir(const QModelIndex &index) const; QModelIndex mkdir(const QModelIndex &parent, const QString &name); bool rmdir(const QModelIndex &index); bool remove(const QModelIndex &index); QString filePath(const QModelIndex &index) const; QString fileName(const QModelIndex &index) const; QFileInfo fileInfo(const QModelIndex &index) const; #ifdef Q_NO_USING_KEYWORD inline QObject *parent() const { return QObject::parent(); } #else using QObject::parent; #endif public Q_SLOTS: void refresh(const QModelIndex &parent = QModelIndex()); protected: ResourceModel(ResourceModelPrivate &, QObject *parent = 0); friend class QFileDialogPrivate; private: Q_DECLARE_PRIVATE(ResourceModel) ResourceModelPrivate * const d_ptr; Q_DISABLE_COPY(ResourceModel) Q_PRIVATE_SLOT(d_func(), void _q_refresh()) }; QT_END_NAMESPACE #endif // QDIRMODEL_H gammaray-2.3.0/CHANGES000066400000000000000000000156021255003167400143140ustar00rootroot00000000000000Release Highlights ================== Version 2.3.0: -------------- * Add QtBluetooth support. * Support local sockets next to TCP for connecting to the probe. * Change probe plugin loading to be compatible with Android .apk restrictions. * Don't generate backtraces for GammaRay-caused qWarnings. * Also show properties defined in a meta object in the meta object browser. * Add non-QObject meta object found via QMetaType to the meta object browser (finds Q_GADGETs with Qt 5.5). * Performance improvements in object tracking, remote model, property view, signal spy and several other places. * Ongoing refactoring work to enable embedding the GammaRay client and launcher components into other host applications. * Add copy backtrace feature in the message browser. * Improved UI-less build option for embedded targets. * Fix various crashes, including when interacting with QOpenGLContext, QDBusAdapter, QML ListModels or Qt containers containing types that cannot be serialized. * Make paint analyzing also work with Qt 5.5 despite the necessary functionality being removed in Qt. * Add support for static properties in the property view. * Qt 5.5 compatibility. * Initial support for QNX 6.6. * Improved QtQuick2 in-app item picking. * Fixed/improved tracking of object reparenting in the object tree model. * Fix widget layout overlay widget leaking into object/widget tree. * Optional compression support for the client/server communication, speeds up debugging over slow USB connections. * Fix initial selection in the model browser having no effect. Version 2.2.1: ------------- * Fix spawning a large number of threads in the process list. * Add GAMMARAY_BUILD_UI build option to only build the non-UI parts, useful for embedded targets. * Add workaround for QSortFilterProxyModel regression introduced in qtbase commit bec1854cc0. * Follow kdstatemachineeditor KDSME API changes. * Use the preload injector by default on Mac for Qt >= 5.4. * Fix probe ABI detection on Mac bundles. * Fix asserts caused by icon loading in QCoreApplication-only targets. * Fix crash when target deletes a signal sender in a slot. Version 2.2.0: ------------- * New translation inspector plug-in. * New signal monitor and object lifetime plotter plug-in. * Support displaying of QQmlListProperty contents. * Expose signal/slot spy callback API to plug-ins. * Improved state machine visualization using KDSME. * Support for QQmlTimer in the timertop plug-in. * Support exporting of QResource data. * Improved QSGMaterial viewer. * Various performance improvements for the QtQuick2 remote preview. * Improved Qt 5.4 compatibility. * Fix handling of large images in the resource browser. * Support for manually emitting signals, and improved method display. Version 2.1.2: ------------- * Fix crash when selecting the scene graph root node. * Fix two asserts in Qt 5.4 when dealing with connections to slot objects. * Fix build with Vivante OpenGL ES2 stack. * Build fixes for Android. * Fix build issues with Qt5.4 and Clang. * Fix minor compiler warnings and Coverity Scan issues. Version 2.1.1: ------------- * Fix invoking non-slot methods with arguments. * Fix QtQuick2 preview not showing any content with Qt 5.2 or older. * Fix crash when encountering tooltips in Qt5 targets. * Fix deadlock in object list model. * Fix QGraphicsView scene selection in in-process mode. * Fix debug message handler for Qt5. * A missing relocatable startup hook is no longer fatal with Qt 5.4. * Fix Qt 5.4 compatibility of the QtQuick2 preview. Version 2.1.0: ------------- * Aggregated property view combining static, dynamic and non-QObject property views. * Qt5Qml/Qt5Quick support (see http://github.com/KDAB/GammaRay/wiki/QtQuick2-Support-Status) * Probe ABI auto-detection on Linux, Mac and Windows. * Support to navigate to objects that are property values. * Plug-ins can now add specialized tabs to the property view. * Support adding and deleting dynamic QObject properties. * Support for "hidden" plug-ins, i.e. plug-ins that only provide type support but no own tool view. * Support KF5 in the KJob tracker plug-in. * Support for Qt 5.4 object creation/destruction callbacks. * Improved connection view, and support for viewing connections in Qt5 applications. Version 2.0.2: ------------- * Restore compatibility with Qt4.7 * Avoid leaking shared-memory in case of crashes of gammaray-client * Fix various crashes * Fix various crashes with heavily multithreaded debuggees * Fix unnecessary value limits in property editor for QPointF, QSizeF, etc * Improve property editor value loading performance Version 2.0.1: ------------- * LLDB injector (enables Mac OSX 10.9 support) * Fix various cases where client and server states get out of sync Version 2.0.0: ------------- * Out-of-process UI * Remote Debugging * Multi-probe support * Probe usable on targets without QtWidget available * Fix preload check on MIPS/MIPSel (issue #63) * Support for displaying arguments of monitored signals Version 1.3.2: ------------- * Support more Qt5-specific data types * Fix crash on some QtQuick2 applications * Support VTK6 * Fix compilation with Mac OSX 10.6 * Fix GDB injector on Mac OSX * Fix launching of bundles on Mac OSX * Fix crash in selection model inspector * Add fallback if function overwriting fails in MSVC release builds * Fix WinDLL injector with Qt5 * Fix Qt version detection in the process list on Windows and Mac OSX * Fix probe re-injections * Fix plugin loading on MSVC release builds Version 1.3.1: ------------- * Fix state machine viewer on Windows * Fix crash in model cell viewer * Fix crash in meta object browser caused by deleted dynamic meta objects * Improve performance of the mime type browser * Improvements in the state machine viewer image export * Compile fixes for some Qt5 configurations Version 1.3: ----------- * New KJob tracker plugin (requires KDE4) * Qt5 support * New Meta Object Browser tool * New QStandardPaths and QMimeTypeDatabase browsers (Qt5 only) Version 1.2: ----------- * Published API for writing your own plugin * New QStyle inspector * New QAction inspector with shortcut conflict finder * New QPalette editor * QWidget paint operation introspection using QPaintBuffer (requires private headers) Version 1.1: ----------- * Plug-in system for tools * Graphical state machine viewer * Object hierarchy visualization plug-in * New timer profiler plug-in * New locale inspector plug-in * New property view/editor for non-QObject types (e.g. QGraphicsItem and many of its sub-classes) * New widget export actions (image, PDF, SVG, Designer UI file) * New launcher UI with support for starting new processes, self-testing, and a much faster process list on Mac OSX * Support more types in the property editor * Improved widget tree model * Fix unreliable attaching with MSVC * MingW support Version 1.0: ----------- * Initial Release gammaray-2.3.0/CMakeLists.txt000066400000000000000000000545731255003167400160730ustar00rootroot00000000000000# This is the top-level CMakeLists.txt file for the GammaRay project. # # Pass the following variables to cmake to control the build: # (See Install.txt for more information) # # -DGAMMARAY_ENFORCE_QT4_BUILD=[true|false] # Force building against Qt4, even if Qt5 is found. # Default=false # # -DGAMMARAY_BUILD_UI=[true|false] # Build the client and in-process UI. # Default=true # # -DGAMMARAY_PROBE_ONLY_BUILD=[true|false] # Build only an additional probe configuration for an already existing launcher. # Default=false # # -DGAMMARAY_UNKNOWN_CXX_MANGLED_NAMES=[true|false] # Enable if your compiler uses an unsupported C++ name mangling scheme. # Default=false # # To build the man page from POD, run 'make man' after CMake (assumes perl is available) # To install the resulting man page, run 'make install' # Not available on Windows. # # To build the apidox, run 'make docs' after CMake (assumes doxygen is available) # project(GammaRay) cmake_minimum_required(VERSION 2.8.12) # b/c of ECMGeneratePriFile.cmake cmake_policy(SET CMP0020 NEW) if(POLICY CMP0043) cmake_policy(SET CMP0043 NEW) endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ ${CMAKE_MODULE_PATH}) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set(CMAKE_MACOSX_RPATH TRUE) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) endif() include(CheckCXXCompilerFlag) include(CheckIncludeFiles) include(CheckLibraryExists) include(GammaRayMacros) include(GammaRayMacrosInternal) include(FeatureSummary) include(ECMGeneratePriFile) # Exit for blacklisted compilers (those that don't support C++11 very well) # MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) # Clang 3.0 set(BAD_CXX_MESSAGE "") if(MSVC) if(MSVC_VERSION LESS 1500) set(BAD_CXX_MESSAGE "MSVC 2008 or higher") endif() endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if(${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.1.0) set(BAD_CXX_MESSAGE "Clang v3.1.0 or higher") endif() endif() if(BAD_CXX_MESSAGE) message(FATAL_ERROR "\nSorry, ${BAD_CXX_MESSAGE} is required to build this software. Please retry using a modern compiler that supports C++11 lambdas.") endif() # Enable the test harness enable_testing() # Version setup set(GAMMARAY_VERSION_MAJOR "2") set(GAMMARAY_VERSION_MINOR "3") set(GAMMARAY_VERSION_PATCH "0") set(GAMMARAY_VERSION "${GAMMARAY_VERSION_MAJOR}.${GAMMARAY_VERSION_MINOR}.${GAMMARAY_VERSION_PATCH}") set(GAMMARAY_VERSION_STRING "${GAMMARAY_VERSION}") set(GAMMARAY_SOVERSION "2.3.0") set(GAMMARAY_PLUGIN_VERSION "2.3") set(PROJECT_VERSION_STRING "${GAMMARAY_VERSION_STRING}") if(ANDROID) # non-rooted Android doesn't like .so versions... set(GAMMARAY_DEFAULT_LIBRARY_PROPERTIES "") else() set(GAMMARAY_DEFAULT_LIBRARY_PROPERTIES SOVERSION ${GAMMARAY_SOVERSION} VERSION ${GAMMARAY_SOVERSION}) endif() if(EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git) set_package_properties(Git PROPERTIES TYPE OPTIONAL PURPOSE "Determine exact build version.") if(GIT_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE _git_revision ) string(REGEX REPLACE "\n" "" _git_revision "${_git_revision}") set(GAMMARAY_VERSION_STRING "${GAMMARAY_VERSION_STRING} (revision: ${_git_revision})") endif() endif() configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config-gammaray-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gammaray-version.h ) message(STATUS "Building GammaRay ${GAMMARAY_VERSION_STRING} in ${CMAKE_BUILD_TYPE} mode") # # Build options # option( GAMMARAY_ENFORCE_QT4_BUILD "Enable if you want to enforce a build with Qt4" OFF ) option( GAMMARAY_BUILD_UI "Build the GammaRay client and in-process UI." ON ) option( GAMMARAY_PROBE_ONLY_BUILD "Build only an additional probe configuration for an already existing launcher." OFF ) # TODO: find a nicer way for all this. ideally auto-detect the name mangling # format, but at least guess a default based on OS + compiler. option( GAMMARAY_UNKNOWN_CXX_MANGLED_NAMES "Enable if your compiler uses an unsupported C++ name mangling scheme" OFF ) # # Compiler & linker settings # if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") check_cxx_compiler_flag(-Wunused-but-set-variable HAVE_GXX_UNUSED_BUT_SET) check_cxx_compiler_flag(-Wlogical-op HAVE_GXX_LOGICAL_OP) check_cxx_compiler_flag(-Wsizeof-pointer-memaccess HAVE_GXX_POINTER_MEMACCESS) check_cxx_compiler_flag(-Wreorder HAVE_GXX_REORDER) check_cxx_compiler_flag(-Wformat-security HAVE_GXX_FORMAT_SECURITY) check_cxx_compiler_flag(-std=gnu++0x HAVE_GXX_GNUXX11) check_cxx_compiler_flag(-std=c++0x HAVE_GXX_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wextra -Woverloaded-virtual -Winit-self -Wmissing-include-dirs -Wunused -Wno-div-by-zero -Wundef -Wpointer-arith -Wmissing-noreturn -Werror=return-type") if(HAVE_GXX_GNUXX11) # QNX needs gnu++0x rather than c++0x for compiling QML V4 private headers set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") elseif(HAVE_GXX_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") endif() if(HAVE_GXX_UNUSED_BUT_SET) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-but-set-variable") endif() if(HAVE_GXX_LOGICAL_OP) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wlogical-op") endif() if(HAVE_GXX_POINTER_MEMACCESS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsizeof-pointer-memaccess") endif() if(HAVE_GXX_REORDER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wreorder") endif() if(HAVE_GXX_FORMAT_SECURITY) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security") endif() if(MINGW) # mingw will error out on the crazy casts in probe.cpp without this set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") else() # visibility attributes not supported on mingw, don't use -fvisibility option # see: http://stackoverflow.com/questions/7994415/mingw-fvisibility-hidden-does-not-seem-to-work set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") endif() endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments") endif() if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments") endif() if(WIN32) add_definitions(-DUNICODE -D_UNICODE) endif() if(QNXNTO) add_definitions(-D_QNX_SOURCE) endif() # linker flags if(CMAKE_SYSTEM_NAME MATCHES Linux OR CMAKE_SYSTEM_NAME STREQUAL GNU) if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_MODULE_LINKER_FLAGS}") endif() endif() # # Finding Qt # # try Qt5 first, and prefer that (if found), but only if not disabled via option if(NOT GAMMARAY_ENFORCE_QT4_BUILD) find_package(Qt5Core 5.1 QUIET) else() set(Qt5Core_FOUND FALSE) endif() if(Qt5Core_FOUND) set_package_properties(Qt5Core PROPERTIES TYPE REQUIRED) find_package(Qt5 NO_MODULE REQUIRED COMPONENTS Gui Network) find_package(Qt5 NO_MODULE QUIET OPTIONAL_COMPONENTS Bluetooth Concurrent Designer PrintSupport Qml Quick Svg Script ScriptTools Test WebKitWidgets Widgets ) if(GAMMARAY_BUILD_UI) # widgets are required for the UI find_package(Qt5 NO_MODULE REQUIRED COMPONENTS Widgets) endif() #HACK: CMake with broken Qt5Qml_PRIVATE_INCLUDE_DIRS, Qt5Quick_PRIVATE_INCLUDE_DIRS if(${Qt5Qml_FOUND}) if(NOT "${Qt5Qml_PRIVATE_INCLUDE_DIRS}" MATCHES "/QtQml/") string(REPLACE "/QtCore" "/QtQml" replaceme "${Qt5Core_PRIVATE_INCLUDE_DIRS}") list(APPEND Qt5Qml_PRIVATE_INCLUDE_DIRS ${replaceme}) list(REMOVE_DUPLICATES Qt5Qml_PRIVATE_INCLUDE_DIRS) endif() endif() if(${Qt5Quick_FOUND}) if(NOT "${Qt5Quick_PRIVATE_INCLUDE_DIRS}" MATCHES "/QtQuick/") string(REPLACE "/QtCore" "/QtQuick" replaceme "${Qt5Core_PRIVATE_INCLUDE_DIRS}") list(APPEND Qt5Quick_PRIVATE_INCLUDE_DIRS ${Qt5Qml_PRIVATE_INCLUDE_DIRS}) list(APPEND Qt5Quick_PRIVATE_INCLUDE_DIRS ${replaceme}) list(REMOVE_DUPLICATES Qt5Quick_PRIVATE_INCLUDE_DIRS) endif() endif() include("cmake/ECMQt4To5Porting.cmake") set(HAVE_QT_CONCURRENT ${Qt5Concurrent_FOUND}) set(HAVE_QT_WIDGETS ${Qt5Widgets_FOUND}) set(HAVE_QT_SVG ${Qt5Svg_FOUND}) set(HAVE_QT_DESIGNER ${Qt5Designer_FOUND}) set(HAVE_QT_PRINTSUPPORT ${Qt5PrintSupport_FOUND}) set(HAVE_QT_WEBKIT1 ${Qt5WebKitWidgets_FOUND}) if(Qt5_POSITION_INDEPENDENT_CODE AND NOT WIN32) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() # TODO: Remove me once fixed in ECM module # more hacks: find qpa/... includes # also see https://codereview.qt-project.org/#change,30483 include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) # TODO warnings rather than build errors for the deprecated methods would be nice... add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0) find_path(QT_PRIVATE_INCLUDE_DIR private/qobject_p.h PATHS ${Qt5Core_PRIVATE_INCLUDE_DIRS}) if(QT_PRIVATE_INCLUDE_DIR) set(HAVE_PRIVATE_QT_HEADERS true) endif() find_path(_Qt5Quick_PRIVATE_INCLUDE_DIR private/qquickitem_p.h PATHS ${Qt5Quick_PRIVATE_INCLUDE_DIRS}) if(_Qt5Quick_PRIVATE_INCLUDE_DIR) set(HAVE_PRIVATE_Qt5Quick_HEADERS true) endif() set_package_properties(Qt5 PROPERTIES URL "http://qt-project.org/") set_package_properties(Qt5Concurrent PROPERTIES TYPE RECOMMENDED PURPOSE "Required for the GammaRay launcher process list.") set_package_properties(Qt5Widget PROPERTIES TYPE RECOMMENDED PURPOSE "Required for the GammaRay client UI and widget-related tools.") set_package_properties(Qt5Svg PROPERTIES TYPE OPTIONAL PURPOSE "Required for widget SVG export.") set_package_properties(Qt5PrintSupport PROPERTIES TYPE OPTIONAL PURPOSE "Required for widget PDF export.") add_feature_info("QPainter analyzer" HAVE_PRIVATE_QT_HEADERS "Requires private Qt headers to be available.") # Qt4 else() set(QT_USE_IMPORTED_TARGETS true) find_package(Qt4 4.8.0 REQUIRED QtCore QtGui QtNetwork) find_package(Qt4 4.8.0 QUIET COMPONENTS QtScript QtScriptTools QtWebKit QtDesigner QtSvg QtTest) include(${QT_USE_FILE}) set(HAVE_QT_CONCURRENT true) set(HAVE_QT_WIDGETS true) set(HAVE_QT_SVG true) if(QT_QTDESIGNER_FOUND) set(HAVE_QT_DESIGNER true) endif() set(HAVE_QT_PRINTSUPPORT true) set(HAVE_QT_WEBKIT1 ${QT_QTWEBKIT_FOUND}) find_path(QT_PRIVATE_INCLUDE_DIR private/qobject_p.h PATHS ${QT_INCLUDES}) if(QT_PRIVATE_INCLUDE_DIR) # not enough, some of them include harfbuzz headers, so we need to find those as well # for now we assume a regular Qt4 source build layout, but that probably should be generalized find_path(HARFBUZZ_INCLUDE_DIR harfbuzz.h PATH ${QT_PRIVATE_INCLUDE_DIR}/../../src/3rdparty/harfbuzz/src) endif() if(QT_PRIVATE_INCLUDE_DIR AND HARFBUZZ_INCLUDE_DIR) set(HAVE_PRIVATE_QT_HEADERS TRUE) include_directories(${HARFBUZZ_INCLUDE_DIR}) else() set(HAVE_PRIVATE_QT_HEADERS FALSE) # needs to go before Qt includes, in case we have non-working headers with the same name there include_directories(BEFORE ${CMAKE_SOURCE_DIR}/3rdparty/qt/4.8) endif() set_package_properties(Qt4 PROPERTIES URL "http://qt-project.org/") add_feature_info("QPainter analyzer" HAVE_PRIVATE_QT_HEADERS "You must have a build version of Qt available. Make sure the qmake found first in your execute comes from this build version." ) # C++11 compatibility with Qt5 add_definitions(-DQ_DECL_OVERRIDE=) endif() add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) # disable QT_STRICT_ITERATORS on the Qt5+Windows combo # see: https://bugreports.qt-project.org/browse/QTBUG-29608 if(NOT (Qt5Core_FOUND AND WIN32)) add_definitions(-DQT_STRICT_ITERATORS) endif() if(CMAKE_BUILD_TYPE MATCHES "^[Rr]elease$") add_definitions(-DQT_NO_DEBUG_OUTPUT) endif() add_feature_info("QtScript debugger" QT_QTSCRIPTTOOLS_FOUND "Requires QtScript and QtScriptTools.") add_feature_info("Web inspector" HAVE_QT_WEBKIT1 "Requires QtWebKit.") add_feature_info("Widget .ui file export" HAVE_QT_DESIGNER "Requires QtDesigner library.") # # Additional dependencies # if(Qt5Core_FOUND AND Qt5Core_VERSION VERSION_LESS 5.2.2) # https://codereview.qt-project.org/75530 message(STATUS "Disabling timer profiler plug-in due to a bug in Qt5 <= 5.2.1.") set(BUILD_TIMER_PLUGIN FALSE) else() if(WIN32 OR APPLE) set(BUILD_TIMER_PLUGIN TRUE) else() check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME) gammaray_add_dummy_package(rt HAVE_CLOCK_GETTIME) set_package_properties(rt PROPERTIES TYPE RECOMMENDED DESCRIPTION "High resolution clock, part of glibc" PURPOSE "Needed for the timer profiler plugin." ) set(BUILD_TIMER_PLUGIN ${HAVE_CLOCK_GETTIME}) endif() endif() check_include_files(stdint.h HAVE_STDINT_H) #VTK discovery works a lot better if you give CMake a hint using the VTK_DIR variable find_path(VTK_DIR VTKConfig.cmake /usr/lib64/vtk /usr/lib/vtk /usr/local/lib64/vtk /usr/local/lib/vtk ) find_package(VTK) set_package_properties(VTK PROPERTIES TYPE OPTIONAL DESCRIPTION "Visualization Toolkit" PURPOSE "Needed for the object visualizer plugin." URL "http://www.vtk.org" ) if(VTK_FOUND) find_path(VTK_QT_INCLUDE_DIR NAMES QVTKWidget.h HINTS ${VTK_INCLUDE_DIRS}) if(NOT VTK_QT_INCLUDE_DIR) message(STATUS "Cannot locate QVTKWidget.h in ${VTK_INCLUDE_DIRS}") set(VTK_FOUND FALSE) add_feature_info("QVTKWidget header" VTK_FOUND "Object visualizer plugin requires QVTKWidget.h header.") endif() endif() set(HAVE_VTK ${VTK_FOUND}) # ELF header for ABI detection find_file(ELF_H elf.h PATH_SUFFIXES sys) if(ELF_H) set(HAVE_ELF_H TRUE) endif() add_feature_info("ELF ABI detection" HAVE_ELF_H "Automatic probe ABI detection on ELF-based systems. Requires elf.h.") # # Determine probe ABI # this needs to be run after we know exactly what we are building, but is needed for that installation settings include(GammaRayProbeABI) # # Installation settings # if(APPLE) # Make sure default prefix on mac is /Applications, dunnow why but it does not default to it # probably because we do not enabled built in bundle support in the main project string(COMPARE EQUAL "${CMAKE_INSTALL_PREFIX}" "/usr/local" CMP_RESULT) if(CMP_RESULT) set(CMAKE_INSTALL_PREFIX "/Applications") endif() set(BUNDLE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}") set(BUNDLE_NAME "GammaRay.app") set(BIN_INSTALL_DIR "${BUNDLE_NAME}/Contents/MacOS") set(LIBEXEC_INSTALL_DIR "${BIN_INSTALL_DIR}") set(LIB_INSTALL_DIR "${BUNDLE_NAME}/Contents/Frameworks") set(PLUGIN_INSTALL_DIR "${BUNDLE_NAME}/Contents/PlugIns") set(RESOURCES_INSTALL_DIR "${BUNDLE_NAME}/Contents/Resources") set(DOC_INSTALL_DIR "${RESOURCES_INSTALL_DIR}/docs") set(CMAKECONFIG_INSTALL_DIR "${RESOURCES_INSTALL_DIR}/cmake/GammaRay") set(INCLUDE_INSTALL_DIR "${RESOURCES_INSTALL_DIR}/include/gammaray") set(MAN_INSTALL_DIR "${RESOURCES_INSTALL_DIR}/man/man1") else() set(BIN_INSTALL_DIR "bin") set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") set(INCLUDE_INSTALL_DIR "include/gammaray") set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/GammaRay) set(DATAROOTDIR share CACHE PATH "Define install directory for read-only architecture-independent data") set(XDG_APPS_INSTALL_DIR "${DATAROOTDIR}/applications") set(APPDATA_INSTALL_DIR "${DATAROOTDIR}/appdata") set(ICON_INSTALL_DIR "${DATAROOTDIR}/icons") set(MAN_INSTALL_DIR "${DATAROOTDIR}/man/man1") if(WIN32) set(PLUGIN_INSTALL_DIR "plugins") set(LIBEXEC_INSTALL_DIR "${BIN_INSTALL_DIR}") set(DOC_INSTALL_DIR .) else() set(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/gammaray") set(LIBEXEC_INSTALL_DIR "${LIB_INSTALL_DIR}/gammaray/libexec") set(DOC_INSTALL_DIR "${DATAROOTDIR}/doc/gammaray/") endif() endif() if(ANDROID) # Android doesn't support sub-directories in lib/ set(PROBE_PLUGIN_INSTALL_DIR "plugins/gammaray") else() set(PROBE_PLUGIN_INSTALL_DIR "${PLUGIN_INSTALL_DIR}/${GAMMARAY_PLUGIN_VERSION}/${GAMMARAY_PROBE_ABI}") endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${LIB_INSTALL_DIR}) # set RPATH only when installing to a non-default location list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}" _isSystemPlatformLibDir) list(FIND CMAKE_C_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}" _isSystemCLibDir) list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}" _isSystemCxxLibDir) if(${_isSystemPlatformLibDir} EQUAL -1 AND ${_isSystemCLibDir} EQUAL -1 AND ${_isSystemCxxLibDir} EQUAL -1) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}") endif() set( INSTALL_TARGETS_DEFAULT_ARGS RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT Devel BUNDLE DESTINATION ${BUNDLE_INSTALL_DIR} ) # "inverse" install dirs, to find the base location again gammaray_inverse_dir(GAMMARAY_INVERSE_BIN_DIR "${BIN_INSTALL_DIR}") gammaray_inverse_dir(GAMMARAY_INVERSE_PROBE_DIR "${PROBE_PLUGIN_INSTALL_DIR}") gammaray_inverse_dir(GAMMARAY_INVERSE_LIBEXEC_DIR "${LIBEXEC_INSTALL_DIR}") # # actually build the stuff # configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config-gammaray.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gammaray.h ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/3rdparty ${CMAKE_BINARY_DIR} ) add_subdirectory(cmake) add_subdirectory(common) add_subdirectory(core) add_subdirectory(hooking) add_subdirectory(launcher) if(GAMMARAY_BUILD_UI AND (Qt5Widgets_FOUND OR QT_QTGUI_FOUND)) add_subdirectory(ui) add_subdirectory(inprocessui) if(NOT GAMMARAY_PROBE_ONLY_BUILD) add_subdirectory(client) add_subdirectory(app) endif() endif() if((Qt5Test_FOUND OR QT_QTTEST_FOUND) AND NOT CMAKE_CROSSCOMPILING) add_subdirectory(tests) endif() add_subdirectory(plugins) add_subdirectory(resources) add_subdirectory(docs) # needs to go last, so see all installed headers for the API docs set(LICENSE_FILE "LICENSE.GPL.txt") set(README_FILE "ReadMe.txt") list(APPEND DOCS ${LICENSE_FILE} ${README_FILE} "LICENSE.txt" "LICENSE.US.txt" "ReadMe-commercial.txt") if(NOT APPLE AND NOT GAMMARAY_PROBE_ONLY_BUILD) if(UNIX AND GAMMARAY_BUILD_UI) install(FILES GammaRay.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES GammaRay.appdata.xml DESTINATION ${APPDATA_INSTALL_DIR}) endif() install(FILES ${DOCS} DESTINATION ${DOC_INSTALL_DIR}) endif() # # cppcheck # find_program(CPPCHECK_EXECUTABLE cppcheck) if(CPPCHECK_EXECUTABLE) set(_cppcheck_flags "-I${CMAKE_CURRENT_BINARY_DIR}") get_directory_property(_inc_dirs INCLUDE_DIRECTORIES) foreach(_current ${_inc_dirs}) set(_cppcheck_flags ${_cppcheck_flags} "-I${_current}") endforeach() get_directory_property(_defs COMPILE_DEFINITIONS) foreach(_current ${_defs}) set(_cppcheck_flags ${_cppcheck_flags} "-D${_current}") endforeach() add_custom_target(cppcheck COMMAND ${CPPCHECK_EXECUTABLE} --enable=all --inconclusive -f --suppress=*:${QT_INCLUDE_DIR}* ${_cppcheck_flags} -i${CMAKE_CURRENT_SOURCE_DIR}/3rdparty -i${CMAKE_CURRENT_SOURCE_DIR}/tests ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Running the cppcheck static code checker" ) endif() # # CMake package config file generation # include(CMakePackageConfigHelpers) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/GammaRayConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/GammaRayConfig.cmake INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/GammaRayConfigVersion.cmake VERSION ${GAMMARAY_VERSION} COMPATIBILITY SameMajorVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/GammaRayConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/GammaRayConfigVersion.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install( EXPORT GammaRayTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE GammaRayTarget.cmake # NAMESPACE GammaRay:: ) #CPACK: General Settings set(CPACK_GENERATOR "TBZ2") set(CPACK_PACKAGE_NAME "gammaray") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An introspection tool for Qt applications") #TODO: shorten lines in the Readme.txt to make rpmlint happy set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/${README_FILE}") set(CPACK_PACKAGE_VENDOR "Klaralvdalens Datakonsult AB (KDAB)") set(CPACK_PACKAGE_CONTACT "gammaray-devel@kdab.com") set(CPACK_PACKAGE_VERSION_MAJOR "${GAMMARAY_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${GAMMARAY_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${GAMMARAY_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${GAMMARAY_VERSION}") #CPACK: RPM Specific Settings set(CPACK_RPM_PACKAGE_LICENSE "GPLv2+") set(CPACK_RPM_PACKAGE_GROUP "Development/Tools") #CPACK: DEB Specific Settings set(CPACK_DEBIAN_PACKAGE_SECTION "Development") set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/${README_FILE}") if(WIN32) set(CPACK_GENERATOR "NSIS" "ZIP") set(CPACK_PACKAGE_EXECUTABLES "GammaRay" "GammaRay") set(CPACK_PACKAGE_INSTALL_DIRECTORY "GammaRay") set(CPACK_PACKAGE_FILE_NAME "GammaRay ${GAMMARAY_VERSION}") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/${LICENSE_FILE}") set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${BIN_INSTALL_DIR}") set(CPACK_NSIS_MUI_ICON "${ICONS_DIR}/Charm.ico") set(CPACK_PACKAGE_ICON "${ICONS_DIR}\\\\CharmNSISHeader.bmp") set(CPACK_NSIS_URL_INFO_ABOUT "http://www.kdab.com/") set(CPACK_NSIS_INSTALLED_ICON_NAME "GammaRay${CMAKE_EXECUTABLE_SUFFIX}") set(CPACK_NSIS_MENU_LINKS "${LICENSE_FILE}" "License" "${README_FILE}" "Readme" ) set(CPACK_NSIS_MUI_FINISHPAGE_RUN "${CPACK_NSIS_INSTALLED_ICON_NAME}") elseif(APPLE) set(CPACK_GENERATOR "DragNDrop") set(CPACK_DMG_FORMAT "UDBZ") set(CPACK_DMG_VOLUME_NAME "GammaRay") set(CPACK_SYSTEM_NAME "OSX") set(CPACK_PACKAGE_FILE_NAME "GammaRay-${GAMMARAY_VERSION}") set(CPACK_PACKAGE_ICON "${ICONS_DIR}/CharmDMG.icns") set(CPACK_DMG_DS_STORE "${ICONS_DIR}/CharmDSStore") set(CPACK_DMG_BACKGROUND_IMAGE "${ICONS_DIR}/CharmDMGBackground.png") elseif(UNIX) set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") endif() include(CPack) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) gammaray-2.3.0/GammaRay.appdata.xml000066400000000000000000000041771255003167400171570ustar00rootroot00000000000000 GammaRay.desktop GFDL-1.3 GPL-2.0+ GammaRay Qt-application inspection and manipulation tool

GammaRay is a tool to poke around in a Qt-application and also to manipulate the application to some extent. GammaRay uses various DLL injection techniques to hook into an application at runtime and provide access to a lot of interesting information.

GammaRay provides the following capabilities to help your Qt application development efforts:

  • Browse the QObject tree with live updates
  • View, and to some extent, edit QObject static and dynamic properties
  • View and call slots of a QObject (similar to qdbusviewer)
  • View other QObject elements such as signals, enums and class info introspectively
  • List all QObject inbound and outbound signal/slot connections
  • Provide live widget preview. Useful for finding layout issues
  • View the content of any QAbstractItemModel (QAIM)
  • Browse the QAbstractProxyModel (QAPM) hierarchy
  • Browse the QGraphicsView (QGV) item tree of any QGV scene
  • ... and much, much more
http://www.kdab.com/wp-content/uploads/stories/software/gammaray2.png http://www.kdab.com/wp-content/uploads/stories/software/gammaray1.png http://www.kdab.com/wp-content/uploads/stories/software/gammaray4_text.png http://www.kdab.com/wp-content/uploads/stories/software/gammaray-traffic-light.png http://www.kdab.com/kdab-products/gammaray/ allen.winter@kdab.com KDAB
gammaray-2.3.0/GammaRay.desktop000066400000000000000000000005371255003167400164130ustar00rootroot00000000000000[Desktop Entry] Name=GammaRay Name[x-test]=xxGammaRayxx Comment=Qt-application inspection and manipulation tool Comment[x-test]=xxQt-application inspection and manipulation toolxx GenericName=Qt Inspection Tool GenericName[x-test]=xxQt Inspection Toolxx Exec=gammaray Icon=GammaRay Type=Application Categories=Qt;Development; X-KDE-StartupNotify=true gammaray-2.3.0/GammaRayConfig.cmake.in000066400000000000000000000014331255003167400175510ustar00rootroot00000000000000@PACKAGE_INIT@ if(@Qt5Core_FOUND@) find_package(Qt5 @Qt5Core_VERSION_MAJOR@.@Qt5Core_VERSION_MINOR@ NO_MODULE REQUIRED COMPONENTS Core Network) find_package(Qt5 @Qt5Core_VERSION_MAJOR@.@Qt5Core_VERSION_MINOR@ NO_MODULE COMPONENTS Widgets) else() find_package(Qt4 @QT_VERSION_MAJOR@.@QT_VERSION_MINOR@) endif() set_and_check(GammaRay_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") list(APPEND GammaRay_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@/..") set(GAMMARAY_PLUGIN_INSTALL_DIR @PLUGIN_INSTALL_DIR@) set(GAMMARAY_PLUGIN_VERSION @GAMMARAY_PLUGIN_VERSION@) set(GAMMARAY_PROBE_ABI @GAMMARAY_PROBE_ABI@) set(GAMMARAY_PROBE_PLUGIN_INSTALL_DIR @PROBE_PLUGIN_INSTALL_DIR@) include("${CMAKE_CURRENT_LIST_DIR}/GammaRayTarget.cmake") include("${CMAKE_CURRENT_LIST_DIR}/GammaRayMacros.cmake") gammaray-2.3.0/Install.txt000066400000000000000000000057311255003167400154720ustar00rootroot00000000000000GammaRay uses the CMake buildsystem. Please see the comments at the top of CMakeLists.txt for the available configuration options you can pass to cmake. The installation directory defaults to /usr/local on UNIX c:/Program Files on Windows and /Applications on MacOS. You can change this location by passing the option -DCMAKE_INSTALL_PREFIX=/install/path to cmake. To build a debug version pass -DCMAKE_BUILD_TYPE=Debug to cmake. To build GammaRay you will need: - CMake 2.8.11 - a C++ compiler with C++11 lambda support - Qt 4.8 or higher Optional FOSS packages (eg. VTK, Graphviz, etc) provide extra functionality. See the "Optional Dependencies" section below for more details. Building on Unix with gcc or clang: % mkdir build % cd build % cmake .. % make % make install Building on Windows with Microsoft Visual Studio: % mkdir build % cd build % cmake -G "NMake Makefiles" .. % nmake % nmake install Building on Windows with mingw: % mkdir build % cd build % cmake -G "MinGW Makefiles" .. % mingw32-make % mingw32-make install == Building with Private Qt Headers == To build against private Qt headers (necessary for painter debugging/profiling) you must have a developer build version of Qt available (i.e. Qt must be configured using the -developer-build option). Make sure the qmake found first in your execute comes from this build version. For example, if your Qt build is in /data/Qt/4.8 then: % export PATH=/data/Qt/4.8/bin:$PATH # on Linux using bash == Force a Qt4 build == On systems with both Qt4 and Qt5 available, the CMake buildsystem will always attempt to use Qt5. To force a Qt build, pass -DGAMMARAY_ENFORCE_QT4_BUILD=true to CMake, as in: % cmake -DGAMMARAY_ENFORCE_QT4_BUILD=true == Optional Dependencies == GammaRay relies on optional (FOSS) dependencies to help provide some of its functionality. For example, you'll need VTK (http://www.vtk.org) to build the object visualizer and Graphviz (http://www.graphviz.org) for the state machine visualizer. When you run cmake it will inform you about these missing dependencies. You can also force CMake to ignore any or all of the optional dependencies by passing the option -DCMAKE_DISABLE_FIND_PACKAGE_=True. For instance: # tell cmake to ignore Graphiz and VTK % cmake -DCMAKE_DISABLE_FIND_PACKAGE_Graphviz=True -DCMAKE_DISABLE_FIND_PACKAGE_VTK=True == Warning! == If your Qt is linked with the "-Bsymbolic-function" option preloading will be broken. When this is enabled, references to global functions will be bound to the shared object internally; therefore, the definition of the function will be fixed and cannot be overwritten by preloading. So, be sure that your distro-provided packages or your self-compiled packages are not linked with this flag (check with `echo $LDFLAGS` before compiling). For more info see: "man ld; search for "-Bsymbolic-function". Known affected distros: Ubuntu 10.10, 11.04 If you are affected by this, try the gdb injector instead by using the "-i gdb" command line argument. gammaray-2.3.0/LICENSE.GPL.txt000066400000000000000000001507531255003167400155740ustar00rootroot00000000000000 The GammaRay software is Copyright (C) 2010-2015 Klaralvdalens Datakonsult AB. You may use, distribute and copy the GammaRay software under the terms of the GNU General Public License version 2 or under the terms of GNU General Public License version 3 both of which are displayed below. ------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ------------------------------------------------------------------------- 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 . ------------------------------------------------------------------------- gammaray-2.3.0/LICENSE.US.txt000066400000000000000000000176021255003167400154740ustar00rootroot00000000000000GammaRay COMMERCIAL LICENSE AGREEMENT FOR COMMERCIAL VERSIONS June 20, 2014 IMPORTANT-READ CAREFULLY: This Klarälvdalens Datakonsult AB End-User License Agreement ("EULA") is a legal agreement between you (either an individual or a legal entity) and Klarälvdalens Datakonsult AB ("KDAB") for the Klarälvdalens Datakonsult AB software product(s) accompanying this EULA, which include(s) computer software and may include "online" or electronic documentation, associated media, and printed materials ("Licensed Product"). The Licensed Product is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The Licensed Product is licensed, not sold. By installing, copying, or otherwise using the Licensed Product, you agree to be bound by the terms of this EULA. If you do not agree to the terms of this EULA, do not install, copy, or otherwise use the Licensed Product; you may, however, return it to your place of purchase for a full refund. In addition, by installing, copying, or otherwise using any updates or other components of the Licensed Product that you receive separately as part of the Licensed Product ("Updates"), you agree to be bound by any additional license terms that accompany such Updates. If you do not agree to the additional license terms that accompany such Updates, you may not install, copy, or otherwise use such Updates. Upon your acceptance of the terms and conditions of this EULA, KDAB grants you the right to use the Licensed Product in the manner provided below. KDAB grants to you as an individual a personal, nonexclusive, nontransferable license to make and use copies of the Licensed Product for the sole purposes of designing, developing, and testing your software product(s) ("Applications"). You may install copies of the Licensed Product on an unlimited number of computers provided that you are the only individual using the Licensed Product. If you are an entity, KDAB grants you the right to designate one, and only one, individual within your organization who shall have the sole right to use the Licensed Product in the manner provided above. You may at any time, but not more frequently that once every six (6) months, designate another individual to replace the current designated user by notifying KDAB, so long as there is no more than one designated user at any given time. GENERAL TERMS THAT APPLY TO APPLICATIONS AND REDISTRIBUTABLES KDAB grants you a nonexclusive, royalty-free right to reproduce and distribute the object code form of any portion of the Licensed Product ("Redistributables") for execution on any operating system of a type listed in the License Certificate ("Platforms"). Copies of Redistributables may only be distributed with and for the sole purpose of executing Applications permitted under this License Agreement that you have created using the Licensed Product. Under no circumstances may any copies of Redistributables be distributed separately. The license granted in this EULA for you to create your own Applications and distribute them and the Redistributables (if any) to your customers is subject to all of the following conditions: (i) all copies of the Applications you create must bear a valid copyright notice, either your own or the copyright notice that appears on the Licensed Product; (ii) you may not remove or alter any copyright, trademark or other proprietary rights notice contained in any portion of the Licensed Product; (iii) Redistributables, if any, shall be licensed to your customer "as is" (KDAB MAKES NO WARRANTIES OR REPRESENTATIONS VIS-A-VIS YOUR CUSTOMER WITH RESPECT TO REDISTRIBUTABLES, AND KDAB EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES VIS-A-VIS YOUR CUSTOMER, WHETHER EXPRESS OR IMPLIED, ORAL OR WRITTEN, INCLUDING, BUT NOT LIMITED TO ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE, WHETHER OR NOT KDAB KNOWS, HAS REASON TO KNOW, HAS BEEN ADVISED OR IS OTHERWISE AWARE OF SUCH PURPOSE); (iv) you will indemnify and hold KDAB, its related companies and its suppliers, harmless from and against any claims or liabilities arising out of the use, reproduction or distribution of your Applications; (v) your Applications must be written using a licensed, registered copy of the Licensed Product; (vi) your Applications must add primary and substantial functionality to the Licensed Product; (vii) your Applications may not pass on functionality which in any way makes it possible for others to create Applications with the Software; (viii) your Applications may not compete with the Licensed Product; (ix)) you may not use KDAB's or any of its suppliers' names, logos, or trademarks to market your programs, except to state that your program was written using the Licensed Product. LICENSEE'S BREACH OF CONTRACT In addition to penalties, other sanctions and the like as stated in the Swedish Copyright Act (1960:729), or successive legislation as it may appear, the Licensee agrees to pay a Contractual Fine in case of his/her/their breach of any of the above mentioned obligations, including but not limited to, the Licensee's obligation to let only one person per license use the Software as stated under above. The Contractual Fine is EUR 5000 and is payable by the Licensee to the Licenser immediately upon the Licenser having reasonably demonstrated that the Licensee is in breach of his obligations in this Agreement. WARRANTY DISCLAIMER THE LICENSED PRODUCT IS LICENSED TO YOU "AS IS". TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, KDAB ON BEHALF OF ITSELF AND ITS SUPPLIERS, DISCLAIMS ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT WITH REGARD TO THE LICENSED PRODUCT. THIS WARRANTY DISCLAIMER NOTWITHSTANDING, YOU MAY HAVE SPECIFIC LEGAL RIGHTS WHICH MAY VARY FROM STATE/JURISDICTION TO STATE/JURISDICTION. LIMITATION OF LIABILITY IF, KDAB'S WARRANTY DISCLAIMER NOTWITHSTANDING, KDAB IS HELD LIABLE TO YOU, WHETHER IN CONTRACT, TORT OR ANY OTHER LEGAL THEORY, BASED ON THE LICENSED PRODUCT, KDAB'S ENTIRE LIABILITY TO YOU AND YOUR EXCLUSIVE REMEDY SHALL BE, AT KDAB'S OPTION, EITHER (A) RETURN OF THE PRICE YOU PAID FOR THE LICENSED PRODUCT, OR (B) REPAIR OR REPLACEMENT OF THE LICENSED PRODUCT, PROVIDED YOU RETURN TO KDAB ALL COPIES OF THE LICENSED PRODUCT AS ORIGINALLY DELIVERED TO YOU. KDAB SHALL NOT UNDER ANY CIRCUMSTANCES BE LIABLE TO YOU BASED ON FAILURE OF THE LICENSED PRODUCT IF THE FAILURE RESULTED FROM ACCIDENT, ABUSE OR MISAPPLICATION, NOR SHALL KDAB UNDER ANY CIRCUMSTANCES BE LIABLE FOR SPECIAL DAMAGES, PUNITIVE OR EXEMPLARY DAMAGES, DAMAGES FOR LOSS OF PROFITS OR INTERRUPTION OF BUSINESS OR FOR LOSS OR CORRUPTION OF DATA. ANY AWARD OF DAMAGES FROM KDAB TO YOU SHALL NOT EXCEED THE TOTAL AMOUNT YOU HAVE PAID TO KDAB IN CONNECTION WITH THIS EULA. SUPPORT AND UPDATES You will receive email based, software developer support and access to Updates to the Licensed Product for one year from the date of initial delivery, in accordance with KDAB support policies and procedures. Such policies and procedures may be changed from time to time. GENERAL PROVISIONS This EULA may only be modified in writing signed by you and an authorized officer of KDAB. All terms of any purchase order or other ordering document shall be superseded by this EULA. If any provision of the EULA is found void or unenforceable, the remainder will remain valid and enforceable according to its terms. If any remedy provided is determined to have failed for its essential purpose, all limitations of liability and exclusions of damages set forth in this EULA shall remain in effect. This EULA shall be construed, interpreted and governed by the laws of Sweden, the venue to be Sunne Tingsratt. The EULA gives you specific legal rights; you may have others, which vary from state to state and from country to country. KDAB reserves all rights not specifically granted in this EULA. gammaray-2.3.0/LICENSE.txt000066400000000000000000000124511255003167400151430ustar00rootroot00000000000000GammaRay COMMERCIAL LICENSE AGREEMENT FOR COMMERCIAL VERSIONS Version 1.0 Copyright of this license text (C) 2001 Trolltech AS and (C) 2002-2015 Klarälvdalens Datakonsult AB. All rights reserved. License text used with kind permission of Trolltech AS. The software and accompanying material is Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB. This non-exclusive non-transferable License Agreement ("Agreement") is between you ("Licensee") and Klarälvdalens Datakonsult AB (KDAB), and pertains to the Klarälvdalens Datakonsult AB software product(s) accompanying this Agreement, which include(s) computer software and may include "online" or electronic documentation, associated media, and printed materials, including the source code, example programs and the documentation ("Software"). COPYRIGHT AND RESTRICTIONS 1. All intellectual property rights in the Software are owned by KDAB and are protected by Swedish copyright laws, other applicable copyright laws, and international treaty provisions. KDAB retains all rights not expressly granted. No title, property rights or copyright in the Software or in any modifications to the Software shall pass to the Licensee under any circumstances. The Software is licensed, not sold. 2. By installing, copying, or otherwise using the Software, you agree to be bound by the terms of this agreement. If you do not agree to the terms of this Agreement, do not install, copy, or otherwise use the Software. 3. Upon your acceptance of the terms and conditions of this Agreement, KDAB grants you the right to use the Software in the manner provided below. 4. KDAB grants to you as an individual a personal, nonexclusive, non-transferable license to make and use copies of the Software for the sole purposes of designing, developing, testing and distributing your software product(s) ("Applications"). You may install copies of the Software on an unlimited number of computers provided that you are the only individual using the Software. If you are an entity, KDAB grants you the right to designate one, and only one, individual within your organization who shall have the sole right to use the Software in the manner provided above. 5. The license granted in this Agreement for you to create and distribute your own Applications is subject to all of the following conditions: (i) all copies of the Applications you create must bear a valid copyright notice, either your own or the copyright notice that appears on the Software; (ii) you may not remove or alter any copyright, trademark or other proprietary rights notice contained in any portion of the Software; (iii) you will indemnify and hold KDAB, its related companies and its suppliers, harmless from and against any claims or liabilities arising out of the use and/or reproduction of your Applications; (iv) your Applications must be written using a licensed, registered copy of the Software; (v) your Applications must add primary and substantial functionality to the Software; (vi) your Applications may not pass on functionality which in any way makes it possible for others to create Applications with the Software; (vii) your Applications may not compete with the Software; (viii) you may not use KDAB's or any of its suppliers' names, logos, or trademarks to market your programs, except to state that your program was written using the Software. 6. LICENSEE'S BREACH OF CONTRACT In addition to penalties, other sanctions and the like as stated in the Swedish Copyright Act (1960:729), or successive legislation as it may appear, the Licensee agrees to pay a Contractual Fine in case of his/her/their breach of any of the above mentioned obligations, including but not limited to, the Licensee's obligation to let only one person per license use the Software as stated under above. The Contractual Fine is EUR 5000 and is payable by the Licensee to the Licenser immediately upon the Licenser having reasonably demonstrated that the Licensee is in breach of his obligations in this Agreement. 7. WARRANTY DISCLAIMER THE SOFTWARE IS LICENSED TO YOU "AS IS". TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, KDAB ON BEHALF OF ITSELF AND ITS SUPPLIERS, DISCLAIMS ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT WITH REGARD TO THE SOFTWARE. 8. LIMITATION OF LIABILITY IF, KDAB'S WARRANTY DISCLAIMER NOTWITHSTANDING, KDAB IS HELD LIABLE TO YOU BASED ON THE SOFTWARE, KDAB'S ENTIRE LIABILITY TO YOU AND YOUR EXCLUSIVE REMEDY SHALL BE, AT REPAIR OR REPLACEMENT OF THE SOFTWARE, PROVIDED YOU RETURN TO KDAB ALL COPIES OF THE SOFTWARE AS ORIGINALLY DELIVERED TO YOU. KDAB SHALL NOT UNDER ANY CIRCUMSTANCES BE LIABLE TO YOU BASED ON FAILURE OF THE SOFTWARE IF THE FAILURE RESULTED FROM ACCIDENT, ABUSE OR MISAPPLICATION, NOR SHALL KDAB UNDER ANY CIRCUMSTANCES BE LIABLE FOR SPECIAL DAMAGES, PUNITIVE OR EXEMPLARY DAMAGES, DAMAGES FOR LOSS OF PROFITS OR INTERRUPTION OF BUSINESS OR FOR LOSS OR CORRUPTION OF DATA. 9. This Agreement may only be modified in writing signed by you and an authorized officer of KDAB. All terms of any purchase order or other ordering document shall be superseded by this Agreement. 10. This Agreement shall be construed, interpreted and governed by the laws of Sweden, the venue to be Sunne Tingsratt. gammaray-2.3.0/ReadMe-commercial.txt000066400000000000000000000026541255003167400173330ustar00rootroot00000000000000Introduction ============ GammaRay is a software introspection tool for Qt applications developed by KDAB. Leveraging the QObject introspection mechanism it allows you to observe and manipulate your application at runtime. This works both locally on your workstation and remotely on an embedded target. For more information, see the ReadMe.txt file or visit our wiki on GitHub at https://github.com/KDAB/GammaRay/wiki Contributing ============ KDAB will happily accept external contributions, but will require a signed Copyright Assignment Agreement. Contact support@kdab.com for more information. Licensing ========= Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, Commercial licensing terms are available in the included file LICENSE.txt (for non-US customers) or LICENSE.US.txt (for US customers) , respectively. For terms of redistribution, refer to the license agreement. About KDAB ========== GammaRay is supported and maintained by Klarälvdalens Datakonsult AB (KDAB). KDAB, the Qt experts, provide consulting and mentoring for developing Qt applications from scratch and in porting from all popular and legacy frameworks to Qt. We continue to help develop parts of Qt and are one of the major contributors to the Qt Project. We can give advanced or standard trainings anywhere around the globe. Please visit http://www.kdab.com to meet the people who write code like this. gammaray-2.3.0/ReadMe.md000077700000000000000000000000001255003167400166652ReadMe.txtustar00rootroot00000000000000gammaray-2.3.0/ReadMe.txt000066400000000000000000000067771255003167400152340ustar00rootroot00000000000000Introduction ============ GammaRay is a software introspection tool for Qt applications developed by KDAB. Leveraging the QObject introspection mechanism it allows you to observe and manipulate your application at runtime. This works both locally on your workstation and remotely on an embedded target. Augmenting your instruction-level debugger, GammaRay allows you to work on a much higher level, with the same concepts as the frameworks you use. This is especially useful for the more complex Qt frameworks such as model/view, state machines or scene graphs. Among other things GammaRay can: * Browse the QObject tree with live updates. * View, and to some extent, edit QObject static and dynamic properties. * View and call slots of a QObject. * View other QObject elements such as signals, enums and class infos. * List all QObject inbound and outbound signal/slot connections. * Provide a layout information overlay for QWidget applications. * Inspect all QPainter operations used to draw a specific widget. * Browse the QtQuick2 item tree and scenegraph. * Plot object lifetime and emitted signals. * View the content of any QAbstractItemModel. Very useful when debugging a proxy model chain for example. * Browse the QAbstractProxyModel hierarchy. * Browse the item tree of any QGraphicsView scene. * Show a live preview of QGraphicsView items, including showing their coordinate system, transformation origin, rotate/zoom/pan, etc. * Intercept translations and change them at runtime. * Inspect all building blocks of a QStyle. * Act as a complete java script debugger, attachable to any QScriptEngine (including the usually not accessible one used by QtQuick1 internally). * Perform HTML/CSS/DOM/JS introspection/editing/profiling on any QWebPage, thanks to QWebInspector. * Browse the QResource tree and its content. * Browse QStateMachines, along with their states and transitions. * Show all registered meta types. * Show all installed fonts. * Show all available codecs. * Browse all QTextDocuments, along with the ability to edit them and view their internal structures. * Show all QTimers and their statistics (number of wakeups, wakeup time, ...) Contact ======= * Feel free to visit us on IRC: Channel is #gammaray on Freenode (irc://irc.freenode.net/gammaray) * Or send mail to our mailing list: https://mail.kdab.com/mailman/listinfo/gammaray-interest Get Involved ================= If you want to contribute, please check out: https://github.com/KDAB/GammaRay/wiki/Get-Involved Contributing ============ KDAB will happily accept external contributions, but substantial contributions will require a signed Copyright Assignment Agreement. Contact support@kdab.com for more information. License ======= The GammaRay Software is (C) 2010-2015 Klarälvdalens Datakonsult AB (KDAB), and is available under the terms of the GPL version 2 (or any later version, at your option). See LICENSE.GPL.txt for license details. Commercial use is also permitted as described in ReadMe-commercial.txt. About KDAB ========== GammaRay is supported and maintained by Klarälvdalens Datakonsult AB (KDAB). KDAB, the Qt experts, provide consulting and mentoring for developing Qt applications from scratch and in porting from all popular and legacy frameworks to Qt. We continue to help develop parts of Qt and are one of the major contributors to the Qt Project. We can give advanced or standard trainings anywhere around the globe. Please visit http://www.kdab.com to meet the people who write code like this. gammaray-2.3.0/add_license_blurb.sh000077500000000000000000000061471255003167400173040ustar00rootroot00000000000000#!/bin/bash find "$@" -name '*.h' -o -name '*.cpp' -o -name '*.qml' | grep -v /3rdparty/ | grep -v /qmldebugcontrol/ | grep -v /StackWalker | grep -v /modeltest | grep -v /processlist | grep -v /interactiveprocess | grep -v /build | while read FILE; do if grep -qiE "Copyright \(C\) [0-9, -]{4,} Klar.*lvdalens Datakonsult AB" "$FILE" ; then continue; fi thisfile=`basename $FILE` authorName=`git config user.name` authorEmail=`git config user.email` thisYear=`date +%Y` cat < "$FILE".tmp /* $thisfile This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) $thisYear Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: $authorName <$authorEmail> Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ EOF cat "$FILE" >> "$FILE".tmp mv "$FILE".tmp "$FILE" done #remove the following exit if you want to add a header to CMakeLists.txt files exit find "$@" -name 'CMakeLists.txt' | while read FILE; do if grep -qiE "Copyright \(C\) [0-9, -]{4,} Klar.*lvdalens Datakonsult AB" "$FILE" ; then continue; fi cat < "$FILE".tmp # This file is part of GammaRay, the Qt application inspection and # manipulation tool. # # Copyright (C) $thisYear Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com # Author: $authorName <$authorEmail> # # Licensees holding valid commercial KDAB GammaRay licenses may use this file in # accordance with GammaRay Commercial License Agreement provided with the Software. # # Contact info@kdab.com if any conditions of this licensing are not clear to you. # # 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 . EOF cat "$FILE" >> "$FILE".tmp mv "$FILE".tmp "$FILE" done gammaray-2.3.0/app/000077500000000000000000000000001255003167400140755ustar00rootroot00000000000000gammaray-2.3.0/app/CMakeLists.txt000066400000000000000000000017551255003167400166450ustar00rootroot00000000000000# Integrated launcher/client for Mac app bundles if(APPLE) set(gammaray_app_srcs main.cpp) add_executable(gammaray-app MACOSX_BUNDLE ${gammaray_app_srcs}) target_link_libraries(gammaray-app ${QT_QTGUI_LIBRARIES} gammaray_common_internal gammaray_launcher_shared gammaray_launcher_ui_internal gammaray_client ) set_target_properties(gammaray-app PROPERTIES OUTPUT_NAME "GammaRay" INSTALL_RPATH "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_STRING "GammaRay ${GAMMARAY_VERSION}" MACOSX_BUNDLE_ICON_FILE "GammaRay.icns" MACOSX_BUNDLE_GUI_IDENTIFIER "com.kdab.gammaray" MACOSX_BUNDLE_LONG_VERSION_STRING "${GAMMARAY_VERSION_STRING}" MACOSX_BUNDLE_BUNDLE_NAME "GammaRay" MACOSX_BUNDLE_SHORT_VERSION_STRING "${GAMMARAY_VERSION}" MACOSX_BUNDLE_BUNDLE_VERSION "${GAMMARAY_VERSION}" MACOSX_BUNDLE_COPYRIGHT "Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com" ) install(TARGETS gammaray-app ${INSTALL_TARGETS_DEFAULT_ARGS}) endif() gammaray-2.3.0/app/main.cpp000066400000000000000000000073651255003167400155400ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include using namespace GammaRay; class InternalLauncher : public Launcher { Q_OBJECT public: explicit InternalLauncher(const LaunchOptions& options, QObject* parent = 0) : Launcher(options, parent) {} signals: void launchClient(const QUrl &serverAddress); protected: void startClient(const QUrl& serverAddress) Q_DECL_OVERRIDE { emit launchClient(serverAddress); } }; class Orchestrator : public QObject { Q_OBJECT public: explicit Orchestrator(QObject *parent = 0) : QObject(parent) { m_launcherWindow = new LauncherWindow; connect(m_launcherWindow, SIGNAL(accepted()), this, SLOT(launcherWindowAccepted())); connect(m_launcherWindow, SIGNAL(rejected()), QCoreApplication::instance(), SLOT(quit())); m_launcherWindow->show(); } public slots: void launcherWindowAccepted() { Q_ASSERT(m_launcherWindow); Q_ASSERT(m_launcherWindow->result() == QDialog::Accepted); const LaunchOptions opts = m_launcherWindow->launchOptions(); if (!opts.isValid()) { QCoreApplication::exit(1); return; } m_launcher = new InternalLauncher(opts, this); connect(m_launcher, SIGNAL(launchClient(QUrl)), this, SLOT(startClient(QUrl))); connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished())); } void startClient(const QUrl &serverAddress) { auto *conMan = new ClientConnectionManager(this); connect(conMan, SIGNAL(ready()), conMan, SLOT(createMainWindow())); connect(conMan, SIGNAL(disconnected()), QApplication::instance(), SLOT(quit())); connect(conMan, SIGNAL(persistentConnectionError(QString)), conMan, SLOT(handlePersistentConnectionError(QString))); conMan->connectToHost(serverAddress); } void launcherFinished() { m_launcher->deleteLater(); } private: QPointer m_launcherWindow; QPointer m_launcher; }; int main(int argc, char** argv) { QCoreApplication::setOrganizationName("KDAB"); QCoreApplication::setOrganizationDomain("kdab.com"); QCoreApplication::setApplicationName("GammaRay"); QApplication::setQuitOnLastWindowClosed(false); QApplication app(argc, argv); Paths::setRelativeRootPath(GAMMARAY_INVERSE_BIN_DIR); ClientConnectionManager::init(); Orchestrator o; return app.exec(); } #include "main.moc" gammaray-2.3.0/client/000077500000000000000000000000001255003167400145735ustar00rootroot00000000000000gammaray-2.3.0/client/CMakeLists.txt000066400000000000000000000034231255003167400173350ustar00rootroot00000000000000set(gammaray_clientlib_srcs client.cpp remotemodel.cpp selectionmodelclient.cpp clientconnectionmanager.cpp propertycontrollerclient.cpp probecontrollerclient.cpp clientdevice.cpp tcpclientdevice.cpp localclientdevice.cpp ) qt4_add_resources(gammaray_clientlib_srcs ${CMAKE_SOURCE_DIR}/resources/gammaray.qrc) add_library(gammaray_client SHARED ${gammaray_clientlib_srcs}) set_target_properties(gammaray_client PROPERTIES ${GAMMARAY_DEFAULT_LIBRARY_PROPERTIES} DEFINE_SYMBOL MAKE_GAMMARAY_CLIENT_LIB ) target_link_libraries(gammaray_client LINK_PUBLIC ${QT_QTCORE_LIBRARIES} LINK_PRIVATE gammaray_ui gammaray_ui_internal gammaray_common ${QT_QTGUI_LIBRARIES} ${QT_QTNETWORK_LIBRARIES} ) set(gammaray_client_srcs main.cpp) add_executable(gammaray-client WIN32 ${gammaray_client_srcs}) target_link_libraries(gammaray-client gammaray_client gammaray_common ${QT_QTGUI_LIBRARIES} ) if(QNXNTO) target_link_libraries(gammaray-client cpp) endif() gammaray_embed_info_plist(gammaray-client ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in) set_target_properties(gammaray-client PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${LIBEXEC_INSTALL_DIR}" ) install(TARGETS gammaray_client EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS gammaray-client DESTINATION ${LIBEXEC_INSTALL_DIR}) gammaray_install_headers( gammaray_client_export.h clientconnectionmanager.h ) ecm_generate_pri_file(BASE_NAME GammaRayClient LIB_NAME gammaray_client DEPS "core gui widgets network GammaRayCommon GammaRayUi" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/.. ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) gammaray-2.3.0/client/Info.plist.in000066400000000000000000000006301255003167400171470ustar00rootroot00000000000000 CFBundleIdentifier com.kdab.GammaRay.client CFBundleInfoDictionaryVersion 6.0 CFBundleName GammaRay CFBundleVersion @GAMMARAY_VERSION_STRING@ CFBundleShortVersion @GAMMARAY_VERSION@ gammaray-2.3.0/client/client.cpp000066400000000000000000000152201255003167400165550ustar00rootroot00000000000000/* client.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "client.h" #include "clientdevice.h" #include #include #include #include #include #include #include using namespace GammaRay; Client::Client(QObject* parent) : Endpoint(parent) , m_clientDevice(0) , m_initState(0) { connect(this, SIGNAL(disconnected()), SLOT(socketDisconnected())); m_propertySyncer->setRequestInitialSync(true); } Client::~Client() { } Client* Client::instance() { return static_cast(s_instance); } bool Client::isRemoteClient() const { return true; } QUrl Client::serverAddress() const { return m_serverAddress; } void Client::connectToHost(const QUrl &url, int tryAgain) { m_serverAddress = url; m_initState = 0; m_clientDevice = ClientDevice::create(m_serverAddress, this); if (!m_clientDevice) { emit persisitentConnectionError(tr("Unsupported transport protocol.")); return; } connect(m_clientDevice, SIGNAL(connected()), this, SLOT(socketConnected())); connect(m_clientDevice, SIGNAL(transientError()), this, SIGNAL(transientConnectionError())); connect(m_clientDevice, SIGNAL(persistentError(QString)), this, SIGNAL(persisitentConnectionError(QString))); connect(m_clientDevice, SIGNAL(transientError()), this, SLOT(socketError())); connect(m_clientDevice, SIGNAL(persistentError(QString)), this, SLOT(socketError())); m_clientDevice->setTryAgain(tryAgain); m_clientDevice->connectToHost(); } void Client::disconnectFromHost() { if (m_clientDevice) m_clientDevice->disconnectFromHost(); } void Client::socketConnected() { Q_ASSERT(m_clientDevice->device()); setDevice(m_clientDevice->device()); } void Client::socketError() { m_clientDevice->deleteLater(); m_clientDevice = 0; } void Client::socketDisconnected() { foreach (const auto &objInfo, objectAddresses()) { unregisterObjectInternal(objInfo.second); } ObjectBroker::clear(); } void Client::messageReceived(const Message& msg) { // server version must be the very first message we get if (!(m_initState & VersionChecked)) { if (msg.address() != endpointAddress() || msg.type() != Protocol::ServerVersion) { qFatal("Protocol violation - first message is not the server version.\n"); } qint32 serverVersion; msg.payload() >> serverVersion; if (serverVersion != Protocol::version()) { qFatal("Server version is %d, was expecting %d - aborting.\n", serverVersion, Protocol::version()); } m_initState |= VersionChecked; return; } if (msg.address() == endpointAddress()) { switch (msg.type()) { case Protocol::ObjectAdded: { QString name; Protocol::ObjectAddress addr; msg.payload() >> name >> addr; registerObjectInternal(name, addr); break; } case Protocol::ObjectRemoved: { QString name; msg.payload() >> name; unregisterObjectInternal(name); break; } case Protocol::ObjectMapReply: { QVector > objects; msg.payload() >> objects; for (QVector >::const_iterator it = objects.constBegin(); it != objects.constEnd(); ++it) { if (it->first != endpointAddress()) registerObjectInternal(it->second, it->first); } m_propertySyncer->setAddress(objectAddress("com.kdab.GammaRay.PropertySyncer")); Q_ASSERT(m_propertySyncer->address() != Protocol::InvalidObjectAddress ); registerMessageHandlerInternal(m_propertySyncer->address(), m_propertySyncer, "handleMessage"); m_initState |= ObjectMapReceived; break; } case Protocol::ServerInfo: { QString label; msg.payload() >> label; setLabel(label); m_initState |= ServerInfoReceived; break; } default: qWarning() << Q_FUNC_INFO << "Got unhandled message:" << msg.type(); return; } if (m_initState == InitComplete) { m_initState |= ConnectionEstablished; emit connectionEstablished(); } } else { dispatchMessage(msg); } } Protocol::ObjectAddress Client::registerObject(const QString &name, QObject *object) { Q_ASSERT(isConnected()); Protocol::ObjectAddress address = Endpoint::registerObject(name, object); m_propertySyncer->addObject(address, object); m_propertySyncer->setObjectEnabled(address, true); Message msg(endpointAddress(), Protocol::ObjectMonitored); msg.payload() << address; send(msg); return address; } /// TODO: get rid of this void Client::registerForObject(Protocol::ObjectAddress objectAddress, QObject* handler, const char* slot) { Q_ASSERT(isConnected()); registerMessageHandlerInternal(objectAddress, handler, slot); Message msg(endpointAddress(), Protocol::ObjectMonitored); msg.payload() << objectAddress; send(msg); } void Client::unregisterForObject(Protocol::ObjectAddress objectAddress) { unregisterMessageHandlerInternal(objectAddress); unmonitorObject(objectAddress); } void Client::objectDestroyed(Protocol::ObjectAddress objectAddress, const QString &/*objectName*/, QObject * /*object*/) { unmonitorObject(objectAddress); } void Client::handlerDestroyed(Protocol::ObjectAddress objectAddress, const QString& /*objectName*/) { unmonitorObject(objectAddress); } void Client::unmonitorObject(Protocol::ObjectAddress objectAddress) { if (!isConnected()) return; Message msg(endpointAddress(), Protocol::ObjectUnmonitored); msg.payload() << objectAddress; send(msg); } gammaray-2.3.0/client/client.h000066400000000000000000000070701255003167400162260ustar00rootroot00000000000000/* client.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENT_H #define GAMMARAY_CLIENT_H #include #include #include namespace GammaRay { class ClientDevice; /** Client-side connection endpoint. */ class Client : public Endpoint { Q_OBJECT public: explicit Client(QObject *parent = 0); ~Client(); /** Connect to a server reachable on @p url. */ void connectToHost(const QUrl &url, int tryAgain = 0); void disconnectFromHost(); /** * Register a client-side QObject to send/receive messages to/from the server side. */ Protocol::ObjectAddress registerObject(const QString &name, QObject *object) Q_DECL_OVERRIDE; /** Register a message handler for @p objectAddress on object @p handler. * Once a message for this object is received, @p slot is called. * * TODO: get rid of this */ void registerForObject(Protocol::ObjectAddress objectAddress, QObject *handler, const char* slot); /** Unregister the message handler for @p objectAddress. */ void unregisterForObject(Protocol::ObjectAddress objectAddress); /** Singleton accessor. */ static Client* instance(); bool isRemoteClient() const Q_DECL_OVERRIDE; QUrl serverAddress() const Q_DECL_OVERRIDE; signals: /** Emitted when we successfully established a connection and passed the protocol version handshake step. */ void connectionEstablished(); /** Emitted on transient connection errors. * That is, on errors it's worth re-trying, e.g. because the target wasn't up yet. */ void transientConnectionError(); /** Emitted on persistent connection errors. * That is, any error that is not a transient one. */ void persisitentConnectionError(const QString &msg); protected: void messageReceived(const Message& msg) Q_DECL_OVERRIDE; void objectDestroyed(Protocol::ObjectAddress objectAddress, const QString &objectName, QObject *object) Q_DECL_OVERRIDE; void handlerDestroyed(Protocol::ObjectAddress objectAddress, const QString& objectName) Q_DECL_OVERRIDE; private: void unmonitorObject(Protocol::ObjectAddress objectAddress); private slots: void socketConnected(); void socketError(); void socketDisconnected(); private: enum InitState { VersionChecked = 1, ObjectMapReceived = 2, ServerInfoReceived = 4, ConnectionEstablished = 8, InitComplete = VersionChecked | ObjectMapReceived | ServerInfoReceived }; QUrl m_serverAddress; ClientDevice *m_clientDevice; int m_initState; }; } #endif // GAMMARAY_CLIENT_H gammaray-2.3.0/client/clientconnectionmanager.cpp000066400000000000000000000131541255003167400221740ustar00rootroot00000000000000/* clientconnectionmanager.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "clientconnectionmanager.h" #include "client.h" #include "remotemodel.h" #include "selectionmodelclient.h" #include "propertycontrollerclient.h" #include "probecontrollerclient.h" #include #include #include #include #include #include #include using namespace GammaRay; static QAbstractItemModel* modelFactory(const QString &name) { return new RemoteModel(name, qApp); } static QItemSelectionModel* selectionModelFactory(QAbstractItemModel* model) { return new SelectionModelClient(model->objectName() + ".selection", model, qApp); } static QObject* createPropertyController(const QString &name, QObject *parent) { return new PropertyControllerClient(name, parent); } static QObject* createProbeController(const QString &name, QObject *parent) { QObject *o = new ProbeControllerClient(parent); ObjectBroker::registerObject(name, o); return o; } void ClientConnectionManager::init() { StreamOperators::registerOperators(); ObjectBroker::registerClientObjectFactoryCallback(createPropertyController); ObjectBroker::registerClientObjectFactoryCallback(createProbeController); ObjectBroker::setModelFactoryCallback(modelFactory); ObjectBroker::setSelectionModelFactoryCallback(selectionModelFactory); } ClientConnectionManager::ClientConnectionManager(QObject* parent, bool showSplashScreenOnStartUp) : QObject(parent), m_client(new Client(this)), m_mainWindow(0), m_toolModel(0), m_ignorePersistentError(false), m_tries(0) { if (showSplashScreenOnStartUp) showSplashScreen(); connect(m_client, SIGNAL(disconnected()), SIGNAL(disconnected())); connect(m_client, SIGNAL(connectionEstablished()), SLOT(connectionEstablished())); connect(m_client, SIGNAL(transientConnectionError()), SLOT(transientConnectionError())); connect(m_client, SIGNAL(persisitentConnectionError(QString)), SIGNAL(persistentConnectionError(QString))); connect(this, SIGNAL(persistentConnectionError(QString)), SLOT(delayedHideSplashScreen())); } ClientConnectionManager::~ClientConnectionManager() { delete m_mainWindow; } QMainWindow *ClientConnectionManager::mainWindow() const { return m_mainWindow; } void ClientConnectionManager::connectToHost(const QUrl &url, int tryAgain) { m_serverUrl = url; m_connectionTimeout.start(); m_tries = tryAgain; connectToHost(); } void ClientConnectionManager::disconnectFromHost() { m_client->disconnectFromHost(); } void ClientConnectionManager::connectToHost() { m_client->connectToHost(m_serverUrl, m_tries ? m_tries-- : 0); } void ClientConnectionManager::connectionEstablished() { m_toolModel = ObjectBroker::model("com.kdab.GammaRay.ToolModel"); if (m_toolModel->rowCount() <= 0) { connect(m_toolModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(toolModelPopulated())); connect(m_toolModel, SIGNAL(layoutChanged()), SLOT(toolModelPopulated())); connect(m_toolModel, SIGNAL(modelReset()), SLOT(toolModelPopulated())); } else { toolModelPopulated(); } } void ClientConnectionManager::toolModelPopulated() { if (m_toolModel->rowCount() <= 0) return; disconnect(m_toolModel, 0, this, 0); QTimer::singleShot(0, this, SLOT(delayedHideSplashScreen())); emit ready(); } QMainWindow *ClientConnectionManager::createMainWindow() { delete m_mainWindow; m_mainWindow = new MainWindow; connect(m_mainWindow, SIGNAL(targetQuitRequested()), this, SLOT(targetQuitRequested())); m_ignorePersistentError = false; m_mainWindow->show(); return m_mainWindow; } void ClientConnectionManager::transientConnectionError() { if (m_connectionTimeout.elapsed() < 60 * 1000) { // client wasn't up yet, keep trying QTimer::singleShot(1000, this, SLOT(connectToHost())); } else { emit persistentConnectionError(tr("Connection refused.")); } } void ClientConnectionManager::handlePersistentConnectionError(const QString& msg) { if (m_ignorePersistentError) return; QString errorMsg; if (m_mainWindow) errorMsg = tr("Lost connection to remote host: %1").arg(msg); else errorMsg = tr("Could not establish connection to remote host: %1").arg(msg); QMessageBox::critical(m_mainWindow, tr("GammaRay - Connection Error"), errorMsg); QApplication::exit(1); } void ClientConnectionManager::delayedHideSplashScreen() { hideSplashScreen(); } void ClientConnectionManager::targetQuitRequested() { m_ignorePersistentError = true; } gammaray-2.3.0/client/clientconnectionmanager.h000066400000000000000000000072231255003167400216410ustar00rootroot00000000000000/* clientconnectionmanager.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENTCONNECTIONMANAGER_H #define GAMMARAY_CLIENTCONNECTIONMANAGER_H #include "gammaray_client_export.h" #include #include #include #include class QAbstractItemModel; class QMainWindow; namespace GammaRay { class Client; class MainWindow; /** @brief Pre-MainWindow connection setup logic. * * This is useful for embedding the GammaRay client into another application * * @since 2.3 */ class GAMMARAY_CLIENT_EXPORT ClientConnectionManager : public QObject { Q_OBJECT public: explicit ClientConnectionManager(QObject* parent = 0, bool showSplashScreenOnStartUp = true); ~ClientConnectionManager(); QMainWindow *mainWindow() const; /** Connect to a GammaRay probe at @p url. */ void connectToHost(const QUrl &url, int tryAgain = 0); /** One-time initialization of stream operators and factory callbacks. */ static void init(); signals: /** Emitted when the connection is established and the tool model is populated. * If you want to bring up the standard main window, connect this to createMainWindow(), * otherwise use this to show your own UI at this point. */ void ready(); /** Emitted when there has been a persistent connection error. * You can connect this to handlePersistentConnectionError() for a standard * message box and application exit handling. */ void persistentConnectionError(const QString &msg); /** Emitted when the connection to the target has been closed, for whatever reason. * For a stand-alone client you probably want to connect this to QApplication::quit(). */ void disconnected(); public slots: /** Disconnect GammaRay. */ void disconnectFromHost(); /** Brings up a client main window for the current connection. * If you want to use this, connect this slot to ready(). */ QMainWindow *createMainWindow(); /** Standard persistent connection error handler. * @see persistentConnectionError() */ void handlePersistentConnectionError(const QString &msg); private slots: void connectToHost(); void connectionEstablished(); void transientConnectionError(); void toolModelPopulated(); void delayedHideSplashScreen(); void targetQuitRequested(); private: QUrl m_serverUrl; Client *m_client; QPointer m_mainWindow; QAbstractItemModel *m_toolModel; QTime m_connectionTimeout; bool m_ignorePersistentError; int m_tries; }; } #endif // GAMMARAY_CLIENTCONNECTIONMANAGER_H gammaray-2.3.0/client/clientdevice.cpp000066400000000000000000000035601255003167400177410ustar00rootroot00000000000000/* clientdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "clientdevice.h" #include "tcpclientdevice.h" #include "localclientdevice.h" #include using namespace GammaRay; ClientDevice::ClientDevice(QObject* parent) : QObject(parent) , m_tries(0) { } ClientDevice::~ClientDevice() { } ClientDevice* ClientDevice::create(const QUrl& url, QObject *parent) { ClientDevice* device = 0; if (url.scheme() == "tcp") device = new TcpClientDevice(parent); else if (url.scheme() == "local") device = new LocalClientDevice(parent); if (!device) { qWarning() << "Unsupported transport protocol:" << url.toString(); return 0; } device->m_serverAddress = url; return device; } void ClientDevice::setTryAgain(int tries) { m_tries = tries; } gammaray-2.3.0/client/clientdevice.h000066400000000000000000000043731255003167400174110ustar00rootroot00000000000000/* clientdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENTDEVICE_H #define GAMMARAY_CLIENTDEVICE_H #include #include class QIODevice; namespace GammaRay { /** Adapter for the various different client socket classes (TCP, local, etc). */ class ClientDevice : public QObject { Q_OBJECT public: explicit ClientDevice(QObject* parent = 0); ~ClientDevice(); static ClientDevice* create(const QUrl& url, QObject* parent); void setTryAgain(int tries); virtual void connectToHost() = 0; virtual void disconnectFromHost() = 0; virtual QIODevice *device() const = 0; signals: void connected(); /** Server is not up yet. */ void transientError(); /** Anything not being a transient error. */ void persistentError(const QString &errorMsg); protected: QUrl m_serverAddress; int m_tries; }; template class ClientDeviceImpl : public ClientDevice { public: explicit ClientDeviceImpl(QObject *parent = 0) : ClientDevice(parent), m_socket(0) { } inline QIODevice* device() const { return m_socket; } protected: ClientT* m_socket; }; } #endif // GAMMARAY_CLIENTDEVICE_H gammaray-2.3.0/client/gammaray_client_export.h000066400000000000000000000030161255003167400215010ustar00rootroot00000000000000/* gammaray_client_export.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENT_EXPORT_H #define GAMMARAY_CLIENT_EXPORT_H #include #ifdef GAMMARAY_CLIENT_STATICLIB # undef GAMMARAY_CLIENT_SHAREDLIB # define GAMMARAY_CLIENT_EXPORT #else # ifdef MAKE_GAMMARAY_CLIENT_LIB # define GAMMARAY_CLIENT_EXPORT Q_DECL_EXPORT # else # define GAMMARAY_CLIENT_EXPORT Q_DECL_IMPORT # endif #endif #endif /* GAMMARAY_CLIENT_EXPORT_H */ gammaray-2.3.0/client/localclientdevice.cpp000066400000000000000000000043531255003167400207550ustar00rootroot00000000000000/* localclientdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localclientdevice.h" using namespace GammaRay; LocalClientDevice::LocalClientDevice(QObject* parent): ClientDeviceImpl(parent) { m_socket = new QLocalSocket(this); connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected())); connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(socketError())); } void LocalClientDevice::connectToHost() { m_socket->connectToServer(m_serverAddress.path()); } void LocalClientDevice::disconnectFromHost() { m_socket->disconnectFromServer(); } void LocalClientDevice::socketError() { switch (m_socket->error()) { case QLocalSocket::ConnectionRefusedError: case QLocalSocket::ServerNotFoundError: case QLocalSocket::SocketAccessError: case QLocalSocket::SocketTimeoutError: case QLocalSocket::ConnectionError: case QLocalSocket::UnknownSocketError: emit transientError(); break; default: if (m_tries) { --m_tries; emit transientError(); } else { emit persistentError(m_socket->errorString()); } break; } } gammaray-2.3.0/client/localclientdevice.h000066400000000000000000000031071255003167400204160ustar00rootroot00000000000000/* localclientdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALCLIENTDEVICE_H #define GAMMARAY_LOCALCLIENTDEVICE_H #include "clientdevice.h" #include namespace GammaRay { class LocalClientDevice : public ClientDeviceImpl { Q_OBJECT public: explicit LocalClientDevice(QObject* parent = 0); void connectToHost() Q_DECL_OVERRIDE; void disconnectFromHost() Q_DECL_OVERRIDE; private slots: void socketError(); }; } #endif // GAMMARAY_LOCALCLIENTDEVICE_H gammaray-2.3.0/client/main.cpp000066400000000000000000000041311255003167400162220ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "client.h" #include "clientconnectionmanager.h" #include #include #include #include using namespace GammaRay; int main(int argc, char** argv) { QApplication app(argc, argv); Paths::setRelativeRootPath(GAMMARAY_INVERSE_LIBEXEC_DIR); ClientConnectionManager::init(); QUrl serverUrl; if (app.arguments().size() == 2) { serverUrl = app.arguments().at(1); } else { serverUrl.setScheme("tcp"); serverUrl.setHost("127.0.0.1"); serverUrl.setPort(Client::defaultPort()); } ClientConnectionManager conMan; QObject::connect(&conMan, SIGNAL(ready()), &conMan, SLOT(createMainWindow())); QObject::connect(&conMan, SIGNAL(disconnected()), QApplication::instance(), SLOT(quit())); QObject::connect(&conMan, SIGNAL(persistentConnectionError(QString)), &conMan, SLOT(handlePersistentConnectionError(QString))); conMan.connectToHost(serverUrl); return app.exec(); } gammaray-2.3.0/client/probecontrollerclient.cpp000066400000000000000000000030141255003167400217070ustar00rootroot00000000000000/* probecontrollerclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probecontrollerclient.h" #include using namespace GammaRay; ProbeControllerClient::ProbeControllerClient(QObject* parent): QObject(parent) { } void ProbeControllerClient::detachProbe() { Endpoint::instance()->invokeObject(objectName(), "detachProbe"); } void ProbeControllerClient::quitHost() { Endpoint::instance()->invokeObject(objectName(), "quitHost"); } gammaray-2.3.0/client/probecontrollerclient.h000066400000000000000000000031441255003167400213600ustar00rootroot00000000000000/* probecontrollerclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBECONTROLLERCLIENT_H #define GAMMARAY_PROBECONTROLLERCLIENT_H #include namespace GammaRay { class ProbeControllerClient : public QObject, public GammaRay::ProbeControllerInterface { Q_OBJECT Q_INTERFACES(GammaRay::ProbeControllerInterface) public: explicit ProbeControllerClient(QObject *parent = 0); void detachProbe() Q_DECL_OVERRIDE; void quitHost() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROBECONTROLLERCLIENT_H gammaray-2.3.0/client/propertycontrollerclient.cpp000066400000000000000000000027651255003167400225000ustar00rootroot00000000000000/* propertycontrollerinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertycontrollerclient.h" #include #include #include using namespace GammaRay; PropertyControllerClient::PropertyControllerClient(const QString &name, QObject *parent) : PropertyControllerInterface(name, parent) { } PropertyControllerClient::~PropertyControllerClient() { } gammaray-2.3.0/client/propertycontrollerclient.h000066400000000000000000000031371255003167400221370ustar00rootroot00000000000000/* propertycontrollerinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYCONTROLLERCLIENT_H #define GAMMARAY_PROPERTYCONTROLLERCLIENT_H #include namespace GammaRay { class PropertyControllerClient : public PropertyControllerInterface { Q_OBJECT Q_INTERFACES(GammaRay::PropertyControllerInterface) public: explicit PropertyControllerClient(const QString &name, QObject *parent = 0); virtual ~PropertyControllerClient(); }; } #endif // GAMMARAY_PROPERTYCONTROLLERCLIENT_H gammaray-2.3.0/client/remotemodel.cpp000066400000000000000000000526761255003167400176330ustar00rootroot00000000000000/* remotemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "remotemodel.h" #include "client.h" #include #include #include using namespace GammaRay; void (*RemoteModel::s_registerClientCallback)() = 0; RemoteModel::Node::~Node() { qDeleteAll(children); } RemoteModel::RemoteModel(const QString &serverObject, QObject *parent) : QAbstractItemModel(parent), m_pendingDataRequestsTimer(new QTimer(this)), m_serverObject(serverObject), m_myAddress(Protocol::InvalidObjectAddress), m_currentSyncBarrier(0), m_targetSyncBarrier(0) { m_root = new Node; m_pendingDataRequestsTimer->setInterval(0); m_pendingDataRequestsTimer->setSingleShot(true); connect(m_pendingDataRequestsTimer, SIGNAL(timeout()), SLOT(doRequestDataAndFlags())); registerClient(serverObject); connectToServer(); } RemoteModel::~RemoteModel() { delete m_root; } bool RemoteModel::isConnected() const { return m_myAddress != Protocol::InvalidObjectAddress; } QModelIndex RemoteModel::index(int row, int column, const QModelIndex &parent) const { if (!isConnected() || row < 0 || column < 0) return QModelIndex(); Node *parentNode = nodeForIndex(parent); Q_ASSERT(parentNode->children.size() >= parentNode->rowCount); if (parentNode->rowCount == -1) requestRowColumnCount(parent); // trying to traverse into a branch we haven't loaded yet if (parentNode->rowCount <= row || parentNode->columnCount <= column) return QModelIndex(); return createIndex(row, column, parentNode->children.at(row)); } QModelIndex RemoteModel::parent(const QModelIndex &index) const { Node *currentNode = nodeForIndex(index); Q_ASSERT(currentNode); if (currentNode == m_root || currentNode->parent == m_root) return QModelIndex(); Q_ASSERT(currentNode->parent && currentNode->parent->parent); Q_ASSERT(currentNode->parent->children.contains(currentNode)); Q_ASSERT(currentNode->parent->parent->children.contains(currentNode->parent)); return createIndex(currentNode->parent->parent->children.indexOf(currentNode->parent), 0, currentNode->parent); } int RemoteModel::rowCount(const QModelIndex &index) const { if (!isConnected() || index.column() > 0) return 0; Node* node = nodeForIndex(index); Q_ASSERT(node); if (node->rowCount < 0) { if (node->columnCount < 0) // not yet requested vs. in the middle of insertion requestRowColumnCount(index); } return qMax(0, node->rowCount); // if requestRowColumnCount is synchronoous, ie. changes rowCount (as in simple unit test), returning 0 above would cause ModelTest to see inconsistent data } int RemoteModel::columnCount(const QModelIndex &index) const { if (!isConnected()) return 0; Node* node = nodeForIndex(index); Q_ASSERT(node); if (node->columnCount < 0) { requestRowColumnCount(index); return 0; } return node->columnCount; } QVariant RemoteModel::data(const QModelIndex &index, int role) const { if (!isConnected() || !index.isValid()) return QVariant(); Node* node = nodeForIndex(index); Q_ASSERT(node); const NodeStates state = stateForColumn(node, index.column()); if ((state & Outdated) && ((state & Loading) == 0)) { requestDataAndFlags(index); } if (role == LoadingState) { return QVariant::fromValue(state); } if (state & Empty) { // still waiting for data if (role == Qt::DisplayRole) return tr("Loading..."); return QVariant(); } // note .value returns good defaults otherwise return node->data.value(index.column()).value(role); } bool RemoteModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!isConnected()) return false; Message msg(m_myAddress, Protocol::ModelSetDataRequest); msg.payload() << Protocol::fromQModelIndex(index) << role << value; sendMessage(msg); return false; } Qt::ItemFlags RemoteModel::flags(const QModelIndex& index) const { Node* node = nodeForIndex(index); Q_ASSERT(node); const QHash::const_iterator it = node->flags.constFind(index.column()); if (it == node->flags.constEnd()) { // default flags if we don't know better, otherwise we can't select into non-expanded branches return index.isValid() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags; } return it.value(); } QVariant RemoteModel::headerData(int section, Qt::Orientation orientation, int role) const { if (!isConnected()) return QVariant(); if (!m_headers.contains(orientation) || !m_headers.value(orientation).contains(section)) requestHeaderData(orientation, section); return m_headers.value(orientation).value(section).value(role); } void RemoteModel::newMessage(const GammaRay::Message& msg) { if (!checkSyncBarrier(msg)) return; switch (msg.type()) { case Protocol::ModelRowColumnCountReply: { Protocol::ModelIndex index; msg.payload() >> index; Node *node = nodeForIndex(index); if (!node) { // This can happen e.g. when we called a blocking operation from the remote client // via the method invocation with a direct connection. Then when the blocking // operation creates e.g. a QObject it is directly added/removed to the ObjectTree // and we get signals for that. When we then though ask for column counts we will // only get responses once the blocking operation has finished, at which point // the object may already have been invalidated. break; } int rowCount, columnCount; msg.payload() >> rowCount >> columnCount; Q_ASSERT(rowCount >= 0 && columnCount >= 0); if (rowCount == node->rowCount && columnCount == node->columnCount) { // This can happen in similar racy conditions as below, when we request the row/col count // for two different Node* at the same index (one was deleted inbetween and then the other // was created). Anyhow, since the data is equal we can/should ignore it anyways. break; } if (node->rowCount == -1) break; // we didn't ask for this, probably outdated response for a moved node Q_ASSERT(node->rowCount < -1 && node->columnCount == -1); const QModelIndex qmi = modelIndexForNode(node, 0); if (columnCount) { beginInsertColumns(qmi, 0, columnCount - 1); node->columnCount = columnCount; endInsertColumns(); } else { node->columnCount = 0; } if (rowCount) { beginInsertRows(qmi, 0, rowCount - 1); node->children.reserve(rowCount); for (int i = 0; i < rowCount; ++i) { Node *child = new Node; child->parent = node; node->children.push_back(child); } node->rowCount = rowCount; endInsertRows(); } else { node->rowCount = 0; } break; } case Protocol::ModelContentReply: { quint32 size; msg.payload() >> size; Q_ASSERT(size > 0); for (quint32 i = 0; i < size; ++i) { Protocol::ModelIndex index; msg.payload() >> index; Node *node = nodeForIndex(index); const NodeStates state = node ? stateForColumn(node, index.last().second) : NoState; typedef QHash ItemData; ItemData itemData; qint32 flags; msg.payload() >> itemData >> flags; if ((state & Loading) == 0) continue; // we didn't ask for this, probably outdated response for a moved cell node->data[index.last().second] = itemData; node->flags[index.last().second] = static_cast(flags); node->state.insert(index.last().second, state & ~(Loading | Empty | Outdated)); // TODO we could do some range compression here const QModelIndex qmi = modelIndexForNode(node, index.last().second); emit dataChanged(qmi, qmi); } break; } case Protocol::ModelHeaderReply: { qint8 orientation; qint32 section; QHash data; msg.payload() >> orientation >> section >> data; Q_ASSERT(orientation == Qt::Horizontal || orientation == Qt::Vertical); Q_ASSERT(section >= 0); m_headers[static_cast(orientation)][section] = data; if ((orientation == Qt::Horizontal && m_root->columnCount > section) || (orientation == Qt::Vertical && m_root->rowCount > section)) emit headerDataChanged(static_cast(orientation), section, section); break; } case Protocol::ModelContentChanged: { Protocol::ModelIndex beginIndex, endIndex; msg.payload() >> beginIndex >> endIndex; Node *node = nodeForIndex(beginIndex); if (!node || node == m_root) break; Q_ASSERT(beginIndex.last().first <= endIndex.last().first); Q_ASSERT(beginIndex.last().second <= endIndex.last().second); // mark content as outdated (will be refetched on next request) for (int row = beginIndex.last().first; row <= endIndex.last().first; ++row) { Node *currentRow = node->parent->children.at(row); for (int col = beginIndex.last().second; col <= endIndex.last().second; ++col) { const NodeStates state = stateForColumn(currentRow, col); if ((state & Outdated) == 0) currentRow->state.insert(col, state | Outdated); } } const QModelIndex qmiBegin = modelIndexForNode(node, beginIndex.last().second); const QModelIndex qmiEnd = qmiBegin.sibling(endIndex.last().first, endIndex.last().second); emit dataChanged(qmiBegin, qmiEnd); break; } case Protocol::ModelHeaderChanged: { qint8 ori; int first, last; msg.payload() >> ori >> first >> last; const Qt::Orientation orientation = static_cast(ori); for (int i = first; i < last; ++i) m_headers[orientation].remove(i); emit headerDataChanged(orientation, first, last); break; } case Protocol::ModelRowsAdded: { Protocol::ModelIndex parentIndex; int first, last; msg.payload() >> parentIndex >> first >> last; Q_ASSERT(last >= first); Node *parentNode = nodeForIndex(parentIndex); if (!parentNode || parentNode->rowCount < 0) return; // we don't know the parent yet, so we don't care about changes to it either doInsertRows(parentNode, first, last); break; } case Protocol::ModelRowsRemoved: { Protocol::ModelIndex parentIndex; int first, last; msg.payload() >> parentIndex >> first >> last; Q_ASSERT(last >= first); Node *parentNode = nodeForIndex(parentIndex); if (!parentNode || parentNode->rowCount < 0) return; // we don't know the parent yet, so we don't care about changes to it either doRemoveRows(parentNode, first, last); break; } case Protocol::ModelRowsMoved: { Protocol::ModelIndex sourceParentIndex, destParentIndex; int sourceFirst, sourceLast, destChild; msg.payload() >> sourceParentIndex >> sourceFirst >> sourceLast >> destParentIndex >> destChild; Q_ASSERT(sourceLast >= sourceFirst); Node *sourceParent = nodeForIndex(sourceParentIndex); Node *destParent = nodeForIndex(destParentIndex); const bool sourceKnown = sourceParent && sourceParent->rowCount >= 0; const bool destKnown = destParent && destParent->rowCount >= 0; // case 1: source and destination not locally cached -> nothing to do if (!sourceKnown && !destKnown) break; // case 2: only source is locally known -> remove if (sourceKnown && !destKnown) { doRemoveRows(sourceParent, sourceFirst, sourceLast); break; } // case 3: only destination is locally known -> added if (!sourceKnown && destKnown) { doInsertRows(destParent, destChild, destChild + sourceLast - sourceFirst); break; } // case 4: source and destination are locally known -> move if (sourceKnown && destKnown) { doMoveRows(sourceParent, sourceFirst, sourceLast, destParent, destChild); break; } } case Protocol::ModelColumnsAdded: case Protocol::ModelColumnsMoved: case Protocol::ModelColumnsRemoved: case Protocol::ModelLayoutChanged: { // TODO qWarning() << Q_FUNC_INFO << "not implemented yet" << msg.type() << m_serverObject; } case Protocol::ModelReset: { clear(); break; } } } void RemoteModel::serverRegistered(const QString& objectName, Protocol::ObjectAddress objectAddress) { if (m_serverObject == objectName) { m_myAddress = objectAddress; connectToServer(); } } void RemoteModel::serverUnregistered(const QString& objectName, Protocol::ObjectAddress objectAddress) { Q_UNUSED(objectName); if (m_myAddress == objectAddress) { m_myAddress = Protocol::InvalidObjectAddress; clear(); } } RemoteModel::Node* RemoteModel::nodeForIndex(const QModelIndex &index) const { if (!index.isValid()) return m_root; return reinterpret_cast(index.internalPointer()); } RemoteModel::Node* RemoteModel::nodeForIndex(const Protocol::ModelIndex &index) const { Node *node = m_root; for (int i = 0; i < index.size(); ++i) { if (node->children.size() <= index[i].first) return 0; node = node->children[index[i].first]; } return node; } QModelIndex RemoteModel::modelIndexForNode(Node* node, int column) const { Q_ASSERT(node); if (node == m_root) return QModelIndex(); return createIndex(node->parent->children.indexOf(node), column, node); } RemoteModel::NodeStates RemoteModel::stateForColumn(RemoteModel::Node* node, int columnIndex) const { Q_ASSERT(node); const QHash::const_iterator it = node->state.constFind(columnIndex); if (it == node->state.constEnd()) return Empty | Outdated; return it.value(); } void RemoteModel::requestRowColumnCount(const QModelIndex &index) const { Node *node = nodeForIndex(index); Q_ASSERT(node); Q_ASSERT(node->rowCount < 0 && node->columnCount < 0); if (node->rowCount < -1) // already requesting return; node->rowCount = -2; Message msg(m_myAddress, Protocol::ModelRowColumnCountRequest); msg.payload() << Protocol::fromQModelIndex(index); sendMessage(msg); } void RemoteModel::requestDataAndFlags(const QModelIndex& index) const { Node *node = nodeForIndex(index); Q_ASSERT(node); const NodeStates state = stateForColumn(node, index.column()); Q_ASSERT(!node->data.contains(index.column()) || state & Outdated); Q_ASSERT(!node->flags.contains(index.column()) || state & Outdated); Q_ASSERT((state & Loading) == 0); node->state.insert(index.column(), state | Loading); // mark pending request m_pendingDataRequests.push_back(Protocol::fromQModelIndex(index)); if (m_pendingDataRequests.size() > 100) { m_pendingDataRequestsTimer->stop(); doRequestDataAndFlags(); } else { m_pendingDataRequestsTimer->start(); } } void RemoteModel::doRequestDataAndFlags() const { Q_ASSERT(!m_pendingDataRequests.isEmpty()); Message msg(m_myAddress, Protocol::ModelContentRequest); msg.payload() << quint32(m_pendingDataRequests.size()); foreach (const auto &index, m_pendingDataRequests) msg.payload() << index; m_pendingDataRequests.clear(); sendMessage(msg); } void RemoteModel::requestHeaderData(Qt::Orientation orientation, int section) const { Q_ASSERT(section >= 0); Q_ASSERT(!m_headers.value(orientation).contains(section)); m_headers[orientation][section][Qt::DisplayRole] = tr("Loading..."); Message msg(m_myAddress, Protocol::ModelHeaderRequest); msg.payload() << qint8(orientation) << qint32(section); sendMessage(msg); } void RemoteModel::clear() { beginResetModel(); if (isConnected()) { Message msg(m_myAddress, Protocol::ModelSyncBarrier); msg.payload() << ++m_targetSyncBarrier; sendMessage(msg); } delete m_root; m_root = new Node; m_headers.clear(); endResetModel(); } void RemoteModel::connectToServer() { if (m_myAddress == Protocol::InvalidObjectAddress) return; beginResetModel(); Client::instance()->registerForObject(m_myAddress, this, "newMessage"); endResetModel(); } bool RemoteModel::checkSyncBarrier(const Message& msg) { if (msg.type() == Protocol::ModelSyncBarrier) msg.payload() >> m_currentSyncBarrier; return m_currentSyncBarrier == m_targetSyncBarrier; } void RemoteModel::resetLoadingState(RemoteModel::Node* node, int startRow) const { if (node->rowCount < 0) { node->rowCount = -1; // reset row count loading state return; } Q_ASSERT(node->children.size() == node->rowCount); for (int row = startRow; row < node->rowCount; ++row) { Node *child = node->children[row]; for (QHash::iterator it = child->state.begin(); it != child->state.end(); ++it) { if (it.value() & Loading) it.value() = it.value() & ~Loading; } resetLoadingState(child, 0); } } void RemoteModel::doInsertRows(RemoteModel::Node* parentNode, int first, int last) { Q_ASSERT(parentNode->rowCount == parentNode->children.size()); const QModelIndex qmiParent = modelIndexForNode(parentNode, 0); beginInsertRows(qmiParent, first, last); // allocate rows in the right spot if (first == parentNode->children.size()) parentNode->children.resize(parentNode->children.size() + 1 + last - first); else parentNode->children.insert(first, last - first + 1, 0); // create nodes for the new rows for (int i = first; i <= last; ++i) { Node *child = new Node; child->parent = parentNode; parentNode->children[i] = child; } // adjust row count parentNode->rowCount += last - first + 1; Q_ASSERT(parentNode->rowCount == parentNode->children.size()); endInsertRows(); resetLoadingState(parentNode, last); } void RemoteModel::doRemoveRows(RemoteModel::Node* parentNode, int first, int last) { Q_ASSERT(parentNode->rowCount == parentNode->children.size()); const QModelIndex qmiParent = modelIndexForNode(parentNode, 0); beginRemoveRows(qmiParent, first, last); // delete nodes for (int i = first; i <= last; ++i) delete parentNode->children.at(i); parentNode->children.remove(first, last - first + 1); // adjust row count parentNode->rowCount -= last - first + 1; Q_ASSERT(parentNode->rowCount == parentNode->children.size()); endRemoveRows(); resetLoadingState(parentNode, first); } void RemoteModel::doMoveRows(RemoteModel::Node* sourceParentNode, int sourceStart, int sourceEnd, RemoteModel::Node* destParentNode, int destStart) { Q_ASSERT(sourceParentNode->rowCount == sourceParentNode->children.size()); Q_ASSERT(destParentNode->rowCount == destParentNode->children.size()); Q_ASSERT(sourceEnd >= sourceStart); Q_ASSERT(sourceParentNode->rowCount > sourceEnd); const int destEnd = destStart + sourceEnd - sourceStart; const int amount = sourceEnd - sourceStart + 1; const QModelIndex qmiSourceParent = modelIndexForNode(sourceParentNode, 0); const QModelIndex qmiDestParent = modelIndexForNode(destParentNode, 0); beginMoveRows(qmiSourceParent, sourceStart, sourceEnd, qmiDestParent, destStart); // make room in the destination if (destStart == destParentNode->children.size()) destParentNode->children.resize(destParentNode->children.size() + amount); else destParentNode->children.insert(destStart, amount, 0); // move nodes for (int i = 0; i < amount; ++i) { Node *node = sourceParentNode->children.at(sourceStart + i); node->parent = destParentNode; destParentNode->children[destStart + i] = node; } // shrink source sourceParentNode->children.remove(sourceStart, amount); // adjust row count sourceParentNode->rowCount -= amount; destParentNode->rowCount += amount; Q_ASSERT(sourceParentNode->rowCount == sourceParentNode->children.size()); Q_ASSERT(destParentNode->rowCount == destParentNode->children.size()); endMoveRows(); resetLoadingState(sourceParentNode, sourceStart); resetLoadingState(destParentNode, destEnd); } void RemoteModel::registerClient(const QString &serverObject) { if (Q_UNLIKELY(s_registerClientCallback)) { // called from ctor, so we can't use virtuals here s_registerClientCallback(); return; } m_myAddress = Endpoint::instance()->objectAddress(serverObject); connect(Endpoint::instance(), SIGNAL(objectRegistered(QString,Protocol::ObjectAddress)), SLOT(serverRegistered(QString,Protocol::ObjectAddress))); connect(Endpoint::instance(), SIGNAL(objectUnregistered(QString,Protocol::ObjectAddress)), SLOT(serverUnregistered(QString,Protocol::ObjectAddress))); } void RemoteModel::sendMessage(const Message& msg) const { Endpoint::send(msg); } gammaray-2.3.0/client/remotemodel.h000066400000000000000000000125241255003167400172640ustar00rootroot00000000000000/* remotemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_REMOTEMODEL_H #define GAMMARAY_REMOTEMODEL_H #include "gammaray_client_export.h" #include #include #include #include #include #include namespace GammaRay { class Message; /** @internal Exported for unit test use only. */ class GAMMARAY_CLIENT_EXPORT RemoteModel : public QAbstractItemModel { Q_OBJECT public: explicit RemoteModel(const QString &serverObject, QObject *parent = 0); ~RemoteModel(); bool isConnected() const; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex& child) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; public slots: void newMessage(const GammaRay::Message &msg); void serverRegistered(const QString &objectName, Protocol::ObjectAddress objectAddress); void serverUnregistered(const QString& objectName, Protocol::ObjectAddress objectAddress); public: enum Roles { LoadingState = ObjectModel::UserRole + 128 // TODO: Tidy up roles in general (and give loading state a proper id) }; enum NodeState { NoState = 0, Empty = 1, Loading = 2, Outdated = 4 }; Q_DECLARE_FLAGS(NodeStates, NodeState) private: struct Node { // represents one row Node() : parent(0), rowCount(-1), columnCount(-1) {} ~Node(); Node* parent; QVector children; qint32 rowCount; qint32 columnCount; QHash > data; // column -> role -> data QHash flags; // column -> flags QHash state; // column -> state (cache outdated, waiting for data, etc) }; void clear(); void connectToServer(); bool checkSyncBarrier(const Message &msg); Node* nodeForIndex(const QModelIndex &index) const; Node* nodeForIndex(const Protocol::ModelIndex &index) const; QModelIndex modelIndexForNode(GammaRay::RemoteModel::Node* node, int column) const; NodeStates stateForColumn(Node* node, int columnIndex) const; void requestRowColumnCount(const QModelIndex &index) const; void requestDataAndFlags(const QModelIndex &index) const; void requestHeaderData(Qt::Orientation orientation, int section) const; /// Reset the loading state for all rows at @p startRow or later. /// This is needed when rows have been added or removed before @p startRow, since /// pending replies might have a wrong index. void resetLoadingState(Node *node, int startRow) const; /// execute a insertRows() operation void doInsertRows(Node *parentNode, int first, int last); /// execute a removeRows() operation void doRemoveRows(Node *parentNode, int first, int last); /// execute a rowsMoved() operation void doMoveRows(Node *sourceParentNode, int sourceStart, int sourceEnd, Node* destParentNode, int destStart); private slots: void doRequestDataAndFlags() const; private: Node* m_root; mutable QHash > > m_headers; // orientation -> section -> role -> data mutable QVector m_pendingDataRequests; QTimer* m_pendingDataRequestsTimer; QString m_serverObject; Protocol::ObjectAddress m_myAddress; qint32 m_currentSyncBarrier, m_targetSyncBarrier; // hooks for unit tests static void (*s_registerClientCallback)(); void registerClient(const QString &serverObject); virtual void sendMessage(const Message &msg) const; friend class FakeRemoteModel; }; } Q_DECLARE_OPERATORS_FOR_FLAGS(GammaRay::RemoteModel::NodeStates) Q_DECLARE_METATYPE(GammaRay::RemoteModel::NodeStates) #endif gammaray-2.3.0/client/selectionmodelclient.cpp000066400000000000000000000047031255003167400215100ustar00rootroot00000000000000/* selectionmodelclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "selectionmodelclient.h" #include "client.h" using namespace GammaRay; SelectionModelClient::SelectionModelClient(const QString& objectName, QAbstractItemModel* model, QObject* parent) : NetworkSelectionModel(objectName, model, parent) { m_myAddress = Client::instance()->objectAddress(objectName); connect(Client::instance(), SIGNAL(objectRegistered(QString,Protocol::ObjectAddress)), SLOT(serverRegistered(QString,Protocol::ObjectAddress))); connect(Client::instance(), SIGNAL(objectUnregistered(QString,Protocol::ObjectAddress)), SLOT(serverUnregistered(QString,Protocol::ObjectAddress))); connectToServer(); } SelectionModelClient::~SelectionModelClient() { } void SelectionModelClient::connectToServer() { if (m_myAddress == Protocol::InvalidObjectAddress) return; Client::instance()->registerForObject(m_myAddress, this, "newMessage"); // TODO: send initial selection? } void SelectionModelClient::serverRegistered(const QString& objectName, Protocol::ObjectAddress objectAddress) { if (objectName == m_objectName) { m_myAddress = objectAddress; connectToServer(); } } void SelectionModelClient::serverUnregistered(const QString& objectName, Protocol::ObjectAddress objectAddress) { Q_UNUSED(objectAddress); if (objectName == m_objectName) m_myAddress = Protocol::InvalidObjectAddress; } gammaray-2.3.0/client/selectionmodelclient.h000066400000000000000000000034651255003167400211610ustar00rootroot00000000000000/* selectionmodelclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SELECTIONMODELCLIENT_H #define GAMMARAY_SELECTIONMODELCLIENT_H #include namespace GammaRay { /** Client side of the network transparent QItemSelectionModel. */ class SelectionModelClient : public NetworkSelectionModel { Q_OBJECT public: SelectionModelClient(const QString& objectName, QAbstractItemModel* model, QObject* parent); ~SelectionModelClient(); private slots: void serverRegistered(const QString &objectName, Protocol::ObjectAddress objectAddress); void serverUnregistered(const QString &objectName, Protocol::ObjectAddress objectAddress); private: void connectToServer(); }; } #endif // GAMMARAY_SELECTIONMODELCLIENT_H gammaray-2.3.0/client/tcpclientdevice.cpp000066400000000000000000000036401255003167400204470ustar00rootroot00000000000000/* tcpclientdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "tcpclientdevice.h" #include "client.h" using namespace GammaRay; TcpClientDevice::TcpClientDevice(QObject* parent) : ClientDeviceImpl(parent) { m_socket = new QTcpSocket(this); connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected())); connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError())); } void TcpClientDevice::connectToHost() { m_socket->connectToHost(m_serverAddress.host(), m_serverAddress.port(Client::defaultPort())); } void TcpClientDevice::disconnectFromHost() { m_socket->disconnectFromHost(); } void TcpClientDevice::socketError() { if (m_socket->error() == QAbstractSocket::ConnectionRefusedError) emit transientError(); else emit persistentError(m_socket->errorString()); } gammaray-2.3.0/client/tcpclientdevice.h000066400000000000000000000030671255003167400201170ustar00rootroot00000000000000/* tcpclientdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TCPCLIENTDEVICE_H #define GAMMARAY_TCPCLIENTDEVICE_H #include "clientdevice.h" #include namespace GammaRay { class TcpClientDevice : public ClientDeviceImpl { Q_OBJECT public: explicit TcpClientDevice(QObject* parent = 0); void connectToHost() Q_DECL_OVERRIDE; void disconnectFromHost() Q_DECL_OVERRIDE; private slots: void socketError(); }; } #endif // GAMMARAY_TCPCLIENTDEVICE_H gammaray-2.3.0/cmake/000077500000000000000000000000001255003167400143755ustar00rootroot00000000000000gammaray-2.3.0/cmake/CMakeLists.txt000066400000000000000000000001131255003167400171300ustar00rootroot00000000000000install(FILES GammaRayMacros.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) gammaray-2.3.0/cmake/ECMGeneratePriFile.cmake000066400000000000000000000205071255003167400207350ustar00rootroot00000000000000#.rst: # ECMGeneratePriFile # ------------------ # # Generate a ``.pri`` file for the benefit of qmake-based projects. # # As well as the function below, this module creates the cache variable # ``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``. # This assumes Qt and the current project are both installed to the same # non-system prefix. Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will # certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like # ``share/qt5/mkspecs/modules``. # # The main thing is that this should be the ``modules`` subdirectory of either # the default qmake ``mkspecs`` directory or of a directory that will be in the # ``$QMAKEPATH`` environment variable when qmake is run. # # :: # # ecm_generate_pri_file(BASE_NAME # LIB_NAME # [DEPS " [ [...]]"] # [FILENAME_VAR ] # [INCLUDE_INSTALL_DIR ] # [LIB_INSTALL_DIR ]) # # If your CMake project produces a Qt-based library, you may expect there to be # applications that wish to use it that use a qmake-based build system, rather # than a CMake-based one. Creating a ``.pri`` file will make use of your # library convenient for them, in much the same way that CMake config files make # things convenient for CMake-based applications. # # ecm_generate_pri_file() generates just such a file. It requires the # ``PROJECT_VERSION_STRING`` variable to be set. This is typically set by # :module:`ECMSetupVersion`, although the project() command in CMake 3.0.0 and # later can also set this. # # BASE_NAME specifies the name qmake project (.pro) files should use to refer to # the library (eg: KArchive). LIB_NAME is the name of the actual library to # link to (ie: the first argument to add_library()). DEPS is a space-separated # list of the base names of other libraries (for Qt libraries, use the same # names you use with the ``QT`` variable in a qmake project file, such as "core" # for QtCore). FILENAME_VAR specifies the name of a variable to store the path # to the generated file in. # # INCLUDE_INSTALL_DIR is the path (relative to ``CMAKE_INSTALL_PREFIX``) that # include files will be installed to. It defaults to # ``${INCLUDE_INSTALL_DIR}/`` if the ``INCLUDE_INSTALL_DIR`` variable # is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable # is used instead, and if neither are set ``include`` is used. LIB_INSTALL_DIR # operates similarly for the installation location for libraries; it defaults to # ``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order. # # Example usage: # # .. code-block:: cmake # # ecm_generate_pri_file( # BASE_NAME KArchive # LIB_NAME KF5KArchive # DEPS "core" # FILENAME_VAR pri_filename # ) # install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) # # A qmake-based project that wished to use this would then do:: # # QT += KArchive # # in their ``.pro`` file. # # Since pre-1.0.0. #============================================================================= # Copyright 2014 David Faure # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= if(KDE_INSTALL_USE_QT_SYS_PATHS) include(ECMQueryQmake) query_qmake(qt_host_data_dir QT_HOST_DATA) set(ECM_MKSPECS_INSTALL_DIR ${qt_host_data_dir}/mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.") else () set(ECM_MKSPECS_INSTALL_DIR mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.") endif() function(ECM_GENERATE_PRI_FILE) set(options ) set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) set(multiValueArgs ) cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(EGPF_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PRI_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"") endif() if(NOT EGPF_BASE_NAME) message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PRI_FILE() call") endif() if(NOT EGPF_LIB_NAME) message(FATAL_ERROR "Required argument LIB_NAME missing in ECM_GENERATE_PRI_FILE() call") endif() if(NOT PROJECT_VERSION_STRING) message(FATAL_ERROR "Required variable PROJECT_VERSION_STRING not set before ECM_GENERATE_PRI_FILE() call. Did you call ecm_setup_version?") endif() if(NOT EGPF_INCLUDE_INSTALL_DIR) if(INCLUDE_INSTALL_DIR) set(EGPF_INCLUDE_INSTALL_DIR "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}") elseif(CMAKE_INSTALL_INCLUDEDIR) set(EGPF_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}") else() set(EGPF_INCLUDE_INSTALL_DIR "include/${EGPF_BASE_NAME}") endif() endif() if(NOT EGPF_LIB_INSTALL_DIR) if(LIB_INSTALL_DIR) set(EGPF_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}") elseif(CMAKE_INSTALL_LIBDIR) set(EGPF_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") else() set(EGPF_LIB_INSTALL_DIR "lib") endif() endif() string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PROJECT_VERSION_MAJOR "${PROJECT_VERSION_STRING}") string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PROJECT_VERSION_MINOR "${PROJECT_VERSION_STRING}") string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PROJECT_VERSION_PATCH "${PROJECT_VERSION_STRING}") set(PRI_TARGET_BASENAME ${EGPF_BASE_NAME}) set(PRI_TARGET_LIBNAME ${EGPF_LIB_NAME}) set(PRI_TARGET_QTDEPS ${EGPF_DEPS}) if(IS_ABSOLUTE "${EGPF_INCLUDE_INSTALL_DIR}") set(PRI_TARGET_INCLUDES "${EGPF_INCLUDE_INSTALL_DIR}") else() set(PRI_TARGET_INCLUDES "${CMAKE_INSTALL_PREFIX}/${EGPF_INCLUDE_INSTALL_DIR}") endif() if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}") set(PRI_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}") else() set(PRI_TARGET_LIBS "${CMAKE_INSTALL_PREFIX}/${EGPF_LIB_INSTALL_DIR}") endif() set(PRI_TARGET_DEFINES "") set(PRI_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/qt_${PRI_TARGET_BASENAME}.pri) if (EGPF_FILENAME_VAR) set(${EGPF_FILENAME_VAR} ${PRI_FILENAME} PARENT_SCOPE) endif() file(GENERATE OUTPUT ${PRI_FILENAME} CONTENT "QT.${PRI_TARGET_BASENAME}.VERSION = ${PROJECT_VERSION_STRING} QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PROJECT_VERSION_MAJOR} QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PROJECT_VERSION_MINOR} QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PROJECT_VERSION_PATCH} QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME} QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES} QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES} QT.${PRI_TARGET_BASENAME}.private_includes = QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS} QT.${PRI_TARGET_BASENAME}.depends = ${PRI_TARGET_QTDEPS} " ) endfunction() gammaray-2.3.0/cmake/ECMQt4To5Porting.cmake000066400000000000000000000056611255003167400203370ustar00rootroot00000000000000#============================================================================= # Copyright 2005-2011 Kitware, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of Kitware, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= # Portability helpers. set(QT_QTGUI_LIBRARIES ${Qt5Gui_LIBRARIES} ${Qt5Widgets_LIBRARIES} ) set(QT_INCLUDES ${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5PrintSupport_INCLUDE_DIRS} ${Qt5Svg_INCLUDE_DIRS} ) set(QT_QTGUI_LIBRARY ${QT_QTGUI_LIBRARIES}) set(_qt_modules Core Widgets Script ScriptTools DBus Network Test Designer Concurrent Xml UiTools Quick1 WebKitWidgets Sql OpenGL Svg Declarative ) foreach(_module ${_qt_modules}) string(TOUPPER ${_module} _module_upper) set(QT_QT${_module_upper}_LIBRARIES ${Qt5${_module}_LIBRARIES}) set(QT_QT${_module_upper}_LIBRARY ${QT_QT${_module_upper}_LIBRARIES}) list(APPEND QT_INCLUDES ${Qt5${_module}_INCLUDE_DIRS}) set(QT_QT${_module_upper}_FOUND ${Qt5${_module}_FOUND}) endforeach() macro(qt4_wrap_ui) qt5_wrap_ui(${ARGN}) endmacro() macro(qt4_wrap_cpp) qt5_wrap_cpp(${ARGN}) endmacro() macro(qt4_add_dbus_adaptor) qt5_add_dbus_adaptor(${ARGN}) endmacro() macro(qt4_add_dbus_interfaces) qt5_add_dbus_interfaces(${ARGN}) endmacro() macro(qt4_add_dbus_interface) qt5_add_dbus_interface(${ARGN}) endmacro() macro(qt4_generate_dbus_interface) qt5_generate_dbus_interface(${ARGN}) endmacro() macro(qt4_add_resources) qt5_add_resources(${ARGN}) endmacro() gammaray-2.3.0/cmake/ECMQueryQmake.cmake000066400000000000000000000014311255003167400200070ustar00rootroot00000000000000find_package(Qt5Core QUIET) set(_qmake_executable_default "qmake-qt5") if (TARGET Qt5::qmake) get_target_property(_qmake_executable_default Qt5::qmake LOCATION) endif() set(QMAKE_EXECUTABLE ${_qmake_executable_default} CACHE FILEPATH "Location of the Qt5 qmake executable") # This is not public API (yet)! function(query_qmake result_variable qt_variable) execute_process( COMMAND ${QMAKE_EXECUTABLE} -query "${qt_variable}" RESULT_VARIABLE return_code OUTPUT_VARIABLE output ) if(return_code EQUAL 0) string(STRIP "${output}" output) file(TO_CMAKE_PATH "${output}" output_path) set(${result_variable} "${output_path}" PARENT_SCOPE) else() message(FATAL "QMake call failed: ${error}") endif() endfunction() gammaray-2.3.0/cmake/FindGraphviz.cmake000066400000000000000000000147311255003167400200000ustar00rootroot00000000000000# - Try to find Graphviz # Once done this will define # # GRAPHVIZ_FOUND - system has Graphviz # GRAPHVIZ_INCLUDE_DIR - the Graphviz include directory # GRAPHVIZ_LIBRARY - Link these to use Graphviz # GRAPHVIZ_VERSION = The value of PACKAGE_VERSION defined in graphviz_version.h # GRAPHVIZ_MAJOR_VERSION = The library major version number # GRAPHVIZ_MINOR_VERSION = The library minor version number # GRAPHVIZ_PATCH_VERSION = The library patch version number # GRAPHVIZ_COMPILE_FLAGS = List of compile flags needed by the GraphViz installation headers # # This module reads hints about search locations from the following env or cache variables: # GRAPHVIZ_ROOT - Graphviz installation prefix # (containing bin/, include/, etc.) # Copyright (c) 2009, Adrien Bustany, # Copyright (c) 2013-2015 Kevin Funk # Version computation and some cleanups by Allen Winter # Bug fixing for WIN32 by Guillaume Jacquenot # Copyright (c) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Redistribution and use is allowed according to the terms of the GPLv3+ license. include(CheckIncludeFiles) include(CMakePushCheckState) if(NOT GRAPHVIZ_MIN_VERSION) set(GRAPHVIZ_MIN_VERSION "2.00") endif() if(GRAPHVIZ_INCLUDE_DIR AND GRAPHVIZ_CDT_LIBRARY AND (GRAPHVIZ_CGRAPH_LIBRARY OR GRAPHVIZ_GRAPH_LIBRARY) AND GRAPHVIZ_PATHPLAN_LIBRARY) set(GRAPHVIZ_FIND_QUIETLY TRUE) endif() if (GRAPHVIZ_ROOT) set(_GRAPHVIZ_ROOT ${GRAPHVIZ_ROOT}) else() set(_GRAPHVIZ_ROOT $ENV{GRAPHVIZ_ROOT}) endif() if(NOT _GRAPHVIZ_ROOT) if(WIN32) find_program(DOT_TOOL dot) get_filename_component(_GRAPHVIZ_ROOT ${DOT_TOOL} PATH) endif() endif() if(_GRAPHVIZ_ROOT) set(_GRAPHVIZ_INCLUDE_DIR ${_GRAPHVIZ_ROOT}/include) set(_GRAPHVIZ_LIBRARY_DIR ${_GRAPHVIZ_ROOT}/lib) set(_GRAPHVIZ_FIND_OPTS NO_DEFAULT_PATH) else() set(_GRAPHVIZ_FIND_OPTS "") endif() find_path(GRAPHVIZ_INCLUDE_DIR NAMES graphviz/graph.h graphviz/cgraph.h HINTS ${_GRAPHVIZ_INCLUDE_DIR} ${_GRAPHVIZ_FIND_OPTS}) if(WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Release") set(GRAPHVIZ_LIB_PATH_SUFFIX "release/lib") else() set(GRAPHVIZ_LIB_PATH_SUFFIX "debug/lib") endif() else() set(GRAPHVIZ_LIB_PATH_SUFFIX) endif() find_library(GRAPHVIZ_CDT_LIBRARY NAMES cdt HINTS ${_GRAPHVIZ_LIBRARY_DIR} PATH_SUFFIXES ${GRAPHVIZ_LIB_PATH_SUFFIX} ${_GRAPHVIZ_FIND_OPTS}) find_library(GRAPHVIZ_GVC_LIBRARY NAMES gvc HINTS ${_GRAPHVIZ_LIBRARY_DIR} PATH_SUFFIXES ${GRAPHVIZ_LIB_PATH_SUFFIX} ${_GRAPHVIZ_FIND_OPTS}) find_library(GRAPHVIZ_CGRAPH_LIBRARY NAMES cgraph HINTS ${_GRAPHVIZ_LIBRARY_DIR} PATH_SUFFIXES ${GRAPHVIZ_LIB_PATH_SUFFIX} ${_GRAPHVIZ_FIND_OPTS}) find_library(GRAPHVIZ_GRAPH_LIBRARY NAMES graph HINTS ${_GRAPHVIZ_LIBRARY_DIR} PATH_SUFFIXES ${GRAPHVIZ_LIB_PATH_SUFFIX} ${_GRAPHVIZ_FIND_OPTS}) find_library(GRAPHVIZ_PATHPLAN_LIBRARY NAMES pathplan HINTS ${_GRAPHVIZ_LIBRARY_DIR} PATH_SUFFIXES ${GRAPHVIZ_LIB_PATH_SUFFIX} ${_GRAPHVIZ_FIND_OPTS}) cmake_push_check_state() set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${GRAPHVIZ_INCLUDE_DIR}) check_include_files(graphviz/graphviz_version.h HAVE_GRAPHVIZ_VERSION_H) cmake_pop_check_state() if(GRAPHVIZ_INCLUDE_DIR AND GRAPHVIZ_CDT_LIBRARY AND GRAPHVIZ_GVC_LIBRARY AND (GRAPHVIZ_CGRAPH_LIBRARY OR GRAPHVIZ_GRAPH_LIBRARY) AND GRAPHVIZ_PATHPLAN_LIBRARY) if(HAVE_GRAPHVIZ_VERSION_H OR WIN32) set(GRAPHVIZ_FOUND TRUE) endif() else() set(GRAPHVIZ_FOUND FALSE) endif() # Ok, now compute the version and make sure its greater then the min required if(GRAPHVIZ_FOUND) if(NOT WIN32) set(FIND_GRAPHVIZ_VERSION_SOURCE "#include \n#include \n int main()\n {\n printf(\"%s\",PACKAGE_VERSION);return 1;\n }\n") set(FIND_GRAPHVIZ_VERSION_SOURCE_FILE ${CMAKE_BINARY_DIR}/CMakeTmp/FindGRAPHVIZ.cxx) file(WRITE "${FIND_GRAPHVIZ_VERSION_SOURCE_FILE}" "${FIND_GRAPHVIZ_VERSION_SOURCE}") set(FIND_GRAPHVIZ_VERSION_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${GRAPHVIZ_INCLUDE_DIR}") if(NOT CMAKE_CROSSCOMPILING) try_run(RUN_RESULT COMPILE_RESULT ${CMAKE_BINARY_DIR} ${FIND_GRAPHVIZ_VERSION_SOURCE_FILE} CMAKE_FLAGS "${FIND_GRAPHVIZ_VERSION_ADD_INCLUDES}" RUN_OUTPUT_VARIABLE GRAPHVIZ_VERSION) endif() if(COMPILE_RESULT AND RUN_RESULT EQUAL 1 AND NOT CMAKE_CROSSCOMPILING) message(STATUS "Found Graphviz version ${GRAPHVIZ_VERSION}") if(${GRAPHVIZ_VERSION} VERSION_LESS ${GRAPHVIZ_MIN_VERSION}) message(STATUS "Graphviz version ${GRAPHVIZ_VERSION} is too old. At least version ${GRAPHVIZ_MIN_VERSION} is needed.") set(GRAPHVIZ_FOUND FALSE) set(GRAPHVIZ_INCLUDE_DIR "") set(GRAPHVIZ_CDT_LIBRARY "") set(GRAPHVIZ_GVC_LIBRARY "") set(GRAPHVIZ_CGRAPH_LIBRARY "") set(GRAPHVIZ_GRAPH_LIBRARY "") set(GRAPHVIZ_PATHPLAN_LIBRARY "") else(${GRAPHVIZ_VERSION} VERSION_LESS ${GRAPHVIZ_MIN_VERSION}) # Compute the major and minor version numbers if(NOT CMAKE_CROSSCOMPILING) string(REPLACE "." ";" VL ${GRAPHVIZ_VERSION}) list(GET VL 0 GRAPHVIZ_MAJOR_VERSION) list(GET VL 1 GRAPHVIZ_MINOR_VERSION) list(GET VL 2 GRAPHVIZ_PATCH_VERSION) endif() endif(${GRAPHVIZ_VERSION} VERSION_LESS ${GRAPHVIZ_MIN_VERSION}) else() if(NOT CMAKE_CROSSCOMPILING) message(FATAL_ERROR "Unable to compile or run the graphviz version detection program.") endif() endif() elseif(WIN32) find_program(DOT_TOOL dot PATHS ${_GRAPHVIZ_ROOT}/bin) execute_process(COMMAND ${DOT_TOOL} -V OUTPUT_VARIABLE DOT_VERSION_OUTPUT ERROR_VARIABLE DOT_VERSION_OUTPUT OUTPUT_QUIET) string(REGEX MATCH "([0-9]+\\.[0-9]+\\.[0-9]+)" GRAPHVIZ_VERSION "${DOT_VERSION_OUTPUT}") string(REPLACE "." ";" VL ${GRAPHVIZ_VERSION}) list(GET VL 0 GRAPHVIZ_MAJOR_VERSION) list(GET VL 1 GRAPHVIZ_MINOR_VERSION) list(GET VL 2 GRAPHVIZ_PATCH_VERSION) endif() set(GRAPHVIZ_COMPILE_FLAGS "") check_include_files(string.h HAVE_STRING_H) if (HAVE_STRING_H) list(APPEND GRAPHVIZ_COMPILE_FLAGS "-DHAVE_STRING_H=1") endif() if(NOT GRAPHVIZ_FIND_QUIETLY) message(STATUS "Found Graphviz: ${GRAPHVIZ_CDT_LIBRARY} ${GRAPHVIZ_GVC_LIBRARY} ${GRAPHVIZ_CGRAPH_LIBRARY} ${GRAPHVIZ_GRAPH_LIBRARY} ${GRAPHVIZ_PATHPLAN_LIBRARY}") endif() else() if(GRAPHVIZ_FIND_REQUIRED) message(FATAL_ERROR "Could NOT find Graphivz") endif() endif() gammaray-2.3.0/cmake/GammaRayMacros.cmake000066400000000000000000000023051255003167400202420ustar00rootroot00000000000000# # GAMMARAY_ADD_PLUGIN: create a gammaray plugin, install at the right place, etc # # Copyright (c) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. macro(gammaray_add_plugin _target_name _desktop_file) if(NOT PROBE_PLUGIN_INSTALL_DIR) # HACK for external plugins that don't set PLUGIN_INSTALL_DIR set(PROBE_PLUGIN_INSTALL_DIR ${GAMMARAY_PROBE_PLUGIN_INSTALL_DIR}) endif() set(_build_target_dir "${PROJECT_BINARY_DIR}/${PROBE_PLUGIN_INSTALL_DIR}") add_library(${_target_name} MODULE ${ARGN}) set_target_properties(${_target_name} PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${_build_target_dir} ) if(APPLE) set_target_properties(${_target_name} PROPERTIES INSTALL_RPATH "@loader_path/../../../Frameworks") endif() install(TARGETS ${_target_name} DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}) if(NOT ${Qt5Core_FOUND}) install(FILES ${_desktop_file} DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${_desktop_file}" "${_build_target_dir}/${_desktop_file}") endif() endmacro() gammaray-2.3.0/cmake/GammaRayMacrosInternal.cmake000066400000000000000000000044501255003167400217420ustar00rootroot00000000000000# GammaRay-specific CMake macros that don't make sense outside of the GammaRay source tree. # Copyright (c) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. macro(gammaray_install_headers) get_filename_component(_dir ${CMAKE_CURRENT_SOURCE_DIR} NAME) if(NOT GAMMARAY_PROBE_ONLY_BUILD) install(FILES ${ARGN} DESTINATION ${INCLUDE_INSTALL_DIR}/${_dir}) endif() set_directory_properties(PROPERTIES GAMMARAY_INSTALLED_HEADERS "${ARGN}") get_property(_include_dirs GLOBAL PROPERTY GAMMARAY_HEADER_DIRS) list(APPEND _include_dirs "${_dir}") set_property(GLOBAL PROPERTY GAMMARAY_HEADER_DIRS "${_include_dirs}") endmacro() macro(gammaray_all_installed_headers _var) set(${_var} "") get_property(_include_dirs GLOBAL PROPERTY GAMMARAY_HEADER_DIRS) foreach(_dir ${_include_dirs}) get_directory_property(_hdrs DIRECTORY ${CMAKE_SOURCE_DIR}/${_dir} GAMMARAY_INSTALLED_HEADERS) foreach(_hdr ${_hdrs}) list(APPEND ${_var} "${CMAKE_SOURCE_DIR}/${_dir}/${_hdr}") endforeach() endforeach() endmacro() macro(gammaray_join_list _var _sep) set(${_var} "") foreach(_element ${ARGN}) set(${_var} "${${_var}}${_sep}${_element}") endforeach() endmacro() macro(gammaray_inverse_dir _var _prefix) file(RELATIVE_PATH ${_var} "${CMAKE_INSTALL_PREFIX}/${_prefix}" "${CMAKE_INSTALL_PREFIX}") endmacro() # embed an Info.plist file into a non-bundled Mac executable macro(gammaray_embed_info_plist _target _plist) configure_file(${_plist} ${CMAKE_CURRENT_BINARY_DIR}/${_target}_Info.plist) if(APPLE) set_target_properties(${_target} PROPERTIES LINK_FLAGS "-sectcreate __TEXT __info_plist ${CMAKE_CURRENT_BINARY_DIR}/${_target}_Info.plist") endif() endmacro() # allow to use CMake FeatureSummary with "packages" that consist only of a minor inline check # rather than a fully-featured find module macro(gammaray_add_dummy_package _package _found) if(${_found}) set(_property_name "PACKAGES_FOUND") else() set(_property_name "PACKAGES_NOT_FOUND") endif() get_property(_packages GLOBAL PROPERTY ${_property_name}) list(APPEND _packages ${_package}) set_property(GLOBAL PROPERTY ${_property_name} "${_packages}") endmacro() gammaray-2.3.0/cmake/GammaRayProbeABI.cmake000066400000000000000000000042041255003167400204010ustar00rootroot00000000000000# Determine probe ABI identifier # # Copyright (c) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. # This contains all properties that define ABI compatibility of a probe with a target # Qt version if(Qt5Core_FOUND) set(GAMMARAY_PROBE_ABI "qt${Qt5Core_VERSION_MAJOR}.${Qt5Core_VERSION_MINOR}") else() set(GAMMARAY_PROBE_ABI "qt${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}") endif() # on Windows, the compiler also matters if(WIN32) set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-${CMAKE_CXX_COMPILER_ID}") endif() # debug vs. release (MSVC only) if(MSVC) if(CMAKE_BUILD_TYPE MATCHES "^[Rr]el") set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-release") else() set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-debug") endif() endif() # processor architecture # this is a bit messy since CMAKE_SYSTEM_PROCESSOR seems to contain the host CPU rather than the target architecture sometimes # and is empty on cross-builds by default if(NOT CMAKE_SYSTEM_PROCESSOR) message(FATAL_ERROR "Unknown target architecture. Make sure to specify CMAKE_SYSTEM_PROCESSOR in your toolchain file!") endif() # on Windows our best bet is CMAKE_SIZEOF_VOID_P and assuming a x86 host==target build if(WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-x86_64") else() set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-i686") endif() # on Mac we apparently always get i386 on x86 elseif(APPLE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "i386" AND CMAKE_SIZEOF_VOID_P EQUAL 8) set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-x86_64") else() set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-${CMAKE_SYSTEM_PROCESSOR}") endif() else() # uname reports different ARM versions, unlike ELF, so map all this to "arm" if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-arm") else() set(GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}-${CMAKE_SYSTEM_PROCESSOR}") endif() endif() message(STATUS "Building probe for ABI: ${GAMMARAY_PROBE_ABI}") gammaray-2.3.0/cmake/Toolchain-GCC-i686.cmake000066400000000000000000000006401255003167400204030ustar00rootroot00000000000000# Toolchain file for 32bit builds on 64bit hosts # # Copyright (c) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. set(CMAKE_SYSTEM_NAME "Linux") set(CMAKE_SYSTEM_PROCESSOR "i686") set(CMAKE_C_COMPILER_ARG1 "-m32") set(CMAKE_CXX_COMPILER_ARG1 "-m32") gammaray-2.3.0/cmake/Toolchain-QNX65.cmake000066400000000000000000000065251255003167400201460ustar00rootroot00000000000000# # (C) Copyright 2009 Johns Hopkins University (JHU), All Rights # Reserved. # # --- begin cisst license - do not edit --- # # This software is provided "as is" under an open source license, with # no warranty. The complete license can be found in license.txt and # http://www.cisst.org/cisst/license.txt. # # --- end cisst license --- SET(CMAKE_SYSTEM_NAME QNX) SET(CMAKE_SYSTEM_VERSION 6.5.0) SET(CMAKE_SYSTEM_PROCESSOR x86) SET(TOOLCHAIN QNX) #SET(CMAKE_IMPORT_LIBRARY_SUFFIX ".a") SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") SET(CMAKE_STATIC_LIBRARY_PREFIX "lib") SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a") IF(CMAKE_HOST_WIN32) SET(HOST_EXECUTABLE_SUFFIX ".exe") ENDIF(CMAKE_HOST_WIN32) FIND_PATH(QNX_HOST NAME usr/bin/qcc${HOST_EXECUTABLE_SUFFIX} PATHS $ENV{QNX_HOST} C:/QNX650/host/win32/x86 NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) FIND_PATH(QNX_TARGET NAME usr/include/qnx_errno.h PATHS $ENV{QNX_TARGET} C:/QNX650/target/qnx6 NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) IF(CMAKE_HOST_WIN32) FIND_PATH(QNX_CONFIGURATION NAME bin/qnxactivate.exe PATHS $ENV{QNX_CONFIGURATION} "C:/Program Files/QNX Software Systems/qconfig" NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) ENDIF(CMAKE_HOST_WIN32) SET(ENV{QNX_HOST} ${QNX_HOST}) SET(ENV{QNX_TARGET} ${QNX_TARGET}) IF(CMAKE_HOST_WIN32) SET(ENV{QNX_CONFIGURATION} ${QNX_CONFIGURATION}) SET(ENV{PATH} "$ENV{PATH};${QNX_HOST}/usr/bin") ENDIF(CMAKE_HOST_WIN32) SET(CMAKE_MAKE_PROGRAM "${QNX_HOST}/usr/bin/make${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX Make Program") SET(CMAKE_SH "${QNX_HOST}/usr/bin/sh${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX shell Program") SET(CMAKE_AR "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ar Program") SET(CMAKE_RANLIB "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ranlib Program") SET(CMAKE_NM "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-nm${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX nm Program") SET(CMAKE_OBJCOPY "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objcopy${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX objcopy Program") SET(CMAKE_OBJDUMP "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objdump${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX objdump Program") SET(CMAKE_LINKER "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ld" CACHE PATH "QNX Linker Program") SET(CMAKE_STRIP "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-strip${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX Strip Program") SET(CMAKE_C_COMPILER ${QNX_HOST}/usr/bin/qcc) SET(CMAKE_C_FLAGS_DEBUG "-g") SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") SET(CMAKE_CXX_COMPILER ${QNX_HOST}/usr/bin/qcc) SET(CMAKE_CXX_FLAGS_DEBUG "-g") SET(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") SET(CMAKE_FIND_ROOT_PATH ${QNX_TARGET}) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(CMAKE_C_FLAGS "-Vgcc_ntoarmv7le" CACHE STRING "qcc c flags" FORCE) SET(CMAKE_CXX_FLAGS "-Vgcc_ntoarmv7le -lang-c++" CACHE STRING "qcc cxx flags" FORCE) gammaray-2.3.0/cmake/Toolchain-QNX66.cmake000066400000000000000000000066561255003167400201540ustar00rootroot00000000000000# # (C) Copyright 2009 Johns Hopkins University (JHU), All Rights # Reserved. # # --- begin cisst license - do not edit --- # # This software is provided "as is" under an open source license, with # no warranty. The complete license can be found in license.txt and # http://www.cisst.org/cisst/license.txt. # # --- end cisst license --- SET(CMAKE_SYSTEM_NAME QNX) SET(CMAKE_SYSTEM_VERSION 6.6.0) SET(CMAKE_SYSTEM_PROCESSOR armv7) SET(TOOLCHAIN QNX) #SET(CMAKE_IMPORT_LIBRARY_SUFFIX ".a") SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") SET(CMAKE_STATIC_LIBRARY_PREFIX "lib") SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a") IF(CMAKE_HOST_WIN32) SET(HOST_EXECUTABLE_SUFFIX ".exe") ENDIF(CMAKE_HOST_WIN32) FIND_PATH(QNX_HOST NAME usr/bin/qcc${HOST_EXECUTABLE_SUFFIX} PATHS $ENV{QNX_HOST} C:/qnx660/host/win32/x86 NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) FIND_PATH(QNX_TARGET NAME usr/include/qconfig.mk PATHS $ENV{QNX_TARGET} C:/qnx660/target/qnx6 NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) IF(CMAKE_HOST_WIN32) FIND_PATH(QNX_CONFIGURATION NAME bin/qnxactivate.exe PATHS $ENV{QNX_CONFIGURATION} "C:/Program Files/QNX Software Systems/qconfig" NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) ENDIF(CMAKE_HOST_WIN32) SET(ENV{QNX_HOST} ${QNX_HOST}) SET(ENV{QNX_TARGET} ${QNX_TARGET}) IF(CMAKE_HOST_WIN32) SET(ENV{QNX_CONFIGURATION} ${QNX_CONFIGURATION}) SET(ENV{PATH} "$ENV{PATH};${QNX_HOST}/usr/bin") ENDIF(CMAKE_HOST_WIN32) SET(CMAKE_MAKE_PROGRAM "${QNX_HOST}/usr/bin/make${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX Make Program") SET(CMAKE_SH "${QNX_HOST}/usr/bin/sh${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX shell Program") SET(CMAKE_AR "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ar Program") SET(CMAKE_RANLIB "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ranlib Program") SET(CMAKE_NM "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-nm${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX nm Program") SET(CMAKE_OBJCOPY "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objcopy${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX objcopy Program") SET(CMAKE_OBJDUMP "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-objdump${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX objdump Program") SET(CMAKE_LINKER "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ld${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX Linker Program") SET(CMAKE_STRIP "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-strip${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX Strip Program") SET(CMAKE_C_COMPILER ${QNX_HOST}/usr/bin/qcc${HOST_EXECUTABLE_SUFFIX}) SET(CMAKE_C_FLAGS_DEBUG "-g") SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") SET(CMAKE_CXX_COMPILER ${QNX_HOST}/usr/bin/qcc${HOST_EXECUTABLE_SUFFIX}) SET(CMAKE_CXX_FLAGS_DEBUG "-g") SET(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") SET(CMAKE_FIND_ROOT_PATH ${QNX_TARGET}) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(CMAKE_C_FLAGS "-Vgcc_ntoarmv7le -fPIC" CACHE STRING "qcc c flags" FORCE) SET(CMAKE_CXX_FLAGS "-Vgcc_ntoarmv7le -lang-c++ -fPIC" CACHE STRING "qcc cxx flags" FORCE) gammaray-2.3.0/cmake/Toolchain-RPI.cmake000066400000000000000000000016731255003167400177560ustar00rootroot00000000000000# Basic cmake toolchain file for RaspberryPi # Assumptions: toolchain is in path, $SYSROOT points to the sysroot # # Copyright (c) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. set(CMAKE_SYSTEM_NAME "Linux") set(CMAKE_SYSTEM_PROCESSOR "armv6l") set(CMAKE_C_COMPILER "arm-linux-gnueabihf-gcc") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_FIND_ROOT_PATH "$ENV{SYSROOT}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) gammaray-2.3.0/cmake/Toolchain-android.cmake000066400000000000000000002401521255003167400207410ustar00rootroot00000000000000# Copyright (c) 2010-2011, Ethan Rublee # Copyright (c) 2011-2014, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # Android CMake toolchain file, for use with the Android NDK r5-r10d # Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk # $ mkdir build && cd build # $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. # $ make -j8 # # Usage Windows: # You need native port of make to build your project. # Android NDK r7 (and newer) already has make.exe on board. # For older NDK you have to install it separately. # For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm # # $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk # $ mkdir build && cd build # $ cmake.exe -G"MinGW Makefiles" # -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake # -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. # $ cmake.exe --build . # # # Options (can be set as cmake parameters: -D=): # ANDROID_NDK=/opt/android-ndk - path to the NDK root. # Can be set as environment variable. Can be set only at first cmake run. # # ANDROID_ABI=armeabi-v7a - specifies the target Application Binary # Interface (ABI). This option nearly matches to the APP_ABI variable # used by ndk-build tool from Android NDK. # # Possible targets are: # "armeabi" - ARMv5TE based CPU with software floating point operations # "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions # this ABI target is used by default # "armeabi-v7a with NEON" - same as armeabi-v7a, but # sets NEON as floating-point unit # "armeabi-v7a with VFPV3" - same as armeabi-v7a, but # sets VFPV3 as floating-point unit (has 32 registers instead of 16) # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP # "x86" - IA-32 instruction set # "mips" - MIPS32 instruction set # # 64-bit ABIs for NDK r10 and newer: # "arm64-v8a" - ARMv8 AArch64 instruction set # "x86_64" - Intel64 instruction set (r1) # "mips64" - MIPS64 instruction set (r6) # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. # Option is read-only when standalone toolchain is used. # Note: building for "android-L" requires explicit configuration. # # ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler # toolchain to be used. The list of possible values depends on the NDK # version. For NDK r10c the possible values are: # # * aarch64-linux-android-4.9 # * aarch64-linux-android-clang3.4 # * aarch64-linux-android-clang3.5 # * arm-linux-androideabi-4.6 # * arm-linux-androideabi-4.8 # * arm-linux-androideabi-4.9 (default) # * arm-linux-androideabi-clang3.4 # * arm-linux-androideabi-clang3.5 # * mips64el-linux-android-4.9 # * mips64el-linux-android-clang3.4 # * mips64el-linux-android-clang3.5 # * mipsel-linux-android-4.6 # * mipsel-linux-android-4.8 # * mipsel-linux-android-4.9 # * mipsel-linux-android-clang3.4 # * mipsel-linux-android-clang3.5 # * x86-4.6 # * x86-4.8 # * x86-4.9 # * x86-clang3.4 # * x86-clang3.5 # * x86_64-4.9 # * x86_64-clang3.4 # * x86_64-clang3.5 # # ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions # instead of Thumb. Is not available for "armeabi-v6 with VFP" # (is forced to be ON) ABI. # # ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker # errors even if they are not used. # # ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared # libraries. Automatically turned for NDK r5x and r6x due to GLESv2 # problems. # # ANDROID_STL=gnustl_static - specify the runtime to use. # # Possible values are: # none -> Do not configure the runtime. # system -> Use the default minimal system C++ runtime library. # Implies -fno-rtti -fno-exceptions. # Is not available for standalone toolchain. # system_re -> Use the default minimal system C++ runtime library. # Implies -frtti -fexceptions. # Is not available for standalone toolchain. # gabi++_static -> Use the GAbi++ runtime as a static library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # gabi++_shared -> Use the GAbi++ runtime as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_static -> Use the STLport runtime as a static library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_shared -> Use the STLport runtime as a shared library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # gnustl_static -> Use the GNU STL as a static library. # Implies -frtti -fexceptions. # gnustl_shared -> Use the GNU STL as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7b and newer. # Silently degrades to gnustl_static if not available. # # ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on # chosen runtime. If disabled, then the user is responsible for settings # these options. # # What?: # android-cmake toolchain searches for NDK/toolchain in the following order: # ANDROID_NDK - cmake parameter # ANDROID_NDK - environment variable # ANDROID_STANDALONE_TOOLCHAIN - cmake parameter # ANDROID_STANDALONE_TOOLCHAIN - environment variable # ANDROID_NDK - default locations # ANDROID_STANDALONE_TOOLCHAIN - default locations # # Make sure to do the following in your scripts: # SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) # SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) # The flags will be prepopulated with critical flags, so don't loose them. # Also be aware that toolchain also sets configuration-specific compiler # flags and linker flags. # # ANDROID and BUILD_ANDROID will be set to true, you may test any of these # variables to make necessary Android-specific configuration changes. # # Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 # will be set true, mutually exclusive. NEON option will be set true # if VFP is set to NEON. # # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) if( DEFINED CMAKE_CROSSCOMPILING ) # subsequent toolchain loading is not really needed return() endif() if( CMAKE_TOOLCHAIN_FILE ) # touch toolchain variable to suppress "unused variable" warning endif() # inherit settings in recursive loads get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) if( _CMAKE_IN_TRY_COMPILE ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) endif() # this one is important if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) set( CMAKE_SYSTEM_NAME Android ) else() set( CMAKE_SYSTEM_NAME Linux ) endif() # this one not so much set( CMAKE_SYSTEM_VERSION 1 ) # rpath makes low sense for Android set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) # NDK search paths set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS ) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" ) else() file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" ) endif() endif() if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) endif() # known ABIs set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) set( ANDROID_SUPPORTED_ABIS_mips "mips" ) set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) # API level defaults set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) macro( __LIST_FILTER listvar regex ) if( ${listvar} ) foreach( __val ${${listvar}} ) if( __val MATCHES "${regex}" ) list( REMOVE_ITEM ${listvar} "${__val}" ) endif() endforeach() endif() endmacro() macro( __INIT_VARIABLE var_name ) set( __test_path 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "PATH" ) set( __test_path 1 ) break() endif() endforeach() if( __test_path AND NOT EXISTS "${${var_name}}" ) unset( ${var_name} CACHE ) endif() if( " ${${var_name}}" STREQUAL " " ) set( __values 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "VALUES" ) set( __values 1 ) elseif( NOT __var STREQUAL "PATH" ) if( __var MATCHES "^ENV_.*$" ) string( REPLACE "ENV_" "" __var "${__var}" ) set( __value "$ENV{${__var}}" ) elseif( DEFINED ${__var} ) set( __value "${${__var}}" ) elseif( __values ) set( __value "${__var}" ) else() set( __value "" ) endif() if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") ) set( ${var_name} "${__value}" ) break() endif() endif() endforeach() unset( __value ) unset( __values ) endif() if( __test_path ) file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) endif() unset( __test_path ) endmacro() macro( __DETECT_NATIVE_API_LEVEL _var _path ) set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) if( NOT __apiFileContent ) message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) endif() string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) unset( __apiFileContent ) unset( __ndkApiLevelRegex ) endmacro() macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) if( EXISTS "${_root}" ) file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) __LIST_FILTER( __gccExePath "^[.].*" ) list( LENGTH __gccExePath __gccExePathsCount ) if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "Could not determine machine name for compiler from ${_root}" ) set( ${_var} "" ) else() get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) endif() unset( __gccExePath ) unset( __gccExePathsCount ) unset( __gccExeName ) else() set( ${_var} "" ) endif() endmacro() # fight against cygwin set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") mark_as_advanced( ANDROID_FORBID_SYGWIN ) if( ANDROID_FORBID_SYGWIN ) if( CYGWIN ) message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) endif() if( CMAKE_HOST_WIN32 ) # remove cygwin from PATH set( __new_path "$ENV{PATH}") __LIST_FILTER( __new_path "cygwin" ) set(ENV{PATH} "${__new_path}") unset(__new_path) endif() endif() # detect current host platform if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() if( NOT ANDROID_NDK_HOST_X64 ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) endif() # see if we have path to Android NDK if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN ) __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) endif() if( NOT ANDROID_NDK ) # see if we have path to Android standalone toolchain __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN ) if( NOT ANDROID_STANDALONE_TOOLCHAIN ) #try to find Android NDK in one of the the default locations set( __ndkSearchPaths ) foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" ) endforeach() endforeach() __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) unset( __ndkSearchPaths ) if( ANDROID_NDK ) message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) else() #try to find Android standalone toolchain in one of the the default locations __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) if( ANDROID_STANDALONE_TOOLCHAIN ) message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) endif( ANDROID_STANDALONE_TOOLCHAIN ) endif( ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) # remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) set( BUILD_WITH_ANDROID_NDK True ) if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) else() set( ANDROID_NDK_RELEASE "r1x" ) set( ANDROID_NDK_RELEASE_FULL "unreleased" ) endif() string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) # try to detect change if( CMAKE_AR ) string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) endif() unset( __androidStandaloneToolchainPreviousPath ) unset( __length ) endif() set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) else() list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. You should either set an environment variable: export ANDROID_NDK=~/my-android-ndk or export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain or put the toolchain or NDK in the default path: sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() # android NDK layout if( BUILD_WITH_ANDROID_NDK ) if( NOT DEFINED ANDROID_NDK_LAYOUT ) # try to automatically detect the layout if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") set( ANDROID_NDK_LAYOUT "RELEASE" ) elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) set( ANDROID_NDK_LAYOUT "LINARO" ) elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) set( ANDROID_NDK_LAYOUT "ANDROID" ) endif() endif() set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) mark_as_advanced( ANDROID_NDK_LAYOUT ) if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) endif() get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) # try to detect change of NDK if( CMAKE_AR ) string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. " ) endif() unset( __androidNdkPreviousPath ) unset( __length ) endif() endif() # get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) set( __availableToolchains "standalone" ) __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) if( NOT __availableToolchainMachines ) message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) endif() if( __availableToolchainMachines MATCHES x86_64 ) set( __availableToolchainArchs "x86_64" ) elseif( __availableToolchainMachines MATCHES i686 ) set( __availableToolchainArchs "x86" ) elseif( __availableToolchainMachines MATCHES aarch64 ) set( __availableToolchainArchs "arm64" ) elseif( __availableToolchainMachines MATCHES arm ) set( __availableToolchainArchs "arm" ) elseif( __availableToolchainMachines MATCHES mips64el ) set( __availableToolchainArchs "mips64" ) elseif( __availableToolchainMachines MATCHES mipsel ) set( __availableToolchainArchs "mips" ) endif() execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) list( APPEND __availableToolchains "standalone-clang" ) list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) endif() endif() macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) foreach( __toolchain ${${__availableToolchainsLst}} ) if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) if( __toolchainVersionStr ) string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) else() string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) endif() unset( __toolchainVersionStr ) unset( __toolchainVersionRegex ) else() set( __gcc_toolchain "${__toolchain}" ) endif() __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) if( __machine ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) if( __machine MATCHES x86_64 ) set( __arch "x86_64" ) elseif( __machine MATCHES i686 ) set( __arch "x86" ) elseif( __machine MATCHES aarch64 ) set( __arch "arm64" ) elseif( __machine MATCHES arm ) set( __arch "arm" ) elseif( __machine MATCHES mips64el ) set( __arch "mips64" ) elseif( __machine MATCHES mipsel ) set( __arch "mips" ) else() set( __arch "" ) endif() #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") if (__arch) list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) list( APPEND __availableToolchainCompilerVersions "${__version}" ) list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) endif() endif() unset( __gcc_toolchain ) endforeach() endmacro() # get all the details about NDK if( BUILD_WITH_ANDROID_NDK ) file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) set( __availableToolchains "" ) set( __availableToolchainMachines "" ) set( __availableToolchainArchs "" ) set( __availableToolchainCompilerVersions "" ) if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) # do not go through all toolchains if we know the name set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) if( __availableToolchains ) list(SORT __availableToolchainsLst) # we need clang to go after gcc endif() __LIST_FILTER( __availableToolchainsLst "^[.]" ) __LIST_FILTER( __availableToolchainsLst "llvm" ) __LIST_FILTER( __availableToolchainsLst "renderscript" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) endif() endif() # build list of available ABIs set( ANDROID_SUPPORTED_ABIS "" ) set( __uniqToolchainArchNames ${__availableToolchainArchs} ) list( REMOVE_DUPLICATES __uniqToolchainArchNames ) list( SORT __uniqToolchainArchNames ) foreach( __arch ${__uniqToolchainArchNames} ) list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) endforeach() unset( __uniqToolchainArchNames ) if( NOT ANDROID_SUPPORTED_ABIS ) message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) endif() # choose target ABI __INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} ) # verify that target ABI is supported list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) if( __androidAbiIdx EQUAL -1 ) string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" " ) endif() unset( __androidAbiIdx ) # set target ABI options if( ANDROID_ABI STREQUAL "x86" ) set( X86 true ) set( ANDROID_NDK_ABI_NAME "x86" ) set( ANDROID_ARCH_NAME "x86" ) set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "i686" ) elseif( ANDROID_ABI STREQUAL "x86_64" ) set( X86 true ) set( X86_64 true ) set( ANDROID_NDK_ABI_NAME "x86_64" ) set( ANDROID_ARCH_NAME "x86_64" ) set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) elseif( ANDROID_ABI STREQUAL "mips64" ) set( MIPS64 true ) set( ANDROID_NDK_ABI_NAME "mips64" ) set( ANDROID_ARCH_NAME "mips64" ) set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips64" ) elseif( ANDROID_ABI STREQUAL "mips" ) set( MIPS true ) set( ANDROID_NDK_ABI_NAME "mips" ) set( ANDROID_ARCH_NAME "mips" ) set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips" ) elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) set( ARM64_V8A true ) set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) set( ANDROID_ARCH_NAME "arm64" ) set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) set( VFPV3 true ) set( NEON true ) elseif( ANDROID_ABI STREQUAL "armeabi" ) set( ARMEABI true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) set( ARMEABI_V6 true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv6" ) # need always fallback to older platform set( ARMEABI true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a") set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) set( NEON true ) else() message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) endif() if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) # really dirty hack # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) endif() if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF ) set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) else() unset( ANDROID_FORCE_ARM_BUILD CACHE ) endif() # choose toolchain if( ANDROID_TOOLCHAIN_NAME ) list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) if( __toolchainIdx EQUAL -1 ) list( SORT __availableToolchains ) string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) set( toolchains_list " * ${toolchains_list}") message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) endif() list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) endif() else() set( __toolchainIdx -1 ) set( __applicableToolchains "" ) set( __toolchainMaxVersion "0.0.0" ) list( LENGTH __availableToolchains __availableToolchainsCount ) math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) foreach( __idx RANGE ${__availableToolchainsCount} ) list( GET __availableToolchainArchs ${__idx} __toolchainArch ) if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) set( __toolchainMaxVersion "${__toolchainVersion}" ) set( __toolchainIdx ${__idx} ) endif() endif() endforeach() unset( __availableToolchainsCount ) unset( __toolchainMaxVersion ) unset( __toolchainVersion ) endif() unset( __toolchainArch ) if( __toolchainIdx EQUAL -1 ) message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) endif() list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) unset( __toolchainIdx ) unset( __availableToolchains ) unset( __availableToolchainMachines ) unset( __availableToolchainArchs ) unset( __availableToolchainCompilerVersions ) # choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) # adjust API level set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) set( __real_api_level ${__level} ) endif() endforeach() if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) endif() unset(__real_api_level) # validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) else() if( BUILD_WITH_ANDROID_NDK ) __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) endif() unset( __realApiLevel ) endif() set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) endif() endif() unset( __levelIdx ) # remember target ABI set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) endif() # runtime choice (STL, rtti, exceptions) if( NOT ANDROID_STL ) set( ANDROID_STL gnustl_static ) endif() set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) if( BUILD_WITH_ANDROID_NDK ) if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. system -> Use the default minimal system C++ runtime library. system_re -> Same as system but with rtti and exceptions. gabi++_static -> Use the GAbi++ runtime as a static library. gabi++_shared -> Use the GAbi++ runtime as a shared library. stlport_static -> Use the STLport runtime as a static library. stlport_shared -> Use the STLport runtime as a shared library. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() endif() unset( ANDROID_RTTI ) unset( ANDROID_EXCEPTIONS ) unset( ANDROID_STL_INCLUDE_DIRS ) unset( __libstl ) unset( __libsupcxx ) if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). You are strongly recommended to switch to another NDK release. " ) endif() if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h index 5e28c64..65892a1 100644 --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h @@ -51,7 +51,11 @@ typedef long int ssize_t; #endif #ifndef _PTRDIFF_T #define _PTRDIFF_T -typedef long ptrdiff_t; +# ifdef __ANDROID__ + typedef int ptrdiff_t; +# else + typedef long ptrdiff_t; +# endif #endif " ) endif() # setup paths and STL for standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) # old location ( pre r8c ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) else() list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) endif() # always search static GNU STL to get the location of libsupc++.a if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) endif() if( __libstl ) set( __libsupcxx "${__libstl}/libsupc++.a" ) set( __libstl "${__libstl}/libstdc++.a" ) endif() if( NOT EXISTS "${__libsupcxx}" ) message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. You need to either upgrade to newer NDK or manually copy $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a to ${__libsupcxx} " ) endif() if( ANDROID_STL STREQUAL "gnustl_shared" ) if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) endif() endif() endif() endif() # clang if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) set( ANDROID_COMPILER_IS_CLANG 1 ) execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) message( FATAL_ERROR "Could not find the Clang compiler driver" ) endif() set( ANDROID_COMPILER_IS_CLANG 1 ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) else() set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) unset( ANDROID_COMPILER_IS_CLANG CACHE ) endif() string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) set( _clang_name "clang" ) endif() # setup paths and STL for NDK if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) if( ANDROID_STL STREQUAL "none" ) # do nothing elseif( ANDROID_STL STREQUAL "system" ) set( ANDROID_RTTI OFF ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL STREQUAL "system_re" ) set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL MATCHES "gabi" ) if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") endif() set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) elseif( ANDROID_STL MATCHES "stlport" ) if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d set( ANDROID_EXCEPTIONS ON ) else() set( ANDROID_EXCEPTIONS OFF ) endif() if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 set( ANDROID_RTTI OFF ) else() set( ANDROID_RTTI ON ) endif() set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) elseif( ANDROID_STL MATCHES "gnustl" ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_RTTI ON ) if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) # gnustl binary for 4.7 compiler is buggy :( # TODO: look for right fix set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) endif() else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) endif() set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" ) if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) else() set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) endif() else() message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) endif() # find libsupc++.a - rtti & exceptions if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer if( NOT EXISTS "${__libsupcxx}" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 endif() if( NOT EXISTS "${__libsupcxx}" ) # before r7 if( ARMEABI_V7A ) if( ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) endif() elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) endif() endif() if( NOT EXISTS "${__libsupcxx}") message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") endif() endif() endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) # TODO: check if .so file exists before the renaming endif() # ccache support __INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) if( _ndk_ccache ) if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) unset( NDK_CCACHE CACHE ) endif() find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") else() unset( NDK_CCACHE CACHE ) endif() unset( _ndk_ccache ) # setup the cross-compiler if( NOT CMAKE_C_COMPILER ) if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") endif() else() if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) endif() endif() set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) endif() set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) if( CMAKE_VERSION VERSION_LESS 2.8.5 ) set( CMAKE_ASM_COMPILER_ARG1 "-c" ) endif() if( APPLE ) find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) if( NOT CMAKE_INSTALL_NAME_TOOL ) message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) endif() mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) endif() # Force set compilers because standard identification works badly for us include( CMakeForceCompiler ) CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ID Clang ) endif() set( CMAKE_C_PLATFORM_ID Linux ) if( X86_64 OR MIPS64 OR ARM64_V8A ) set( CMAKE_C_SIZEOF_DATA_PTR 8 ) else() set( CMAKE_C_SIZEOF_DATA_PTR 4 ) endif() set( CMAKE_C_HAS_ISYSROOT 1 ) set( CMAKE_C_COMPILER_ABI ELF ) CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_CXX_COMPILER_ID Clang) endif() set( CMAKE_CXX_PLATFORM_ID Linux ) set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) set( CMAKE_CXX_HAS_ISYSROOT 1 ) set( CMAKE_CXX_COMPILER_ABI ELF ) set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) # force ASM compiler (required for CMake < 2.8.5) set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) set( CMAKE_ASM_COMPILER_ID GNU ) set( CMAKE_ASM_COMPILER_WORKS TRUE ) set( CMAKE_ASM_COMPILER_FORCED TRUE ) set( CMAKE_COMPILER_IS_GNUASM 1) set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) foreach( lang C CXX ASM ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} ) else() set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} ) endif() endforeach() # flags and definitions remove_definitions( -DANDROID ) add_definitions( -DANDROID ) if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) if( CMAKE_HOST_WIN32 ) # try to convert path to 8.3 form file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE __result ERROR_QUIET ) if( __result EQUAL 0 ) file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) else() set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) endif() else() set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) endif() if( NOT _CMAKE_IN_TRY_COMPILE ) # quotes can break try_compile and compiler identification message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") endif() else() set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) endif() # NDK flags if (ARM64_V8A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif( ARMEABI OR ARMEABI_V7A) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) endif() else() # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() endif() elseif( X86 OR X86_64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) elseif( MIPS OR MIPS64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif() set( ANDROID_CXX_FLAGS_RELEASE "" ) set( ANDROID_CXX_FLAGS_DEBUG "" ) endif() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) endif() if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ endif() # ABI-specific flags if( ARMEABI_V7A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) if( NEON ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) elseif( VFPV3 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) endif() elseif( ARMEABI_V6 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) endif() if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) else() set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) endif() # STL if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) if( EXISTS "${__libstl}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) endif() if( EXISTS "${__libsupcxx}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) # C objects: set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) set( CMAKE_C_LINK_EXECUTABLE " -o " ) set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) endif() if( ANDROID_STL MATCHES "gnustl" ) if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) set( ANDROID_LIBM_PATH -lm ) endif() set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) endif() endif() # variables controlling optional build flags if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. # So this flag option is required for all projects using OpenGL from native. __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) else() __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) endif() __INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON ) __INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) __INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) __INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) __INIT_VARIABLE( ANDROID_RELRO VALUES ON ) set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" ) set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) # linker flags set( ANDROID_LINKER_FLAGS "" ) if( ARMEABI_V7A ) # this is *required* to use the following linker flags that routes around # a CPU bug in some Cortex-A8 implementations: set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) endif() if( ANDROID_NO_UNDEFINED ) if( MIPS ) # there is some sysroot-related problem in mips linker... if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) endif() else() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() if( ANDROID_SO_UNDEFINED ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) endif() if( ANDROID_FUNCTION_LEVEL_LINKING ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) endif() if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 On Linux and OS X host platform you can workaround this problem using gold linker (default). Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. " ) endif() endif() # version 4.6 if( ANDROID_NOEXECSTACK ) if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) endif() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) endif() if( ANDROID_RELRO ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) endif() if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) endif() endif() # cache flags set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) # put flags to cache (for debug purpose only) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) endif() # pie/pic if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) ) set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") else() set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) endif() # configure rtti if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_RTTI ) set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) endif() endif() # configure exceptios if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_EXCEPTIONS ) set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) endif() endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "-shared" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) separate_arguments( __cmd ) foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) if( ${__var} ) set( __tmp "${${__var}}" ) separate_arguments( __tmp ) string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") endif() endforeach() string( REPLACE "'" "" __cmd "${__cmd}" ) string( REPLACE "\"" "" __cmd "${__cmd}" ) execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) if( __cmd_result EQUAL 0 ) set( ANDROID_EXPLICIT_CRT_LINK ON ) else() set( ANDROID_EXPLICIT_CRT_LINK OFF ) endif() endif() if( ANDROID_EXPLICIT_CRT_LINK ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) endif() # setup output directories set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) if( DEFINED LIBRARY_OUTPUT_PATH_ROOT OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml" OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") ) set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" ) if( NOT _CMAKE_IN_TRY_COMPILE ) if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) else() set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) endif() set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" ) endif() endif() # copy shaed stl library to build directory if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH ) get_filename_component( __libstlname "${__libstl}" NAME ) execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) endif() unset( __fileCopyProcess ) unset( __libstlname ) endif() # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) # where is the target environment set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) # only search for libraries and includes in the ndk toolchain set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) # macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_package( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_program( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # export toolchain settings for the try_compile() command if( NOT _CMAKE_IN_TRY_COMPILE ) set( __toolchain_config "") foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_NDK_HOST_X64 ANDROID_NDK ANDROID_NDK_LAYOUT ANDROID_STANDALONE_TOOLCHAIN ANDROID_TOOLCHAIN_NAME ANDROID_ABI ANDROID_NATIVE_API_LEVEL ANDROID_STL ANDROID_STL_FORCE_FEATURES ANDROID_FORCE_ARM_BUILD ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ANDROID_LIBM_PATH ANDROID_EXPLICIT_CRT_LINK ANDROID_APP_PIE ) if( DEFINED ${__var} ) if( ${__var} MATCHES " ") set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) else() set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) endif() endif() endforeach() file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) unset( __toolchain_config ) endif() # force cmake to produce / instead of \ in build commands for Ninja generator if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) # it is a bad hack after all # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion enable_language( C ) enable_language( CXX ) # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it unset( MINGW ) endif() # Variables controlling behavior or set by cmake toolchain: # ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" # ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) # ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none # ANDROID_FORBID_SYGWIN : ON/OFF # ANDROID_NO_UNDEFINED : ON/OFF # ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) # ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF # ANDROID_GOLD_LINKER : ON/OFF # ANDROID_NOEXECSTACK : ON/OFF # ANDROID_RELRO : ON/OFF # ANDROID_FORCE_ARM_BUILD : ON/OFF # ANDROID_STL_FORCE_FEATURES : ON/OFF # ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` # Can be set only at the first run: # ANDROID_NDK : path to your NDK install # NDK_CCACHE : path to your ccache executable # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain # ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) # ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) # LIBRARY_OUTPUT_PATH_ROOT : # ANDROID_STANDALONE_TOOLCHAIN # # Primary read-only variables: # ANDROID : always TRUE # ARMEABI : TRUE for arm v6 and older devices # ARMEABI_V6 : TRUE for arm v6 # ARMEABI_V7A : TRUE for arm v7a # ARM64_V8A : TRUE for arm64-v8a # NEON : TRUE if NEON unit is enabled # VFPV3 : TRUE if VFP version 3 is enabled # X86 : TRUE if configured for x86 # X86_64 : TRUE if configured for x86_64 # MIPS : TRUE if configured for mips # MIPS64 : TRUE if configured for mips64 # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK # ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) # ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform # ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used # # Secondary (less stable) read-only variables: # ANDROID_COMPILER_VERSION : GCC version used (not Clang version) # ANDROID_CLANG_VERSION : version of clang compiler if clang is used # ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform # ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI # ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" # ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) # ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools # ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK # ANDROID_STL_INCLUDE_DIRS : stl include paths # ANDROID_RTTI : if rtti is enabled by the runtime # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used # # Defaults: # ANDROID_DEFAULT_NDK_API_LEVEL # ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} # ANDROID_NDK_SEARCH_PATHS # ANDROID_SUPPORTED_ABIS_${ARCH} # ANDROID_SUPPORTED_NDK_VERSIONS gammaray-2.3.0/cmake/Toolchain-blackberry-armv7le.cmake000066400000000000000000000022751255003167400230160ustar00rootroot00000000000000# Basic cmake toolchain file for BlackBerry 10 # Copyright (c) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Rafael Roquetto # # Redistribution and use is allowed according to the terms of the BSD license. # the name of the target operating system set(CMAKE_SYSTEM_NAME QNX) set(CMAKE_SYSTEM_PROCESSOR "armv7le") # which compilers to use for C and C++ set(arch gcc_ntoarmv7le) set(CMAKE_C_COMPILER qcc -V${arch}) set(CMAKE_CXX_COMPILER QCC -V${arch}) # here is the target environment located set(CMAKE_FIND_ROOT_PATH $ENV{QNX_TARGET}/armle-v7 $ENV{QNX_TARGET}) if(CMAKE_HOST_WIN32) set(HOST_EXECUTABLE_SUFFIX ".exe") endif() set(CMAKE_AR "$ENV{QNX_HOST}/usr/bin/ntoarmv7-ar${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ar Program") set(CMAKE_RANLIB "$ENV{QNX_HOST}/usr/bin/ntoarmv7-ranlib${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "QNX ar Program") # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) gammaray-2.3.0/cmake/Toolchain-iMX6.cmake000066400000000000000000000020471255003167400201030ustar00rootroot00000000000000# Basic cmake toolchain file for Freescale iMX6 # Assumptions: toolchain is in path, $SYSROOT points to the sysroot # # Copyright (c) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Volker Krause # # Redistribution and use is allowed according to the terms of the BSD license. set(CMAKE_SYSTEM_NAME "Linux") set(CMAKE_SYSTEM_PROCESSOR "armv7-a") set(CMAKE_C_COMPILER "arm-linux-gcc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=$ENV{SYSROOT} -march=armv7-a -mfpu=neon") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --sysroot=$ENV{SYSROOT} -march=armv7-a -mfpu=neon") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}") set(CMAKE_FIND_ROOT_PATH "$ENV{SYSROOT}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) gammaray-2.3.0/common/000077500000000000000000000000001255003167400146055ustar00rootroot00000000000000gammaray-2.3.0/common/CMakeLists.txt000066400000000000000000000060041255003167400173450ustar00rootroot00000000000000# # Shared non-UI code between probe and client # set(gammaray_common_srcs ${CMAKE_SOURCE_DIR}/3rdparty/kde/klinkitemselectionmodel.cpp ${CMAKE_SOURCE_DIR}/3rdparty/kde/kmodelindexproxymapper.cpp ${CMAKE_SOURCE_DIR}/3rdparty/lz4/lz4.c methodargument.cpp objectbroker.cpp protocol.cpp message.cpp endpoint.cpp paths.cpp propertysyncer.cpp ) add_library(gammaray_common SHARED ${gammaray_common_srcs}) set_target_properties(gammaray_common PROPERTIES ${GAMMARAY_DEFAULT_LIBRARY_PROPERTIES} DEFINE_SYMBOL MAKE_GAMMARAY_COMMON_LIB OUTPUT_NAME gammaray_common-${GAMMARAY_PROBE_ABI} ) if(Qt5Core_FOUND) target_link_libraries(gammaray_common LINK_PUBLIC Qt5::Core LINK_PRIVATE Qt5::Network) else() target_link_libraries(gammaray_common LINK_PUBLIC ${QT_QTCORE_LIBRARIES} LINK_PRIVATE ${QT_QTGUI_LIBRARIES} ${QT_QTNETWORK_LIBRARIES} ) endif() install(TARGETS gammaray_common EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) set(gammaray_common_internal_srcs plugininfo.cpp pluginmanager.cpp proxyfactorybase.cpp propertycontrollerinterface.cpp probecontrollerinterface.cpp modelinspectorinterface.cpp resourcebrowserinterface.cpp networkselectionmodel.cpp streamoperators.cpp probeabi.cpp probeabidetector.cpp tools/objectinspector/propertiesextensioninterface.cpp tools/objectinspector/methodsextensioninterface.cpp tools/objectinspector/connectionsextensioninterface.cpp ) if(WIN32) list(APPEND gammaray_common_internal_srcs probeabidetector_win.cpp) elseif(APPLE) list(APPEND gammaray_common_internal_srcs probeabidetector_mac.cpp) elseif(UNIX AND NOT QNXNTO) list(APPEND gammaray_common_internal_srcs probeabidetector_elf.cpp) else() list(APPEND gammaray_common_internal_srcs probeabidetector_dummy.cpp) endif() add_library(gammaray_common_internal STATIC ${gammaray_common_internal_srcs}) set_target_properties(gammaray_common_internal PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(gammaray_common_internal gammaray_common) if(Qt5Core_FOUND) target_link_libraries(gammaray_common_internal Qt5::Gui Qt5::Network) else() target_link_libraries(gammaray_common_internal ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTNETWORK_LIBRARIES} ) endif() if(WIN32) target_link_libraries(gammaray_common_internal version) endif() if(APPLE) target_link_libraries(gammaray_common_internal "-framework CoreFoundation") endif() if (ANDROID) add_definitions(-DENABLE_MESSAGE_COMPRESSSION) endif() gammaray_install_headers( gammaray_common_export.h endpoint.h enums.h metatypedeclarations.h modelroles.h objectbroker.h objectmodel.h paths.h propertycontrollerinterface.h protocol.h ) ecm_generate_pri_file(BASE_NAME GammaRayCommon LIB_NAME gammaray_common-${GAMMARAY_PROBE_ABI} DEPS "core gui network" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/.. ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) gammaray-2.3.0/common/endpoint.cpp000066400000000000000000000237101255003167400171340ustar00rootroot00000000000000/* endpoint.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "endpoint.h" #include "message.h" #include "methodargument.h" #include "propertysyncer.h" #include using namespace GammaRay; using namespace std; Endpoint* Endpoint::s_instance = 0; Endpoint::Endpoint(QObject* parent): QObject(parent), m_propertySyncer(new PropertySyncer(this)), m_socket(0), m_myAddress(Protocol::InvalidObjectAddress +1) { Q_ASSERT(!s_instance); s_instance = this; ObjectInfo *endpointObj = new ObjectInfo; endpointObj->address = m_myAddress; endpointObj->name = QLatin1String("com.kdab.GammaRay.Server"); // TODO: we could set this as message handler here and use the same dispatch mechanism insertObjectInfo(endpointObj); connect(m_propertySyncer, SIGNAL(message(GammaRay::Message)), this, SLOT(sendMessage(GammaRay::Message))); } Endpoint::~Endpoint() { for (QHash::const_iterator it = m_addressMap.constBegin(); it != m_addressMap.constEnd(); ++it) delete it.value(); s_instance = 0; } Endpoint* Endpoint::instance() { return s_instance; } void Endpoint::send(const Message& msg) { Q_ASSERT(s_instance); Q_ASSERT(msg.address() != Protocol::InvalidObjectAddress); msg.write(s_instance->m_socket); } void Endpoint::sendMessage(const Message& msg) { send(msg); } void Endpoint::waitForMessagesWritten() { m_socket->waitForBytesWritten(-1); } bool Endpoint::isConnected() { return s_instance && s_instance->m_socket; } quint16 Endpoint::defaultPort() { return 11732; } quint16 Endpoint::broadcastPort() { return 13325; } void Endpoint::setDevice(QIODevice* device) { Q_ASSERT(!m_socket); Q_ASSERT(device); m_socket = device; connect(m_socket.data(), SIGNAL(readyRead()), SLOT(readyRead())); connect(m_socket.data(), SIGNAL(disconnected()), SLOT(connectionClosed())); if (m_socket->bytesAvailable()) readyRead(); } Protocol::ObjectAddress Endpoint::endpointAddress() const { return m_myAddress; } void Endpoint::readyRead() { while (Message::canReadMessage(m_socket.data())) { messageReceived(Message::readMessage(m_socket.data())); } } void Endpoint::connectionClosed() { m_socket->deleteLater(); m_socket = 0; emit disconnected(); } Protocol::ObjectAddress Endpoint::objectAddress(const QString& objectName) const { const QHash::const_iterator it = m_nameMap.constFind(objectName); if (it != m_nameMap.constEnd()) return it.value()->address; return Protocol::InvalidObjectAddress; } Protocol::ObjectAddress Endpoint::registerObject(const QString &name, QObject *object) { ObjectInfo* obj = m_nameMap.value(name, 0); Q_ASSERT(obj); Q_ASSERT(!obj->object); Q_ASSERT(obj->address != Protocol::InvalidObjectAddress); if (!obj || obj->object || obj->address == Protocol::InvalidObjectAddress) { return 0; } obj->object = object; Q_ASSERT(!m_objectMap.contains(object)); m_objectMap[object] = obj; connect(object, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*))); return obj->address; } void Endpoint::invokeObject(const QString &objectName, const char *method, const QVariantList &args) const { if (!isConnected()) { return; } ObjectInfo* obj = m_nameMap.value(objectName, 0); Q_ASSERT(obj); Q_ASSERT(obj->address != Protocol::InvalidObjectAddress); if (!obj || obj->address == Protocol::InvalidObjectAddress) { return; } Message msg(obj->address, Protocol::MethodCall); const QByteArray name(method); Q_ASSERT(!name.isEmpty()); msg.payload() << name << args; send(msg); } void Endpoint::invokeObjectLocal(QObject *object, const char *method, const QVariantList &args) const { Q_ASSERT(args.size() <= 10); QVector a(10); for (int i = 0; i < args.size(); ++i) { a[i] = MethodArgument(args.at(i)); } QMetaObject::invokeMethod(object, method, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } void Endpoint::registerObjectInternal(const QString& objectName, Protocol::ObjectAddress objectAddress) { Q_ASSERT(objectAddress != Protocol::InvalidObjectAddress); ObjectInfo *obj = new ObjectInfo; obj->address = objectAddress; obj->name = objectName; insertObjectInfo(obj); emit objectRegistered(objectName, objectAddress); } void Endpoint::unregisterObjectInternal(const QString& objectName) { Q_ASSERT(m_nameMap.contains(objectName)); ObjectInfo *obj = m_nameMap.value(objectName); emit objectUnregistered(objectName, obj->address); removeObjectInfo(obj); } void Endpoint::registerMessageHandlerInternal(Protocol::ObjectAddress objectAddress, QObject* receiver, const char* messageHandlerName) { Q_ASSERT(m_addressMap.contains(objectAddress)); ObjectInfo *obj = m_addressMap.value(objectAddress); Q_ASSERT(obj); Q_ASSERT(!obj->receiver); Q_ASSERT(obj->messageHandler.isEmpty()); obj->receiver = receiver; obj->messageHandler = messageHandlerName; Q_ASSERT(!m_handlerMap.contains(receiver, obj)); m_handlerMap.insert(receiver, obj); connect(receiver, SIGNAL(destroyed(QObject*)), SLOT(handlerDestroyed(QObject*))); } void Endpoint::unregisterMessageHandlerInternal(Protocol::ObjectAddress objectAddress) { Q_ASSERT(m_addressMap.contains(objectAddress)); ObjectInfo *obj = m_addressMap.value(objectAddress); Q_ASSERT(obj); Q_ASSERT(obj->receiver); disconnect(obj->receiver, SIGNAL(destroyed(QObject*)), this, SLOT(handlerDestroyed(QObject*))); m_handlerMap.remove(obj->receiver, obj); obj->receiver = 0; obj->messageHandler.clear(); } void Endpoint::objectDestroyed(QObject *obj) { ObjectInfo* info = m_objectMap.value(obj, 0); Q_ASSERT(info); Q_ASSERT(info->object == obj); if (!info || info->object != obj) { return; } info->object = 0; m_objectMap.remove(obj); objectDestroyed(info->address, QString(info->name), obj); // copy the name, in case unregisterMessageHandlerInternal() is called inside } void Endpoint::handlerDestroyed(QObject* obj) { const QList objs = m_handlerMap.values(obj); // copy, the virtual method below likely changes the maps. m_handlerMap.remove(obj); foreach (ObjectInfo *obj, objs) { obj->receiver = 0; obj->messageHandler.clear(); handlerDestroyed(obj->address, QString(obj->name)); // copy the name, in case unregisterMessageHandlerInternal() is called inside } } void Endpoint::dispatchMessage(const Message& msg) { const QHash::const_iterator it = m_addressMap.constFind(msg.address()); if (it == m_addressMap.constEnd()) { cerr << "message for unknown object address received: " << quint64(msg.address()) << endl; return; } ObjectInfo* obj = it.value(); if (msg.type() == Protocol::MethodCall) { QByteArray method; msg.payload() >> method; if (obj->object) { Q_ASSERT(!method.isEmpty()); QVariantList args; msg.payload() >> args; invokeObjectLocal(obj->object, method.constData(), args); } else { cerr << "cannot call method " << method.constData() << " on unknown object of name " << qPrintable(obj->name) << " with address " << quint64(obj->address) << " - did you forget to register it?" << endl; } } if (obj->receiver) { QMetaObject::invokeMethod(obj->receiver, obj->messageHandler, Q_ARG(GammaRay::Message, msg)); } if (!obj->receiver && (msg.type() != Protocol::MethodCall || !obj->object)) { cerr << "Cannot dispatch message " << quint64(msg.type()) << " - no handler registered." << " Receiver: " << qPrintable(obj->name) << ", address " << quint64(obj->address) << endl; } } QVector< QPair< Protocol::ObjectAddress, QString > > Endpoint::objectAddresses() const { QVector > addrs; addrs.reserve(m_addressMap.size()); for (QHash::const_iterator it = m_addressMap.constBegin(); it != m_addressMap.constEnd(); ++it) addrs.push_back(qMakePair(it.key(), it.value()->name)); return addrs; } void Endpoint::insertObjectInfo(Endpoint::ObjectInfo* oi) { Q_ASSERT(!m_addressMap.contains(oi->address)); m_addressMap.insert(oi->address, oi); Q_ASSERT(!m_nameMap.contains(oi->name)); m_nameMap.insert(oi->name, oi); if (oi->receiver) m_handlerMap.insert(oi->receiver, oi); if (oi->object) m_objectMap.insert(oi->object, oi); } void Endpoint::removeObjectInfo(Endpoint::ObjectInfo* oi) { Q_ASSERT(m_addressMap.contains(oi->address)); m_addressMap.remove(oi->address); Q_ASSERT(m_nameMap.contains(oi->name)); m_nameMap.remove(oi->name); if (oi->receiver) { disconnect(oi->receiver, SIGNAL(destroyed(QObject*)), this, SLOT(handlerDestroyed(QObject*))); m_handlerMap.remove(oi->receiver, oi); } if (oi->object) { disconnect(oi->object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); m_objectMap.remove(oi->object); } delete oi; } QString Endpoint::label() const { return m_label; } void Endpoint::setLabel(const QString &label) { m_label = label; } gammaray-2.3.0/common/endpoint.h000066400000000000000000000162631255003167400166060ustar00rootroot00000000000000/* endpoint.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ENDPOINT_H #define GAMMARAY_ENDPOINT_H #include "gammaray_common_export.h" #include "protocol.h" #include #include class QIODevice; class QUrl; namespace GammaRay { class Message; class PropertySyncer; /** @brief Network protocol endpoint. * * Contains: * - object address <-> object name mapping * - message handler registration and message dispatching */ class GAMMARAY_COMMON_EXPORT Endpoint : public QObject { Q_OBJECT public: ~Endpoint(); /** Send @p msg to the connected endpoint. */ static void send(const Message &msg); /** Returns @c true if we are currently connected to another endpoint. */ static bool isConnected(); static quint16 defaultPort(); static quint16 broadcastPort(); /** Returns the object address for @p objectName, or @c Protocol::InvalidObjectAddress if not known. */ Protocol::ObjectAddress objectAddress(const QString &objectName) const; /** Singleton accessor. */ static Endpoint* instance(); /** * Register an object of the given name for transparent server/client communication. */ virtual Protocol::ObjectAddress registerObject(const QString &name, QObject *object); /** * Invoke @p method on the object called @p objectName with the given @p args. * * This also works with signals. * * The default implementation forwards the object calls to remote side when the * endpoint is connected. The Server implementation is furthermore expected to * call the method directly on the local object to support the in-process mode. */ virtual void invokeObject(const QString &objectName, const char *method, const QVariantList &args = QVariantList()) const; /** * Write all pending data and block until this is done. * * This should only be used in very rare situations. */ void waitForMessagesWritten(); /** * Returns a human-readable string describing the host program. */ QString label() const; /** * Sets the human-readable label of this instance used e.g. when advertising on the network. */ void setLabel(const QString &label); /** * Returns true for remote clients and false for the in-probe server endpoint. */ virtual bool isRemoteClient() const = 0; /** * Returns the listening address of the server, in case you need to connect to a different service there * (such as the web inspector server). */ virtual QUrl serverAddress() const = 0; public slots: /** Convenience overload of send(), to directly send message delivered via signals. */ void sendMessage(const GammaRay::Message &msg); signals: /** Emitted when we lost the connection to the other endpoint. */ void disconnected(); /** Emitted when a new object with name @p objectName has been registered at address @p objectAddress. */ void objectRegistered(const QString &objectName, Protocol::ObjectAddress objectAddress); void objectUnregistered(const QString &objectName, Protocol::ObjectAddress objectAddress); protected: Endpoint(QObject* parent = 0); /** Call with the socket once you have established a connection to another endpoint, takes ownership of @p device. */ void setDevice(QIODevice* device); /** The object address of the other endpoint. */ Protocol::ObjectAddress endpointAddress() const; /** Called for every incoming message. * @see dispatchMessage(). */ virtual void messageReceived(const Message &msg) = 0; /** Call this when learning about a new object <-> address mapping. */ void registerObjectInternal(const QString &objectName, Protocol::ObjectAddress objectAddress); /** Call this when learning about a dissolved object <-> address mapping. */ void unregisterObjectInternal(const QString& objectName); /** Register the slot @p messageHandlerName on @p receiver as the handler for messages to/from @p objectAddress. * @see dispatchMessage() */ void registerMessageHandlerInternal(Protocol::ObjectAddress objectAddress, QObject *receiver, const char* messageHandlerName); /** Unregister the message handler for @p objectAddress. */ void unregisterMessageHandlerInternal(Protocol::ObjectAddress objectAddress); /** Called when the current handler of the object identified by @p objectAddress has been destroyed. */ virtual void handlerDestroyed(Protocol::ObjectAddress objectAddress, const QString &objectName) = 0; /** Called when a registered object identified by @p objectAddress has been destroyed. */ virtual void objectDestroyed(Protocol::ObjectAddress objectAddress, const QString &objectName, QObject *object) = 0; /** Calls the message handler registered for the receiver of @p msg. */ void dispatchMessage(const GammaRay::Message& msg); /** All current object name/address pairs. */ QVector > objectAddresses() const; /** Singleton instance. */ static Endpoint *s_instance; /** * Invoke @p method on @p object with the given @p args. * * This is invokes the method directly on the local object. */ void invokeObjectLocal(QObject *object, const char *method, const QVariantList &args) const; PropertySyncer *m_propertySyncer; private slots: void readyRead(); void connectionClosed(); void handlerDestroyed(QObject* obj); void objectDestroyed(QObject* obj); private: struct ObjectInfo { ObjectInfo() : address(Protocol::InvalidObjectAddress) , object(0) , receiver(0) { } QString name; Protocol::ObjectAddress address; // the locally registered object QObject *object; // custom message handling support // TODO: obsolete this QObject *receiver; QByteArray messageHandler; }; /** Inserts @p oi into all maps. */ void insertObjectInfo(ObjectInfo *oi); /** Removes @p oi from all maps and destroys it. */ void removeObjectInfo(ObjectInfo *oi); QHash m_nameMap; QHash m_addressMap; QHash m_objectMap; QMultiHash m_handlerMap; QPointer m_socket; Protocol::ObjectAddress m_myAddress; QString m_label; }; } #endif // GAMMARAY_ENDPOINT_H gammaray-2.3.0/common/enums.h000066400000000000000000000030131255003167400161020ustar00rootroot00000000000000/* enums.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ENUMS_H #define GAMMARAY_ENUMS_H #include namespace GammaRay { /** @brief Display mode settings of the property widget. */ namespace PropertyWidgetDisplayState { enum State { QObject, ///< full QObject instance Object, ///< non-QObject instance MetaObject ///< QMetaObject instance only }; } } Q_DECLARE_METATYPE(GammaRay::PropertyWidgetDisplayState::State) #endif gammaray-2.3.0/common/gammaray_common_export.h000066400000000000000000000030041255003167400215220ustar00rootroot00000000000000/* gammaray_common_export.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_COMMON_EXPORT_H #define GAMMARAY_COMMON_EXPORT_H #include #ifdef GAMMARAY_COMMON_STATICLIB # undef GAMMARAY_COMMON_SHAREDLIB # define GAMMARAY_COMMON_EXPORT #else # ifdef MAKE_GAMMARAY_COMMON_LIB # define GAMMARAY_COMMON_EXPORT Q_DECL_EXPORT # else # define GAMMARAY_COMMON_EXPORT Q_DECL_IMPORT # endif #endif #endif /* GAMMARAY_COMMON_EXPORT_H */ gammaray-2.3.0/common/message.cpp000066400000000000000000000142141255003167400167370ustar00rootroot00000000000000/* message.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "message.h" #include "lz4/lz4.h" //3rdparty #include #include inline QByteArray compress(const QByteArray &src) { const qint32 srcSz = src.size(); QByteArray dst; dst.resize(LZ4_compressBound(srcSz + sizeof(srcSz))); *(qint32*)dst.data() = srcSz; // save the source size const int sz = LZ4_compress_default(src.constData(), dst.data() + sizeof(int), srcSz, dst.size()); dst.resize(sz + sizeof(srcSz)); return dst; } inline QByteArray uncompress(const QByteArray &src) { const qint32 dstSz = *(const qint32*)src.constData(); // get the dest size QByteArray dst; dst.resize(dstSz); const int sz = LZ4_decompress_safe(src.constData() + sizeof(dstSz), dst.data(), src.size()- sizeof(dstSz), dstSz); if (sz <= 0) dst.resize(0); else dst.resize(sz); return dst; } static const QDataStream::Version StreamVersion = QDataStream::Qt_4_7; #ifdef ENABLE_MESSAGE_COMPRESSSION static const int minimumUncompressedSize = 32; #endif #if QT_VERSION < 0x040800 // This template-specialization is missing in qendian.h, required for qFromBigEndian template<> inline quint8 qbswap(quint8 source) { return source; } #endif template static T readNumber(QIODevice *device) { T buffer; const int readSize = device->read((char*)&buffer, sizeof(T)); Q_UNUSED(readSize); Q_ASSERT(readSize == sizeof(T)); return qFromBigEndian(buffer); } template static void writeNumber(QIODevice *device, T value) { value = qToBigEndian(value); const int writeSize = device->write((char*)&value, sizeof(T)); Q_UNUSED(writeSize); Q_ASSERT(writeSize == sizeof(T)); } using namespace GammaRay; Message::Message() : m_objectAddress(Protocol::InvalidObjectAddress), m_messageType(Protocol::InvalidMessageType) { } Message::Message(Protocol::ObjectAddress objectAddress, Protocol::MessageType type) : m_objectAddress(objectAddress), m_messageType(type) { } #ifdef Q_COMPILER_RVALUE_REFS Message::Message(Message&& other) : m_buffer(std::move(other.m_buffer)), m_objectAddress(other.m_objectAddress), m_messageType(other.m_messageType) { m_stream.swap(other.m_stream); } #endif Message::~Message() { } Protocol::ObjectAddress Message::address() const { return m_objectAddress; } Protocol::MessageType Message::type() const { return m_messageType; } QDataStream& Message::payload() const { if (!m_stream) { if (m_buffer.isEmpty()) m_stream.reset(new QDataStream(&m_buffer, QIODevice::WriteOnly)); else m_stream.reset(new QDataStream(m_buffer)); m_stream->setVersion(StreamVersion); } return *m_stream; } bool Message::canReadMessage(QIODevice* device) { static const int minimumSize = sizeof(Protocol::PayloadSize) + sizeof(Protocol::ObjectAddress) + sizeof(Protocol::MessageType); if (device->bytesAvailable() < minimumSize) return false; Protocol::PayloadSize payloadSize; const int peekSize = device->peek((char*)&payloadSize, sizeof(Protocol::PayloadSize)); if (peekSize < (int)sizeof(Protocol::PayloadSize)) return false; if (payloadSize == -1 && !device->isSequential()) // input end on shared memory return false; payloadSize = abs(qFromBigEndian(payloadSize)); return device->bytesAvailable() >= payloadSize + minimumSize; } Message Message::readMessage(QIODevice* device) { Message msg; Protocol::PayloadSize payloadSize = readNumber(device); msg.m_objectAddress = readNumber(device); msg.m_messageType = readNumber(device); Q_ASSERT(msg.m_messageType != Protocol::InvalidMessageType); Q_ASSERT(msg.m_objectAddress != Protocol::InvalidObjectAddress); if (payloadSize < 0) { payloadSize = abs(payloadSize); QByteArray buff = device->read(payloadSize); msg.m_buffer = uncompress(buff); Q_ASSERT(payloadSize == buff.size()); } else { if (payloadSize > 0) { msg.m_buffer = device->read(payloadSize); Q_ASSERT(payloadSize == msg.m_buffer.size()); } } return msg; } void Message::write(QIODevice* device) const { Q_ASSERT(m_objectAddress != Protocol::InvalidObjectAddress); Q_ASSERT(m_messageType != Protocol::InvalidMessageType); const int buffSize = m_buffer.size(); #ifdef ENABLE_MESSAGE_COMPRESSSION QByteArray buff; if (buffSize > minimumUncompressedSize) buff = compress(m_buffer); if (buff.size() && buff.size() < buffSize) writeNumber(device, -buff.size()); // send compressed Buffer else #endif writeNumber(device, buffSize); // send uncompressed Buffer writeNumber(device, m_objectAddress); writeNumber(device, m_messageType); #ifdef ENABLE_MESSAGE_COMPRESSSION if (buffSize) { if (buff.size() && buff.size() < buffSize) { const int s = device->write(buff); Q_ASSERT(s == buff.size()); Q_UNUSED(s); } else { #endif const int s = device->write(m_buffer); Q_ASSERT(s == m_buffer.size()); Q_UNUSED(s); #ifdef ENABLE_MESSAGE_COMPRESSSION } } #endif } gammaray-2.3.0/common/message.h000066400000000000000000000060431255003167400164050ustar00rootroot00000000000000/* message.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGE_H #define GAMMARAY_MESSAGE_H #include "gammaray_common_export.h" #include "protocol.h" #include #include namespace GammaRay { /** * Single message send between client and server. * Binary format: * - sizeof(Protocol::PayloadSize) byte size of the message payload (not including the size and other fixed fields itself) in netowork byte order (big endian) * - sizeof(Protocol::ObjectAddress) server object address (big endian) * - sizeof(Protocol::MessageType) command type (big endian) * - size bytes message payload (encoding is user defined, QDataStream provided for convenience) */ class GAMMARAY_COMMON_EXPORT Message { public: /** * Construct a new message to/from @p address and message type @p type. */ explicit Message(Protocol::ObjectAddress address, Protocol::MessageType type); #ifdef Q_COMPILER_RVALUE_REFS Message(Message &&other); //krazy:exclude=explicit #else // this is only needed to make readMessage compile (due to RVO there is no actual copy though) // semantically we don't want to support copying, due to the datastream state Message(const Message &other); #endif ~Message(); Protocol::ObjectAddress address() const; Protocol::MessageType type() const; /** Access to the message payload. This is read-only for received messages * and write-only for messages to be sent. */ QDataStream& payload() const; /** Checks if there is a full message waiting in @p device. */ static bool canReadMessage(QIODevice *device); /** Read the next message from @p device. */ static Message readMessage(QIODevice *device); /** Write this message to @p device. */ void write(QIODevice *device) const; private: Message(); mutable QByteArray m_buffer; mutable QScopedPointer m_stream; Protocol::ObjectAddress m_objectAddress; Protocol::MessageType m_messageType; }; } #endif gammaray-2.3.0/common/metatypedeclarations.h000066400000000000000000000046341255003167400212060ustar00rootroot00000000000000/* metatypedeclarations.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares the various metatypes. @brief Declares the various metatypes. @author Volker Krause \ */ #ifndef GAMMARAY_METATYPEDECLARATIONS_H #define GAMMARAY_METATYPEDECLARATIONS_H #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #include #include #include #endif Q_DECLARE_METATYPE(Qt::ConnectionType) Q_DECLARE_METATYPE(Qt::FillRule) Q_DECLARE_METATYPE(Qt::InputMethodHints) Q_DECLARE_METATYPE(Qt::MouseButtons) Q_DECLARE_METATYPE(Qt::TransformationMode) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(QPolygonF) Q_DECLARE_METATYPE(QMetaMethod::MethodType) Q_DECLARE_METATYPE(QMargins) Q_DECLARE_METATYPE(Qt::WindowType) Q_DECLARE_METATYPE(Qt::WindowState) Q_DECLARE_METATYPE(const QMatrix4x4*) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_DECLARE_METATYPE(QOpenGLShader::ShaderType) Q_DECLARE_METATYPE(QSurfaceFormat) Q_DECLARE_METATYPE(QSurface::SurfaceClass) Q_DECLARE_METATYPE(QSurface::SurfaceType) #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && QT_VERSION < QT_VERSION_CHECK(5, 5, 0) Q_DECLARE_METATYPE(Qt::ApplicationState) #endif #endif gammaray-2.3.0/common/methodargument.cpp000066400000000000000000000053721255003167400203430ustar00rootroot00000000000000/* methodargument.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodargument.h" #include "variantwrapper.h" #include #include using namespace GammaRay; class GammaRay::MethodArgumentPrivate : public QSharedData { public: MethodArgumentPrivate() : QSharedData(), data(0), unwrapVariant(true) {} MethodArgumentPrivate(const MethodArgumentPrivate &other) : QSharedData(other) { value = other.value; name = other.name; data = 0; unwrapVariant = other.unwrapVariant; } ~MethodArgumentPrivate() { if (data) QMetaType::destroy(value.type(), data); } QVariant value; QByteArray name; void *data; bool unwrapVariant; }; MethodArgument::MethodArgument() : d(new MethodArgumentPrivate) { } MethodArgument::MethodArgument(const QVariant& v) : d(new MethodArgumentPrivate) { if (v.userType() == qMetaTypeId()) { d->value = v.value().variant(); d->unwrapVariant = false; d->name = "QVariant"; } else { d->value = v; d->unwrapVariant = true; d->name = v.typeName(); } } MethodArgument::MethodArgument(const MethodArgument& other) : d(other.d) { } MethodArgument::~MethodArgument() { } MethodArgument& MethodArgument::operator=(const MethodArgument& other) { d = other.d; return *this; } MethodArgument::operator QGenericArgument() const { if (!d->unwrapVariant) { return QGenericArgument(d->name.data(), &d->value); } if (d->value.isValid()) { d->data = QMetaType::construct(d->value.userType(), d->value.constData()); Q_ASSERT(d->data); return QGenericArgument(d->name.data(), d->data); } return QGenericArgument(); } gammaray-2.3.0/common/methodargument.h000066400000000000000000000034661255003167400200120ustar00rootroot00000000000000/* methodargument.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METHODARGUMENT_H #define GAMMARAY_METHODARGUMENT_H #include "gammaray_common_export.h" #include #include namespace GammaRay { class MethodArgumentPrivate; /** Q[Generic]Argument that works on a QVariant, with some memory handling safety. */ class GAMMARAY_COMMON_EXPORT MethodArgument { public: MethodArgument(); explicit MethodArgument(const QVariant &v); MethodArgument(const MethodArgument &other); ~MethodArgument(); MethodArgument& operator=(const MethodArgument &other); operator QGenericArgument() const; private: QExplicitlySharedDataPointer d; }; } #endif // GAMMARAY_METHODARGUMENT_H gammaray-2.3.0/common/modelinspectorinterface.cpp000066400000000000000000000026551255003167400222310ustar00rootroot00000000000000/* modelinspectorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelinspectorinterface.h" #include "objectbroker.h" using namespace GammaRay; ModelInspectorInterface::ModelInspectorInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } ModelInspectorInterface::~ModelInspectorInterface() { } gammaray-2.3.0/common/modelinspectorinterface.h000066400000000000000000000032521255003167400216700ustar00rootroot00000000000000/* modelinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTORINTERFACE_H #define GAMMARAY_MODELINSPECTORINTERFACE_H #include namespace GammaRay { class ModelInspectorInterface : public QObject { Q_OBJECT public: explicit ModelInspectorInterface(QObject *parent = 0); virtual ~ModelInspectorInterface(); signals: void cellSelected(int row, int col, const QString &internalId, const QString &internalPtr); }; } Q_DECLARE_INTERFACE(GammaRay::ModelInspectorInterface, "com.kdab.GammaRay.ModelInspectorInterface") #endif // GAMMARAY_MODELINSPECTORINTERFACE_H gammaray-2.3.0/common/modelroles.h000066400000000000000000000037251255003167400171320ustar00rootroot00000000000000/* modelroles.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELROLES_H #define GAMMARAY_MODELROLES_H #include /** * @file modelroles.h * @brief A collection of custom model roles shared between client and server. */ namespace GammaRay { /** Portable replacement for Qt::UserRole. * Qt4 uses 32, Qt5 256, use the latter globally to allow combining Qt4/5 client/servers. */ static const int UserRole = 256; /** @brief Custom roles for GammaRay::ToolModel. * @todo These can be split again, between core tool model and UI tool model. */ namespace ToolModelRole { enum Role { ToolFactory = UserRole + 1, ToolWidget, ToolId, ToolWidgetParent, ToolEnabled }; } /** @brief Custom roles for GammaRay::ObjectMethodModel. */ namespace ObjectMethodModelRole { enum Role { MetaMethod = UserRole + 1, MetaMethodType, MethodSignature }; } } #endif gammaray-2.3.0/common/networkselectionmodel.cpp000066400000000000000000000132731255003167400217370ustar00rootroot00000000000000/* networkselectionmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "networkselectionmodel.h" #include "message.h" #include "endpoint.h" #include "settempvalue.h" #include using namespace GammaRay; static QItemSelection readSelection(const Message &msg, const QAbstractItemModel *model) { QItemSelection selection; qint32 size = 0; msg.payload() >> size; for (int i = 0; i < size; ++i) { Protocol::ModelIndex topLeft, bottomRight; msg.payload() >> topLeft >> bottomRight; const QModelIndex qmiTopLeft = Protocol::toQModelIndex(model, topLeft); const QModelIndex qmiBottomRight = Protocol::toQModelIndex(model, bottomRight); if (!qmiTopLeft.isValid() && !qmiBottomRight.isValid()) continue; selection.push_back(QItemSelectionRange(qmiTopLeft, qmiBottomRight)); } return selection; } static void writeSelection(Message *msg, const QItemSelection &selection) { msg->payload() << qint32(selection.size()); foreach(const QItemSelectionRange& range, selection) { msg->payload() << Protocol::fromQModelIndex(range.topLeft()) << Protocol::fromQModelIndex(range.bottomRight()); } } NetworkSelectionModel::NetworkSelectionModel(const QString &objectName, QAbstractItemModel* model, QObject* parent): QItemSelectionModel(model, parent), m_objectName(objectName), m_myAddress(Protocol::InvalidObjectAddress), m_handlingRemoteMessage(false) { connect(this, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); connect(this, SIGNAL(currentColumnChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentColumnChanged(QModelIndex,QModelIndex))); connect(this, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentRowChanged(QModelIndex,QModelIndex))); connect(this, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); } NetworkSelectionModel::~NetworkSelectionModel() { } void NetworkSelectionModel::newMessage(const Message& msg) { Q_ASSERT(msg.address() == m_myAddress); switch (msg.type()) { case Protocol::SelectionModelSelect: { QItemSelection selected = readSelection(msg, model()); QItemSelection deselected = readSelection(msg, model()); Util::SetTempValue guard(m_handlingRemoteMessage, true); if (!deselected.isEmpty()) { select(deselected, Deselect); } if (!selected.isEmpty()) { select(selected, Select); } break; } case Protocol::SelectionModelCurrent: { qint32 flags; Protocol::ModelIndex index; msg.payload() >> flags >> index; const QModelIndex qmi = Protocol::toQModelIndex(model(), index); if (!qmi.isValid()) break; Util::SetTempValue guard(m_handlingRemoteMessage, true); setCurrentIndex(qmi, QItemSelectionModel::SelectionFlags(flags)); break; } default: Q_ASSERT(false); } } void NetworkSelectionModel::slotCurrentChanged(const QModelIndex& current, const QModelIndex& previous) { Q_UNUSED(previous); if (m_handlingRemoteMessage || !Endpoint::isConnected() || m_myAddress == Protocol::InvalidObjectAddress) return; Message msg(m_myAddress, Protocol::SelectionModelCurrent); msg.payload() << qint32(QItemSelectionModel::Current) << Protocol::fromQModelIndex(current); Endpoint::send(msg); } void NetworkSelectionModel::slotCurrentColumnChanged(const QModelIndex& current, const QModelIndex& previous) { Q_UNUSED(previous); if (m_handlingRemoteMessage ||!Endpoint::isConnected() || m_myAddress == Protocol::InvalidObjectAddress) return; Message msg(m_myAddress, Protocol::SelectionModelCurrent); msg.payload() << qint32(QItemSelectionModel::Current|QItemSelectionModel::Columns) << Protocol::fromQModelIndex(current); Endpoint::send(msg); } void NetworkSelectionModel::slotCurrentRowChanged(const QModelIndex& current, const QModelIndex& previous) { Q_UNUSED(previous); if (m_handlingRemoteMessage ||!Endpoint::isConnected() || m_myAddress == Protocol::InvalidObjectAddress) return; Message msg(m_myAddress, Protocol::SelectionModelCurrent); msg.payload() << qint32(QItemSelectionModel::Current|QItemSelectionModel::Rows) << Protocol::fromQModelIndex(current); Endpoint::send(msg); } void NetworkSelectionModel::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { if (m_handlingRemoteMessage ||!Endpoint::isConnected() || m_myAddress == Protocol::InvalidObjectAddress) return; Message msg(m_myAddress, Protocol::SelectionModelSelect); writeSelection(&msg, selected); writeSelection(&msg, deselected); Endpoint::send(msg); } gammaray-2.3.0/common/networkselectionmodel.h000066400000000000000000000042441255003167400214020ustar00rootroot00000000000000/* networkselectionmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_NETWORKSELECTIONMODEL_H #define GAMMARAY_NETWORKSELECTIONMODEL_H #include #include "protocol.h" namespace GammaRay { class Message; /** Base class for network-transparent item selection models, do not use directly. */ class NetworkSelectionModel : public QItemSelectionModel { Q_OBJECT public: ~NetworkSelectionModel(); protected: explicit NetworkSelectionModel(const QString &objectName, QAbstractItemModel *model, QObject *parent = 0); QString m_objectName; Protocol::ObjectAddress m_myAddress; private slots: void newMessage(const GammaRay::Message &msg); void slotCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous); void slotCurrentColumnChanged(const QModelIndex ¤t, const QModelIndex &previous); void slotCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); void slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); private: bool m_handlingRemoteMessage; }; } #endif // GAMMARAY_NETWORKSELECTIONMODEL_H gammaray-2.3.0/common/objectbroker.cpp000066400000000000000000000153241255003167400177710ustar00rootroot00000000000000/* objectbroker.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectbroker.h" #include "endpoint.h" #include #include #include #include #include #include #include #include namespace GammaRay { struct ObjectlBrokerData { ObjectlBrokerData() : modelCallback(0), selectionCallback(0) {} QHash objects; QHash models; QHash selectionModels; QHash clientObjectFactories; ObjectBroker::ModelFactoryCallback modelCallback; ObjectBroker::selectionModelFactoryCallback selectionCallback; QVector ownedObjects; }; Q_GLOBAL_STATIC(ObjectlBrokerData, s_objectBroker) void ObjectBroker::registerObject(const QString &name, QObject *object) { Q_ASSERT(!name.isEmpty()); Q_ASSERT(object->objectName().isEmpty()); object->setObjectName(name); Q_ASSERT(!s_objectBroker()->objects.contains(name)); s_objectBroker()->objects.insert(name, object); Q_ASSERT(Endpoint::instance()); Endpoint::instance()->registerObject(name, object); } QObject* ObjectBroker::objectInternal(const QString& name, const QByteArray &type) { const QHash::const_iterator it = s_objectBroker()->objects.constFind(name); if (it != s_objectBroker()->objects.constEnd()) { return it.value(); } // Below here only valid for clients! // Remote/probe side should have registered the object directly QObject* obj = 0; if (!type.isEmpty()) { Q_ASSERT(s_objectBroker()->clientObjectFactories.contains(type)); obj = s_objectBroker()->clientObjectFactories[type](name, qApp); } else { // fallback obj = new QObject(qApp); registerObject(name, obj); } s_objectBroker()->ownedObjects.push_back(obj); Q_ASSERT(obj); // ensure it was registered Q_ASSERT_X(s_objectBroker()->objects.value(name, 0) == obj, Q_FUNC_INFO, qPrintable(QString("Object %1 was not registered in the broker.").arg(name))); return obj; } void ObjectBroker::registerClientObjectFactoryCallbackInternal(const QByteArray &type, ObjectBroker::ClientObjectFactoryCallback callback) { Q_ASSERT(!type.isEmpty()); s_objectBroker()->clientObjectFactories[type] = callback; } void ObjectBroker::registerModelInternal(const QString& name, QAbstractItemModel* model) { Q_ASSERT(!s_objectBroker()->models.contains(name)); model->setObjectName(name); s_objectBroker()->models.insert(name, model); } QAbstractItemModel* ObjectBroker::model(const QString& name) { const QHash::const_iterator it = s_objectBroker()->models.constFind(name); if (it != s_objectBroker()->models.constEnd()) return it.value(); if (s_objectBroker()->modelCallback) { QAbstractItemModel* model = s_objectBroker()->modelCallback(name); if (model) { model->setObjectName(name); s_objectBroker()->models.insert(name, model); s_objectBroker()->ownedObjects.push_back(model); return model; } } return 0; } void ObjectBroker::setModelFactoryCallback(ObjectBroker::ModelFactoryCallback callback) { s_objectBroker()->modelCallback = callback; } void ObjectBroker::registerSelectionModel(QItemSelectionModel* selectionModel) { Q_ASSERT(!s_objectBroker()->selectionModels.contains(const_cast(selectionModel->model()))); s_objectBroker()->selectionModels.insert(const_cast(selectionModel->model()), selectionModel); } void ObjectBroker::unregisterSelectionModel(QItemSelectionModel *selectionModel) { Q_ASSERT(s_objectBroker()->selectionModels.contains(const_cast(selectionModel->model()))); s_objectBroker()->selectionModels.remove(const_cast(selectionModel->model())); } bool ObjectBroker::hasSelectionModel(QAbstractItemModel* model) { return s_objectBroker()->selectionModels.contains(model); } static QAbstractItemModel* sourceModelForProxy(QAbstractItemModel* model) { // stop once we found a registered model, this is what network communication is based on if (s_objectBroker()->models.values().contains(model)) return model; QAbstractProxyModel *proxy = qobject_cast(model); if (!proxy) return model; return sourceModelForProxy(proxy->sourceModel()); } QItemSelectionModel* ObjectBroker::selectionModel(QAbstractItemModel* model) { const QHash::const_iterator it = s_objectBroker()->selectionModels.constFind(model); if (it != s_objectBroker()->selectionModels.constEnd()) return it.value(); if (s_objectBroker()->selectionCallback) { QAbstractItemModel *sourceModel = sourceModelForProxy(model); QItemSelectionModel* selectionModel = 0; if (sourceModel == model) { selectionModel = s_objectBroker()->selectionCallback(sourceModel); s_objectBroker()->ownedObjects.push_back(selectionModel); } else { QItemSelectionModel *sourceSelectionModel = ObjectBroker::selectionModel(sourceModel); selectionModel = new KLinkItemSelectionModel(model, sourceSelectionModel, model); } if (selectionModel) { registerSelectionModel(selectionModel); return selectionModel; } } return 0; } void ObjectBroker::setSelectionModelFactoryCallback(ObjectBroker::selectionModelFactoryCallback callback) { s_objectBroker()->selectionCallback = callback; } void ObjectBroker::clear() { auto *ob = s_objectBroker(); qDeleteAll(ob->ownedObjects); ob->ownedObjects.clear(); ob->objects.clear(); ob->models.clear(); ob->selectionModels.clear(); } } gammaray-2.3.0/common/objectbroker.h000066400000000000000000000131171255003167400174340ustar00rootroot00000000000000/* objectbroker.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTBROKER_H #define GAMMARAY_OBJECTBROKER_H #include "gammaray_common_export.h" #include class QItemSelectionModel; class QAbstractItemModel; namespace GammaRay { /** @brief Retrieve/expose objects independent of whether using in-process or out-of-process UI. */ namespace ObjectBroker { /** Register a newly created QObject under the given name. */ GAMMARAY_COMMON_EXPORT void registerObject(const QString &name, QObject *object); template void registerObject(QObject *object) { const QString interfaceName = QString::fromUtf8(qobject_interface_iid()); registerObject(interfaceName, object); } /** Retrieve object by name. */ GAMMARAY_COMMON_EXPORT QObject* objectInternal(const QString &name, const QByteArray &type = QByteArray()); /** * Retrieve an object by name implementing interface @p T. * * Use this if multiple objects of the given type have been registered. * Otherwise the function below is simpler and more failsafe. * * NOTE: the "T = 0" is just to ensure a pointer type is given. */ template T object(const QString &name, T = 0) { T ret = qobject_cast(objectInternal(name, QByteArray(qobject_interface_iid()))); Q_ASSERT(ret); return ret; } /** * Retrieve object implementing interface @p T. * * This only works if a single type was registered implementing this interface * using qobject_interface_iid as object name. * * In most cases this is the simplest way for tools to get an object. * * NOTE: the "T = 0" is just to ensure a pointer type is given. */ template T object(T = 0) { const QByteArray interfaceName(qobject_interface_iid()); T ret = qobject_cast(objectInternal(QString::fromUtf8(interfaceName), interfaceName)); Q_ASSERT(ret); return ret; } typedef QObject*(*ClientObjectFactoryCallback)(const QString &, QObject *parent); /** Register a callback for a factory to create remote object stubs for the given type. */ GAMMARAY_COMMON_EXPORT void registerClientObjectFactoryCallbackInternal(const QByteArray &type, ClientObjectFactoryCallback callback); /** * Register a callback for a factory of a given interface to create remote object stubs for the given type. * * NOTE: the "T = 0" is just to ensure a pointer type is given. */ template void registerClientObjectFactoryCallback(ClientObjectFactoryCallback callback, T = 0) { registerClientObjectFactoryCallbackInternal(QByteArray(qobject_interface_iid()), callback); } /** * Register a newly created model with the given name. * * NOTE: This must not be called directly by anything but the probe/server side. * User code must use Probe::registerModel() instead! */ GAMMARAY_COMMON_EXPORT void registerModelInternal(const QString &name, QAbstractItemModel* model); /** Retrieve a model by name. */ GAMMARAY_COMMON_EXPORT QAbstractItemModel* model(const QString &name); typedef QAbstractItemModel*(*ModelFactoryCallback)(const QString &); /** Set a callback for the case that a model was requested but had not been registered before. */ GAMMARAY_COMMON_EXPORT void setModelFactoryCallback(ModelFactoryCallback callback); /** Register a newly created selection model. */ GAMMARAY_COMMON_EXPORT void registerSelectionModel(QItemSelectionModel *selectionModel); /** Unregisters a selection model. You have to take care of deletion yourself. */ GAMMARAY_COMMON_EXPORT void unregisterSelectionModel(QItemSelectionModel *selectionModel); /** Checks whether a selection model for the given @p model is registered already. */ GAMMARAY_COMMON_EXPORT bool hasSelectionModel(QAbstractItemModel* model); /** Retrieve the selection model for @p model. */ GAMMARAY_COMMON_EXPORT QItemSelectionModel* selectionModel(QAbstractItemModel *model); typedef QItemSelectionModel*(*selectionModelFactoryCallback)(QAbstractItemModel*); /** Set a callback for the case that a selection model was requested but had not been registered before. */ GAMMARAY_COMMON_EXPORT void setSelectionModelFactoryCallback(selectionModelFactoryCallback callback); /** @brief Clear all registered objects. * * This also destroys all objects created by factory methods registered here, but not externally * created objects that have just been registered here. * Useful when the probe is deleted, or the client lost the connection. */ GAMMARAY_COMMON_EXPORT void clear(); } } #endif // GAMMARAY_OBJECTBROKER_H gammaray-2.3.0/common/objectmodel.h000066400000000000000000000036751255003167400172600ustar00rootroot00000000000000/* objectmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares the public object model roles. @brief Declares the public object model roles. @author Volker Krause \ */ #ifndef GAMMARAY_OBJECTMODEL_H #define GAMMARAY_OBJECTMODEL_H #include namespace GammaRay { /** * @brief GammaRay Object Models. * * Public object model roles, for use by tool plugins without needing access * to the real object model classes. */ namespace ObjectModel { /** Role enum, to be used with the object list and tree models. */ enum Role { // Qt4 uses 32, Qt5 256, for Qt::UserRole - use the latter globally to allow combining Qt4/5 client/servers. ObjectRole = 256 + 1, /**< the Object role */ UserRole /**< the UserRole, as defined by Qt */ }; } } #endif gammaray-2.3.0/common/paths.cpp000066400000000000000000000053261255003167400164360ustar00rootroot00000000000000/* paths.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "paths.h" #include #include #include #include namespace GammaRay { namespace Paths { static QString s_rootPath; QString rootPath() { Q_ASSERT(!s_rootPath.isEmpty()); return s_rootPath; } void setRootPath(const QString& rootPath) { Q_ASSERT(!rootPath.isEmpty()); Q_ASSERT(QDir(rootPath).exists()); Q_ASSERT(QDir(rootPath).isAbsolute()); s_rootPath = rootPath; } void setRelativeRootPath(const char* relativeRootPath) { Q_ASSERT(relativeRootPath); setRootPath(QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String(relativeRootPath)); } QString probePath(const QString& probeABI) { #ifndef Q_OS_ANDROID return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_PLUGIN_INSTALL_DIR) + QDir::separator() + QLatin1String(GAMMARAY_PLUGIN_VERSION) + QDir::separator() + probeABI; #else Q_UNUSED(probeABI); return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_PLUGIN_INSTALL_DIR); #endif } QString binPath() { return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_BIN_INSTALL_DIR); } QString libexecPath() { return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_LIBEXEC_INSTALL_DIR); } QString currentProbePath() { return probePath(GAMMARAY_PROBE_ABI); } QString libraryExtension() { #ifdef Q_OS_WIN return QLatin1String(".dll"); #elif defined(Q_OS_MAC) return QLatin1String(".dylib"); #else return QLatin1String(".so"); #endif } QString pluginExtension() { #ifdef Q_OS_MAC return QLatin1String(".so"); #else return libraryExtension(); #endif } } } gammaray-2.3.0/common/paths.h000066400000000000000000000056171255003167400161060ustar00rootroot00000000000000/* paths.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PATHS_H #define GAMMARAY_PATHS_H #include "gammaray_common_export.h" class QString; namespace GammaRay { /** @brief Methods to determine install locations of the various bits of GammaRay. */ namespace Paths { /** Absolute path to the root of the GammaRay installation, anything else * is relative to this. */ GAMMARAY_COMMON_EXPORT QString rootPath(); /** Call this to set the root of the GammaRay install location, as early as * possible. The install location is usually determined by using * QCoreApplication::applicationDirPath() or the probe path, and the known relative * install location of the corresponding component. */ GAMMARAY_COMMON_EXPORT void setRootPath(const QString &rootPath); /** Convenience version of the above, for root paths relative to * QCoreApplication::applicationDirPath(). */ GAMMARAY_COMMON_EXPORT void setRelativeRootPath(const char* relativeRootPath); /** Returns the probe and plugin base path for the given probe ABI. * If @p probeABI is empty, the path containing the probes is returned. */ GAMMARAY_COMMON_EXPORT QString probePath(const QString& probeABI); /** Returns the path containing the GammaRay injector executable. */ GAMMARAY_COMMON_EXPORT QString binPath(); /** Returns the path containing helper executables. */ GAMMARAY_COMMON_EXPORT QString libexecPath(); /** Returns the path to the current probe location, probePath(GAMMARAY_PROBE_ABI). */ GAMMARAY_COMMON_EXPORT QString currentProbePath(); /** Returns the file extension used on the current platform for libraries. */ GAMMARAY_COMMON_EXPORT QString libraryExtension(); /** Returns the file extension used on the current platform for plugins. */ GAMMARAY_COMMON_EXPORT QString pluginExtension(); } } #endif // GAMMARAY_PATHS_H gammaray-2.3.0/common/plugininfo.cpp000066400000000000000000000103241255003167400174630ustar00rootroot00000000000000/* plugininfo.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "plugininfo.h" #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #include #include #include #endif using namespace GammaRay; PluginInfo::PluginInfo() : m_remoteSupport(true), m_hidden(false) { } PluginInfo::PluginInfo(const QString& path) : m_remoteSupport(true), m_hidden(false) { if (QLibrary::isLibrary(path)) { initFromJSON(path); } else if (path.endsWith(QLatin1String(".desktop"))) { initFromDesktopFile(path); } } QString PluginInfo::path() const { return m_path; } QString PluginInfo::id() const { return m_id; } QString PluginInfo::interface() const { return m_interface; } QStringList PluginInfo::supportedTypes() const { return m_supportedTypes; } bool PluginInfo::remoteSupport() const { return m_remoteSupport; } QString PluginInfo::name() const { return m_name; } bool PluginInfo::isHidden() const { return m_hidden; } bool PluginInfo::isValid() const { return !m_path.isEmpty() && !m_interface.isEmpty(); } void PluginInfo::initFromJSON(const QString& path) { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) const QPluginLoader loader(path); const QJsonObject metaData = loader.metaData(); m_interface = metaData.value("IID").toString(); const QJsonObject customData = metaData.value("MetaData").toObject(); m_id = customData.value("id").toString(); m_name = customData.value("name").toString(); m_remoteSupport = customData.value("remoteSupport").toBool(true); m_hidden = customData.value("hidden").toBool(false); const QJsonArray types = customData.value("types").toArray(); m_supportedTypes.reserve(types.size()); for (auto it = types.constBegin(); it != types.constEnd(); ++it) m_supportedTypes.push_back((*it).toString()); m_path = path; #else Q_UNUSED(path); #endif } void PluginInfo::initFromDesktopFile(const QString& path) { const QFileInfo fi(path); QSettings desktopFile(path, QSettings::IniFormat); desktopFile.beginGroup(QLatin1String("Desktop Entry")); m_id = desktopFile.value("X-GammaRay-Id", fi.baseName()).toString(); m_interface = desktopFile.value("X-GammaRay-ServiceTypes", QString()).toString(); m_supportedTypes = desktopFile.value(QLatin1String("X-GammaRay-Types")).toString().split(QLatin1Char(';'), QString::SkipEmptyParts); m_name = desktopFile.value(QLatin1String("Name")).toString(); m_remoteSupport = desktopFile.value(QLatin1String("X-GammaRay-Remote"), true).toBool(); m_hidden = desktopFile.value(QLatin1String("Hidden"), false).toBool(); const QString dllBaseName = desktopFile.value(QLatin1String("Exec")).toString(); if (dllBaseName.isEmpty()) return; foreach (const QString &entry, fi.dir().entryList(QStringList(dllBaseName + QLatin1Char('*')), QDir::Files)) { const QString pluginPath = fi.dir().absoluteFilePath(entry); if (QLibrary::isLibrary(pluginPath)) { m_path = pluginPath; break; } } } gammaray-2.3.0/common/plugininfo.h000066400000000000000000000037351255003167400171400ustar00rootroot00000000000000/* plugininfo.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PLUGININFO_H #define GAMMARAY_PLUGININFO_H #include #include namespace GammaRay { /** Meta-data about a specific plugin. * This abstracts Qt5-style embedded JSON data and Qt4-style desktop files. */ class PluginInfo { public: PluginInfo(); explicit PluginInfo(const QString &path); QString path() const; QString id() const; QString interface() const; QStringList supportedTypes() const; QString name() const; bool remoteSupport() const; bool isHidden() const; bool isValid() const; private: void initFromJSON(const QString &path); void initFromDesktopFile(const QString &path); QString m_path; QString m_id; QString m_interface; QStringList m_supportedTypes; QString m_name; bool m_remoteSupport; bool m_hidden; }; } #endif // GAMMARAY_PLUGININFO_H gammaray-2.3.0/common/pluginmanager.cpp000066400000000000000000000056651255003167400201560ustar00rootroot00000000000000/* pluginmanager.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pluginmanager.h" #include "paths.h" #include #include #include #include #include #include #define IF_DEBUG(x) using namespace GammaRay; using namespace std; PluginManagerBase::PluginManagerBase(QObject *parent) : m_parent(parent) { } PluginManagerBase::~PluginManagerBase() { } QStringList PluginManagerBase::pluginPaths() const { QStringList pluginPaths; pluginPaths.push_back(Paths::currentProbePath()); return pluginPaths; } QStringList PluginManagerBase::pluginFilter() const { QStringList filter; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) filter.push_back("*.desktop"); #elif defined(Q_OS_ANDROID) filter.push_back(QLatin1String("libplugins_gammaray_gammaray_*") + Paths::pluginExtension()); #else filter.push_back(QLatin1String("*") + Paths::pluginExtension()); #endif return filter; } void PluginManagerBase::scan(const QString &serviceType) { m_errors.clear(); QStringList loadedPluginNames; foreach (const QString &pluginPath, pluginPaths()) { const QDir dir(pluginPath); IF_DEBUG(cout << "checking plugin path: " << qPrintable(dir.absolutePath()) << endl); foreach (const QString &plugin, dir.entryList(pluginFilter(), QDir::Files)) { const QString pluginFile = dir.absoluteFilePath(plugin); const PluginInfo pluginInfo(pluginFile); if (!pluginInfo.isValid() || loadedPluginNames.contains(pluginInfo.id())) { continue; } if (pluginInfo.interface() != serviceType) { IF_DEBUG(qDebug() << Q_FUNC_INFO << "skipping" << pluginFile << "not supporting service type" << serviceType << "service types are: " << pluginInfo.interface();) continue; } if (createProxyFactory(pluginInfo, m_parent)) loadedPluginNames.push_back(pluginInfo.id()); } } } gammaray-2.3.0/common/pluginmanager.h000066400000000000000000000065511255003167400176160ustar00rootroot00000000000000/* pluginmanager.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PLUGINMANAGER_H #define GAMMARAY_PLUGINMANAGER_H #include "plugininfo.h" #include #include #include #include #include namespace GammaRay { class PluginLoadError; typedef QList PluginLoadErrors; class PluginLoadError { public: PluginLoadError(const QString &_pluginFile, const QString &_errorString) : pluginFile(_pluginFile), errorString(_errorString) { } QString pluginName() const { return QFileInfo(pluginFile).baseName(); } public: QString pluginFile; QString errorString; }; class PluginManagerBase { public: /** * @param parent This is the parent object for all objects created by the plugins */ explicit PluginManagerBase(QObject *parent = 0); ~PluginManagerBase(); QList errors() const { return m_errors; } protected: virtual bool createProxyFactory(const PluginInfo& pluginInfo, QObject* parent) = 0; void scan(const QString& serviceType); QStringList pluginPaths() const; QStringList pluginFilter() const; QList m_errors; QObject *m_parent; }; template class PluginManager : public PluginManagerBase { public: explicit inline PluginManager(QObject *parent = 0) : PluginManagerBase(parent) { const QString iid = QString::fromLatin1(qobject_interface_iid()); Q_ASSERT(!iid.isEmpty()); const QString serviceType = iid.split('/').first(); scan(serviceType); } inline ~PluginManager() {} inline QVector plugins() { return m_plugins; } protected: bool createProxyFactory(const PluginInfo& pluginInfo, QObject* parent) { Proxy *proxy = new Proxy(pluginInfo, parent); if (!proxy->isValid()) { m_errors << PluginLoadError(pluginInfo.path(), QObject::tr("Failed to load plugin: %1").arg(proxy->errorString())); std::cerr << "invalid plugin " << qPrintable(pluginInfo.path()) << std::endl; delete proxy; } else { m_plugins.push_back(proxy); return true; } return false; } private: QVector m_plugins; }; } #endif // GAMMARAY_PLUGINMANAGER_H gammaray-2.3.0/common/probeabi.cpp000066400000000000000000000132211255003167400170730ustar00rootroot00000000000000/* probeabi.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probeabi.h" #include #include #include #include #include namespace GammaRay { class ProbeABIPrivate : public QSharedData { public: ProbeABIPrivate() : majorQtVersion(-1), minorQtVersion(-1), isDebug(false) {} ProbeABIPrivate(const ProbeABIPrivate &other) : QSharedData(other), architecture(other.architecture), compiler(other.compiler), majorQtVersion(other.majorQtVersion), minorQtVersion(other.minorQtVersion), isDebug(other.isDebug) {} QString architecture; QString compiler; int majorQtVersion; int minorQtVersion; bool isDebug; }; } using namespace GammaRay; ProbeABI::ProbeABI() : d(new ProbeABIPrivate) { } ProbeABI::ProbeABI(const ProbeABI& other) : d(other.d) { } ProbeABI::~ProbeABI() { } ProbeABI& ProbeABI::operator=(const ProbeABI& other) { d = other.d; return *this; } int ProbeABI::majorQtVersion() const { return d->majorQtVersion; } int ProbeABI::minorQtVersion() const { return d->minorQtVersion; } void ProbeABI::setQtVersion(int major, int minor) { d->majorQtVersion = major; d->minorQtVersion = minor; } bool ProbeABI::hasQtVersion() const { return d->majorQtVersion > 0 && d->minorQtVersion >= 0; } QString ProbeABI::architecture() const { return d->architecture; } void ProbeABI::setArchitecture(const QString& architecture) { d->architecture = architecture; } QString ProbeABI::compiler() const { return d->compiler; } void ProbeABI::setCompiler(const QString& compiler) { d->compiler = compiler; } bool ProbeABI::isDebug() const { return d->isDebug; } void ProbeABI::setIsDebug(bool debug) { d->isDebug = debug; } bool ProbeABI::isDebugRelevant() const { return compiler() == "MSVC"; } bool ProbeABI::isValid() const { return hasQtVersion() && !d->architecture.isEmpty() #ifdef Q_OS_WIN && !d->compiler.isEmpty() #endif ; } bool ProbeABI::isCompatible(const ProbeABI& referenceABI) const { return d->majorQtVersion == referenceABI.majorQtVersion() && d->minorQtVersion >= referenceABI.minorQtVersion() // we can work with older probes, since the target defines the Qt libraries being used && d->architecture == referenceABI.architecture() #ifdef Q_OS_WIN && d->compiler == referenceABI.compiler() #endif && (isDebugRelevant() ? d->isDebug == referenceABI.isDebug() : true) ; } QString ProbeABI::id() const { if (!isValid()) return QString(); QStringList idParts; idParts.push_back(QString("qt%1.%2").arg(majorQtVersion()).arg(minorQtVersion())); #ifdef Q_OS_WIN idParts.push_back(compiler()); #endif if (isDebugRelevant()) idParts.push_back(isDebug() ? "debug" : "release"); idParts.push_back(architecture()); return idParts.join("-"); } ProbeABI ProbeABI::fromString(const QString& id) { QStringList idParts = id.split('-'); if (idParts.size() < 2) return ProbeABI(); int index = 0; ProbeABI abi; // version static QRegExp versionRegExp("^qt(\\d+)\\.(\\d+)$"); if (versionRegExp.indexIn(idParts.value(index++)) != 0) return ProbeABI(); abi.setQtVersion(versionRegExp.cap(1).toInt(), versionRegExp.cap(2).toInt()); // compiler #ifdef Q_OS_WIN abi.setCompiler(idParts.value(index++)); #endif // debug/release if (abi.isDebugRelevant()) { if (idParts.size() <= index) return ProbeABI(); const QString s = idParts.value(index++); if (s != "release" && s != "debug") return ProbeABI(); abi.setIsDebug(s == "debug"); } // architecture if (idParts.size() != index + 1) return ProbeABI(); abi.setArchitecture(idParts.value(index)); return abi; } QString ProbeABI::displayString() const { if (!isValid()) return QString(); QStringList details; #ifdef Q_OS_WIN details.push_back(compiler()); #endif if (isDebugRelevant()) details.push_back(isDebug() ? QObject::tr("debug") : QObject::tr("release")); details.push_back(architecture()); return QObject::tr("Qt %1.%2 (%3)") .arg(majorQtVersion()) .arg(minorQtVersion()) .arg(details.join(", ")); } bool ProbeABI::operator==(const ProbeABI& rhs) const { return majorQtVersion() == rhs.majorQtVersion() && minorQtVersion() == rhs.minorQtVersion() && architecture() == rhs.architecture() && compiler() == rhs.compiler() && isDebug() == rhs.isDebug(); } bool ProbeABI::operator<(const ProbeABI& rhs) const { if (majorQtVersion() == rhs.majorQtVersion()) return minorQtVersion() < rhs.minorQtVersion(); return majorQtVersion() < rhs.majorQtVersion(); } gammaray-2.3.0/common/probeabi.h000066400000000000000000000054571255003167400165540ustar00rootroot00000000000000/* probeabi.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBEABI_H #define GAMMARAY_PROBEABI_H #include namespace GammaRay { class ProbeABIPrivate; /** @brief Describes a probe ABI. * The probe ABI is everything that determines if a probe is compatible * with a given target or not. */ class ProbeABI { public: ProbeABI(); ProbeABI(const ProbeABI &other); ~ProbeABI(); ProbeABI& operator=(const ProbeABI &other); /** Qt version. */ int majorQtVersion() const; int minorQtVersion() const; void setQtVersion(int major, int minor); bool hasQtVersion() const; /** Processor architecture. */ QString architecture() const; void setArchitecture(const QString &architecture); /** Debug vs. release. */ bool isDebug() const; void setIsDebug(bool debug); /** Returns @c true if debug vs. release is changing the ABI. */ bool isDebugRelevant() const; /** Compiler ABI is currently only relevant for MSVC vs. Mingw. */ QString compiler() const; void setCompiler(const QString &compiler); /** Returns if this probe ABI is fully specified. */ bool isValid() const; /** Checks if this is ABI is compatible with @p referenceABI. */ bool isCompatible(const ProbeABI &referenceABI) const; bool operator==(const ProbeABI &rhs) const; /** @brief Orders probes by Qt version. * This is useful to pick the best matching one of multiple compatible ones. */ bool operator<(const ProbeABI &rhs) const; /** Conversion from and to probe ABI identifiers. */ QString id() const; static ProbeABI fromString(const QString& id); /** User-visible name of this ABI. */ QString displayString() const; private: QSharedDataPointer d; }; } #endif // GAMMARAY_PROBEABI_H gammaray-2.3.0/common/probeabidetector.cpp000066400000000000000000000105641255003167400206340ustar00rootroot00000000000000/* probeabidetector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "probeabidetector.h" #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif using namespace GammaRay; ProbeABIDetector::ProbeABIDetector() { } ProbeABIDetector::~ProbeABIDetector() { } ProbeABI ProbeABIDetector::abiForQtCore(const QString& path) const { QFileInfo fi(path); if (!fi.exists()) return ProbeABI(); const QHash::const_iterator it = m_abiForQtCoreCache.constFind(fi.canonicalFilePath()); if (it != m_abiForQtCoreCache.constEnd()) return it.value(); const ProbeABI abi = detectAbiForQtCore(fi.canonicalFilePath()); m_abiForQtCoreCache.insert(fi.canonicalFilePath(), abi); return abi; } QString ProbeABIDetector::qtCoreFromLsof(qint64 pid) const { QString lsofExe; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) lsofExe = QStandardPaths::findExecutable("lsof"); // on OSX it's in sbin, which usually but not always is in PATH... if (lsofExe.isEmpty()) lsofExe = QStandardPaths::findExecutable("lsof", QStringList() << "/usr/sbin" << "/sbin"); #endif if (lsofExe.isEmpty()) lsofExe = "lsof"; // maybe QProcess has more luck QProcess proc; proc.setProcessChannelMode(QProcess::SeparateChannels); proc.setReadChannel(QProcess::StandardOutput); proc.start(lsofExe, QStringList() << "-Fn" << "-n" << "-p" << QString::number(pid)); proc.waitForFinished(); forever { const QByteArray line = proc.readLine(); if (line.isEmpty()) break; if (containsQtCore(line)) { return QString::fromLocal8Bit(line.mid(1).trimmed()); // strip the field identifier } } return QString(); } static bool checkQtCorePrefix(const QByteArray &line, int index) { Q_ASSERT(index >= 0); if (index == 0) return true; // we either have a "lib" prefix, or some sort of separator if (index >= 3 && line.indexOf("lib", index - 3) == index - 3) return true; if ((line.at(index - 1) >= 'a' && line.at(index - 1) <= 'z') || (line.at(index - 1) >= 'A' && line.at(index - 1) <= 'Z')) { return false; } return true; } static bool checkQtCoreSuffix(const QByteArray &line, int index) { if (index >= line.size()) return false; Q_ASSERT(line.at(index - 2) == 'Q' && line.at(index - 1) == 't'); // skip version numbers while (index < line.size() && line.at(index) >= '0' && line.at(index) <= '9') ++index; if (line.indexOf("Core", index) != index) return false; // deal with the "d" and "_debug" debug suffixes index += 4; if (index < line.size() && line.at(index) == 'd') ++index; // "Core" must not be followed by another part of the name, so we don't trigger on eg. "QtCoreAddon" if (index < line.size() && ((line.at(index) >= 'a' && line.at(index) <= 'z') || (line.at(index) >= 'A' && line.at(index) <= 'Z'))) return false; return true; } bool ProbeABIDetector::containsQtCore(const QByteArray& line) { // Unix: libQt[X]Core.so[.X.Y.Z]$ // Mac: [^/]Qt[X]Core[_debug]$, [lib]Qt[X]Core[_debug].dylib[.X.Y.Z]$ // Windows Qt[X]Core[d].dll for (int index = 0; (index = line.indexOf("Qt", index)) >= 0; ++index) { if (!checkQtCorePrefix(line, index)) continue; if (checkQtCoreSuffix(line, index + 2)) return true; } return false; } gammaray-2.3.0/common/probeabidetector.h000066400000000000000000000047421255003167400203020ustar00rootroot00000000000000/* probeabidetector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBEABIDETECTOR_H #define GAMMARAY_PROBEABIDETECTOR_H #include "probeabi.h" #include #include namespace GammaRay { /** @brief Detect the probe ABI required for a given target. * A target can be specified as either a process id or a path to an executable to be launched. */ class ProbeABIDetector { public: ProbeABIDetector(); ~ProbeABIDetector(); /** Detect the ABI of the executable at @p path. */ ProbeABI abiForExecutable(const QString &path) const; /** Detect the ABI of the process running with PID @p pid. */ ProbeABI abiForProcess(qint64 pid) const; /** Check if the given line contains a mention of the QtCore library. */ static bool containsQtCore(const QByteArray &line); private: /** Returns the ABI of the given QtCore DLL. * Implementation of abiForXXX() should call this as it implements caching. */ ProbeABI abiForQtCore(const QString &path) const; /** Detect the ABI of the given QtCore DLL. * This needs to be implemented for every platform. */ ProbeABI detectAbiForQtCore(const QString &path) const; /** Path to the QtCore DLL for @p pid, using the lsof tool * on UNIX-like systems. */ QString qtCoreFromLsof(qint64 pid) const; mutable QHash m_abiForQtCoreCache; }; } #endif // GAMMARAY_PROBEABIDETECTOR_H gammaray-2.3.0/common/probeabidetector_dummy.cpp000066400000000000000000000032471255003167400220470ustar00rootroot00000000000000/* probeabidetector_dummy.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "probeabidetector.h" #include "probeabi.h" #include using namespace GammaRay; ProbeABI ProbeABIDetector::abiForExecutable(const QString& path) const { Q_UNUSED(path); return ProbeABI::fromString(GAMMARAY_PROBE_ABI); } ProbeABI ProbeABIDetector::abiForProcess(qint64 pid) const { Q_UNUSED(pid); return ProbeABI::fromString(GAMMARAY_PROBE_ABI); } ProbeABI ProbeABIDetector::detectAbiForQtCore(const QString& path) const { Q_UNUSED(path); return ProbeABI::fromString(GAMMARAY_PROBE_ABI); } gammaray-2.3.0/common/probeabidetector_elf.cpp000066400000000000000000000124651255003167400214640ustar00rootroot00000000000000/* probeabidetector_elf.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "probeabidetector.h" #include "probeabi.h" #include #include #include #include #include #ifdef HAVE_ELF_H #include #endif using namespace GammaRay; static QString qtCoreFromLdd(const QString &path) { QProcess proc; proc.setProcessChannelMode(QProcess::SeparateChannels); proc.setReadChannel(QProcess::StandardOutput); proc.start("ldd", QStringList() << path); proc.waitForFinished(); forever { const QByteArray line = proc.readLine(); if (line.isEmpty()) break; if (ProbeABIDetector::containsQtCore(line)) { const int begin = line.indexOf("=> "); const int end = line.lastIndexOf(" ("); if (begin <= 0 || end <= 0 || end <= begin) continue; return QString::fromLocal8Bit(line.mid(begin + 3, end - begin - 3).trimmed()); } } return QString(); } ProbeABI ProbeABIDetector::abiForExecutable(const QString& path) const { // TODO: add fast version reading the ELF file directly? const QString qtCorePath = qtCoreFromLdd(path); if (!qtCorePath.isEmpty()) return abiForQtCore(qtCorePath); return ProbeABI(); } static bool qtCoreFromProc(qint64 pid, QString &path) { const QString mapsPath = QString("/proc/%1/maps").arg(pid); QFile f(mapsPath); if (!f.open(QFile::ReadOnly)) { path.clear(); return false; } forever { const QByteArray line = f.readLine(); if (line.isEmpty()) break; if (ProbeABIDetector::containsQtCore(line)) { const int pos = line.indexOf('/'); if (pos <= 0) continue; path = QString::fromLocal8Bit(line.mid(pos).trimmed()); return true; } } path.clear(); return true; } ProbeABI ProbeABIDetector::abiForProcess(qint64 pid) const { QString qtCorePath; if (!qtCoreFromProc(pid, qtCorePath)) qtCorePath = qtCoreFromLsof(pid); return abiForQtCore(qtCorePath); } static ProbeABI qtVersionFromFileName(const QString &path) { ProbeABI abi; const QStringList parts = path.split('.'); if (parts.size() < 4 || parts.at(parts.size() - 4) != "so") return abi; abi.setQtVersion(parts.at(parts.size() - 3).toInt(), parts.at(parts.size() - 2).toInt()); return abi; } static ProbeABI qtVersionFromExec(const QString &path) { ProbeABI abi; // yep, you can actually execute QtCore.so... QProcess proc; proc.setReadChannelMode(QProcess::SeparateChannels); proc.setReadChannel(QProcess::StandardOutput); proc.start(path); proc.waitForFinished(); const QByteArray line = proc.readLine(); const int pos = line.lastIndexOf(' '); const QList version = line.mid(pos).split('.'); if (version.size() < 3) return abi; abi.setQtVersion(version.at(0).toInt(), version.at(1).toInt()); return abi; } #ifdef HAVE_ELF_H template static QString archFromELFHeader(const uchar *data, quint64 size) { if (size <= sizeof(ElfEHdr)) return QString(); const ElfEHdr *hdr = reinterpret_cast(data); switch (hdr->e_machine) { case EM_386: return "i686"; #ifdef EM_X86_64 case EM_X86_64: return "x86_64"; #endif case EM_ARM: return "arm"; } qWarning() << "Unsupported ELF machine type:" << hdr->e_machine; return QString(); } #endif static QString archFromELF(const QString &path) { #ifdef HAVE_ELF_H QFile f(path); if (!f.open(QFile::ReadOnly)) return QString(); const uchar* data = f.map(0, f.size()); if (!data || f.size() < EI_NIDENT) return QString(); if (qstrncmp(reinterpret_cast(data), ELFMAG, SELFMAG) != 0) // no ELF signature return QString(); switch (data[EI_CLASS]) { case ELFCLASS32: return archFromELFHeader(data, f.size()); case ELFCLASS64: return archFromELFHeader(data, f.size()); } #else Q_UNUSED(path); #endif return QString(); } ProbeABI ProbeABIDetector::detectAbiForQtCore(const QString& path) const { // try to find the version ProbeABI abi = qtVersionFromFileName(path); if (!abi.hasQtVersion()) abi = qtVersionFromExec(path); // TODO: architecture detection fallback without elf.h? const QString arch = archFromELF(path); abi.setArchitecture(arch); return abi; } gammaray-2.3.0/common/probeabidetector_mac.cpp000066400000000000000000000121331255003167400214460ustar00rootroot00000000000000/* probeabidetector_mac.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //krazy:excludeall=null since used by Darwin internals #include #include "probeabidetector.h" #include "probeabi.h" #include #include #include #include #include #include #include using namespace GammaRay; static QString resolveBundlePath(const QString &bundlePath) { const QFileInfo fi(bundlePath); if (!fi.isBundle()) return bundlePath; const QByteArray utf8Bundle = fi.absoluteFilePath().toUtf8(); CFURLRef bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast(utf8Bundle.data()), utf8Bundle.length(), true); CFBundleRef bundle = CFBundleCreate(NULL, bundleUrl); if (bundle) { CFURLRef url = CFBundleCopyExecutableURL(bundle); char executableFile[FILENAME_MAX]; CFURLGetFileSystemRepresentation(url, true, reinterpret_cast(executableFile), FILENAME_MAX); CFRelease(url); CFRelease(bundle); CFRelease(bundleUrl); return QString::fromUtf8(executableFile); } CFRelease(bundle); CFRelease(bundleUrl); return bundlePath; } static QString qtCoreFromOtool(const QString &path) { QProcess proc; proc.setProcessChannelMode(QProcess::SeparateChannels); proc.setReadChannel(QProcess::StandardOutput); proc.start("otool", QStringList() << "-L" << path); proc.waitForFinished(); forever { const QByteArray line = proc.readLine(); if (line.isEmpty()) break; if (ProbeABIDetector::containsQtCore(line)) { const int pos = line.lastIndexOf(" ("); if (pos <= 0) continue; return QString::fromLocal8Bit(line.left(pos).trimmed()); } } return QString(); } ProbeABI ProbeABIDetector::abiForExecutable(const QString& path) const { const QString qtCorePath = qtCoreFromOtool(resolveBundlePath(path)); if (qtCorePath.isEmpty()) return ProbeABI(); return abiForQtCore(qtCorePath); } ProbeABI ProbeABIDetector::abiForProcess(qint64 pid) const { const QString qtCorePath = qtCoreFromLsof(pid); if (qtCorePath.isEmpty()) return ProbeABI(); return abiForQtCore(qtCorePath); } template static QString readMachOHeader(const uchar* data, quint64 size, quint32 &offset, qint32 &ncmds, qint32 &cmdsize) { if (size <= sizeof(T)) return QString(); const T* header = reinterpret_cast(data); offset = sizeof(T); ncmds = header->ncmds; cmdsize = header->sizeofcmds; switch (header->cputype) { case CPU_TYPE_I386: return "i686"; case CPU_TYPE_X86_64: return "x86_64"; } return QString(); } static ProbeABI abiFromMachO(const uchar* data, qint64 size) { ProbeABI abi; const quint32 magic = *reinterpret_cast(data); quint32 offset = 0; qint32 ncmds = 0; qint32 cmdsize = 0; switch (magic) { case MH_MAGIC: abi.setArchitecture(readMachOHeader(data, size, offset, ncmds, cmdsize)); break; case MH_MAGIC_64: abi.setArchitecture(readMachOHeader(data, size, offset, ncmds, cmdsize)); break; } if (offset >= size || ncmds <= 0 || cmdsize <= 0 || size <= offset + cmdsize) return ProbeABI(); // read load commands for (int i = 0; i < ncmds; ++i) { const load_command* cmd = reinterpret_cast(data + offset); if (cmd->cmd == LC_ID_DYLIB) { const dylib_command* dlcmd = reinterpret_cast(data + offset); const int majorVersion = (dlcmd->dylib.current_version & 0x00ff0000) >> 16; const int minorVersion = (dlcmd->dylib.current_version & 0x0000ff00) >> 8; abi.setQtVersion(majorVersion, minorVersion); } offset += cmd->cmdsize; } return abi; } ProbeABI ProbeABIDetector::detectAbiForQtCore(const QString& path) const { QFile f(path); if (!f.open(QFile::ReadOnly)) return ProbeABI(); const uchar* data = f.map(0, f.size()); if (!data || (uint)f.size() <= sizeof(quint32)) return ProbeABI(); return abiFromMachO(data, f.size()); } gammaray-2.3.0/common/probeabidetector_win.cpp000066400000000000000000000157541255003167400215170ustar00rootroot00000000000000/* probeabidetector_win.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "probeabidetector.h" #include "probeabi.h" #include #include #include #include #include #include #include using namespace GammaRay; ProbeABI ProbeABIDetector::abiForExecutable(const QString& path) const { Q_UNUSED(path); return ProbeABI::fromString(GAMMARAY_PROBE_ABI); } ProbeABI ProbeABIDetector::abiForProcess(qint64 pid) const { MODULEENTRY32 me; me.dwSize = sizeof(MODULEENTRY32); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); if (snapshot == INVALID_HANDLE_VALUE) { return ProbeABI(); } for (bool hasNext = Module32First(snapshot, &me); hasNext; hasNext = Module32Next(snapshot, &me)) { const QString module = QString::fromUtf16(reinterpret_cast(me.szModule)); if (containsQtCore(module.toUtf8())) { const QString path = QString::fromUtf16(reinterpret_cast(me.szExePath)); CloseHandle(snapshot); return abiForQtCore(path); } } CloseHandle(snapshot); return ProbeABI(); } static QString archFromPEHeader(const IMAGE_FILE_HEADER *coffHdr) { switch(coffHdr->Machine) { case IMAGE_FILE_MACHINE_I386: return "i686"; case IMAGE_FILE_MACHINE_AMD64: return "x86_64"; } return QString(); } static const IMAGE_SECTION_HEADER* sectionForRVA(const IMAGE_FILE_HEADER *hdr, DWORD rva, const uchar *end) { const uchar *data = reinterpret_cast(hdr); const IMAGE_SECTION_HEADER* sectionHdr = reinterpret_cast(data + sizeof(IMAGE_FILE_HEADER) + hdr->SizeOfOptionalHeader); for (int i = 0; i < hdr->NumberOfSections; ++i, ++sectionHdr) { if (reinterpret_cast(sectionHdr +1) >= end) return 0; if (rva >= sectionHdr->VirtualAddress && rva < sectionHdr->VirtualAddress + sectionHdr->Misc.VirtualSize) return sectionHdr; } return 0; } static const uchar* rvaToFile(const IMAGE_FILE_HEADER *hdr, DWORD rva, const uchar *begin, const uchar *end) { const IMAGE_SECTION_HEADER* sectionHdr = sectionForRVA(hdr, rva, end); if (!sectionHdr) return 0; return begin + rva - sectionHdr->VirtualAddress + sectionHdr->PointerToRawData; } static QString compilerFromLibraries(const QStringList &libraries) { foreach (const QString &lib, libraries) { if (lib.toLower().startsWith(QLatin1String("libgcc"))) return "GNU"; } return "MSVC"; } static bool isDebugRuntime(const QStringList &libraries) { foreach (const QString &lib, libraries) { if (lib.toLower().startsWith(QLatin1String("msvcr"))) return lib.toLower().endsWith(QLatin1String("d.dll")); } return false; } ProbeABI ProbeABIDetector::detectAbiForQtCore(const QString& path) const { ProbeABI abi; // version DWORD pointlessHandle; DWORD fileVersionInfoSize = GetFileVersionInfoSize(reinterpret_cast(path.utf16()), &pointlessHandle); if (!fileVersionInfoSize) return ProbeABI(); BYTE *buffer = new BYTE[fileVersionInfoSize]; if (GetFileVersionInfoW(reinterpret_cast(path.utf16()), pointlessHandle, fileVersionInfoSize, buffer)) { void* versionInfoData; unsigned int versionInfoSize; if (VerQueryValue(buffer, TEXT("\\"), &versionInfoData, &versionInfoSize) && versionInfoSize) { VS_FIXEDFILEINFO *versionInfo = reinterpret_cast(versionInfoData); if (versionInfo->dwSignature == VS_FFI_SIGNATURE) { abi.setQtVersion(versionInfo->dwFileVersionMS >> 16, versionInfo->dwFileVersionMS & 0xffff); } } } delete[] buffer; // architecture and dependent libraries QFile f(path); if (!f.open(QFile::ReadOnly)) return ProbeABI(); const uchar* const begin = f.map(0, f.size()); const uchar* data = begin; const uchar* const end = begin + f.size(); if (!data || f.size() < sizeof(IMAGE_DOS_HEADER)) return ProbeABI(); const IMAGE_DOS_HEADER *dosHdr = reinterpret_cast(data); if (dosHdr->e_magic != IMAGE_DOS_SIGNATURE) return ProbeABI(); data += dosHdr->e_lfanew; if (data + sizeof(quint32) >= end) return ProbeABI(); const quint32 *peHdr = reinterpret_cast(data); if (*peHdr != IMAGE_NT_SIGNATURE) return ProbeABI(); data += sizeof(quint32); if (data + sizeof(IMAGE_FILE_HEADER) >= end) return ProbeABI(); // architecture const IMAGE_FILE_HEADER* coffHdr = reinterpret_cast(data); abi.setArchitecture(archFromPEHeader(coffHdr)); data += sizeof(IMAGE_FILE_HEADER); if (data + sizeof(IMAGE_OPTIONAL_HEADER64) >= end) return ProbeABI(); // import table const IMAGE_OPTIONAL_HEADER32 *optHdr32 = reinterpret_cast(data); if (optHdr32->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { data = rvaToFile(coffHdr, optHdr32->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, begin, end); } else { const IMAGE_OPTIONAL_HEADER64 *optHdr64 = reinterpret_cast(data); if (optHdr64->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return ProbeABI(); data = rvaToFile(coffHdr, optHdr64->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, begin, end); } if (data + sizeof(IMAGE_IMPORT_DESCRIPTOR) >= end) return ProbeABI(); const IMAGE_IMPORT_DESCRIPTOR* importDesc = reinterpret_cast(data); QStringList libs; while (importDesc->Name) { const char* libraryName = reinterpret_cast(rvaToFile(coffHdr, importDesc->Name, begin, end)); if (libraryName) libs.push_back(QString::fromAscii(libraryName)); importDesc++; if (reinterpret_cast(importDesc) + sizeof(IMAGE_IMPORT_DESCRIPTOR) >= end) return ProbeABI(); } // compiler and debug mode abi.setCompiler(compilerFromLibraries(libs)); if (abi.compiler() == "MSVC") abi.setIsDebug(isDebugRuntime(libs)); return abi; } gammaray-2.3.0/common/probecontrollerinterface.cpp000066400000000000000000000023741255003167400224130ustar00rootroot00000000000000/* probecontrollerinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probecontrollerinterface.h" using namespace GammaRay; ProbeControllerInterface::~ProbeControllerInterface() { } gammaray-2.3.0/common/probecontrollerinterface.h000066400000000000000000000033111255003167400220500ustar00rootroot00000000000000/* probecontrollerinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBECONTROLLERINTERFACE_H #define GAMMARAY_PROBECONTROLLERINTERFACE_H #include namespace GammaRay { /** Probe and host process remote control functions. */ class ProbeControllerInterface { public: virtual ~ProbeControllerInterface(); /** Terminate host application. */ virtual void quitHost() = 0; /** Detach GammaRay but keep host application running. */ virtual void detachProbe() = 0; }; } Q_DECLARE_INTERFACE(GammaRay::ProbeControllerInterface, "com.kdab.GammaRay.ProbeControllerInterface") #endif // GAMMARAY_PROBECONTROLLERINTERFACE_H gammaray-2.3.0/common/propertycontrollerinterface.cpp000066400000000000000000000036021255003167400231630ustar00rootroot00000000000000/* propertycontrollerinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertycontrollerinterface.h" #include "objectbroker.h" using namespace GammaRay; PropertyControllerInterface::PropertyControllerInterface(const QString &name, QObject *parent) : QObject(parent) , m_name(name) { ObjectBroker::registerObject(name, this); } PropertyControllerInterface::~PropertyControllerInterface() { } QString PropertyControllerInterface::name() const { return m_name; } QStringList PropertyControllerInterface::availableExtensions() const { return m_availableExtensions; } void PropertyControllerInterface::setAvailableExtensions(const QStringList& availableExtensions) { if (m_availableExtensions == availableExtensions) return; m_availableExtensions = availableExtensions; emit availableExtensionsChanged(); } gammaray-2.3.0/common/propertycontrollerinterface.h000066400000000000000000000041621255003167400226320ustar00rootroot00000000000000/* propertycontrollerinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYCONTROLLERINTERFACE_H #define GAMMARAY_PROPERTYCONTROLLERINTERFACE_H #include #include #include "enums.h" namespace GammaRay { /** @brief Client/Server interface of the property editor. */ class PropertyControllerInterface : public QObject { Q_OBJECT Q_PROPERTY(QStringList availableExtensions READ availableExtensions WRITE setAvailableExtensions NOTIFY availableExtensionsChanged) public: explicit PropertyControllerInterface(const QString &name, QObject *parent = 0); virtual ~PropertyControllerInterface(); QString name() const; QStringList availableExtensions() const; void setAvailableExtensions(const QStringList &availableExtensions); signals: void availableExtensionsChanged(); private: QString m_name; QStringList m_availableExtensions; }; } Q_DECLARE_INTERFACE(GammaRay::PropertyControllerInterface, "com.kdab.GammaRay.PropertyControllerInterface") #endif // GAMMARAY_PROPERTYCONTROLLERINTERFACE_H gammaray-2.3.0/common/propertymodel.h000066400000000000000000000036111255003167400176640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYMODEL_H #define GAMMARAY_PROPERTYMODEL_H namespace GammaRay { /** * @brief GammaRay property model roles. * * Public property model roles, for use by tool plugins without needing access * to the real property model classes. */ namespace PropertyModel { /** Role enum, to be used with the property models. */ enum Role { // Qt4 uses 32, Qt5 256, for Qt::UserRole - use the latter globally to allow combining Qt4/5 client/servers. ActionRole = 256 + 1, /**< the property action role */ UserRole , /**< the UserRole, as defined by Qt */ ValueRole, AppropriateToolRole }; /** Available property actions. */ enum Action { NoAction = 0, Delete = 1, Reset = 2, NavigateTo = 4 }; } } #endif gammaray-2.3.0/common/propertysyncer.cpp000066400000000000000000000160321255003167400204230ustar00rootroot00000000000000/* propertysyncer.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertysyncer.h" #include "message.h" #include #include #include using namespace GammaRay; static int qobjectPropertyOffset() { return QObject::staticMetaObject.propertyCount(); } PropertySyncer::PropertySyncer(QObject* parent) : QObject(parent), m_address(Protocol::InvalidObjectAddress), m_initialSync(false) { } PropertySyncer::~PropertySyncer() { } void PropertySyncer::setRequestInitialSync(bool initialSync) { m_initialSync = initialSync; } void PropertySyncer::addObject(Protocol::ObjectAddress addr, QObject* obj) { Q_ASSERT(addr != Protocol::InvalidObjectAddress); Q_ASSERT(obj); bool hasProperties = false; for (int i = qobjectPropertyOffset(); i < obj->metaObject()->propertyCount(); ++i) { const auto prop = obj->metaObject()->property(i); if (!prop.hasNotifySignal()) continue; connect(obj, QByteArray("2") + #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) prop.notifySignal().signature() #else prop.notifySignal().methodSignature() #endif , this, SLOT(propertyChanged())); hasProperties = true; } if (!hasProperties) { return; } connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); ObjectInfo info; info.addr = addr; info.obj = obj; info.recursionLock = false; info.enabled = false; m_objects.push_back(info); } void PropertySyncer::setObjectEnabled(Protocol::ObjectAddress addr, bool enabled) { const auto it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) { return info.addr == addr; }); if (it == m_objects.end() || (*it).enabled == enabled) return; (*it).enabled = enabled; if (enabled && m_initialSync) { Message msg(m_address, Protocol::PropertySyncRequest); msg.payload() << addr; emit message(msg); } } Protocol::ObjectAddress PropertySyncer::address() const { return m_address; } void PropertySyncer::setAddress(Protocol::ObjectAddress addr) { m_address = addr; } void PropertySyncer::handleMessage(const GammaRay::Message& msg) { Q_ASSERT(msg.address() == m_address); switch (msg.type()) { case Protocol::PropertySyncRequest: { Protocol::ObjectAddress addr; msg.payload() >> addr; Q_ASSERT(addr != Protocol::InvalidObjectAddress); const auto it = std::find_if(m_objects.constBegin(), m_objects.constEnd(), [addr](const ObjectInfo &info) { return info.addr == addr; }); if (it == m_objects.constEnd()) break; QVector > values; const auto propCount = (*it).obj->metaObject()->propertyCount(); values.reserve(propCount); for (int i = qobjectPropertyOffset(); i < propCount; ++i) { const auto prop = (*it).obj->metaObject()->property(i); values.push_back(qMakePair(QString(prop.name()), prop.read((*it).obj))); } Q_ASSERT(!values.isEmpty()); Message msg(m_address, Protocol::PropertyValuesChanged); msg.payload() << addr << (quint32)values.size(); foreach (const auto &value, values) msg.payload() << value.first << value.second; emit message(msg); break; } case Protocol::PropertyValuesChanged: { Protocol::ObjectAddress addr; quint32 changeSize; msg.payload() >> addr >> changeSize; Q_ASSERT(addr != Protocol::InvalidObjectAddress); Q_ASSERT(changeSize > 0); auto it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) { return info.addr == addr; }); if (it == m_objects.end()) break; for (quint32 i = 0; i < changeSize; ++i) { QString propName; QVariant propValue; msg.payload() >> propName >> propValue; (*it).recursionLock = true; (*it).obj->setProperty(propName.toUtf8(), propValue); // it can be invalid if as a result of the above call new objects have been registered for example it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) { return info.addr == addr; }); Q_ASSERT(it != m_objects.end()); (*it).recursionLock = false; } break; } default: Q_ASSERT(!"We should not get here!"); } } void PropertySyncer::propertyChanged() { const auto *obj = sender(); Q_ASSERT(obj); const auto it = std::find_if(m_objects.constBegin(), m_objects.constEnd(), [obj](const ObjectInfo &info) { return info.obj == obj; }); Q_ASSERT(it != m_objects.constEnd()); if ((*it).recursionLock || !(*it).enabled) return; const auto sigIndex = senderSignalIndex(); QVector > changes; for (int i = qobjectPropertyOffset(); i < obj->metaObject()->propertyCount(); ++i) { const auto prop = obj->metaObject()->property(i); if (prop.notifySignalIndex() != sigIndex) continue; changes.push_back(qMakePair(QString(prop.name()), prop.read(obj))); } Q_ASSERT(!changes.isEmpty()); Message msg(m_address, Protocol::PropertyValuesChanged); msg.payload() << (*it).addr << (quint32)changes.size(); foreach (const auto &change, changes) msg.payload() << change.first << change.second; emit message(msg); } void PropertySyncer::objectDestroyed(QObject* obj) { const auto it = std::find_if(m_objects.begin(), m_objects.end(), [obj](const ObjectInfo &info) { return info.obj == obj; }); Q_ASSERT(it != m_objects.end()); m_objects.erase(it); } gammaray-2.3.0/common/propertysyncer.h000066400000000000000000000057061255003167400200760ustar00rootroot00000000000000/* propertysyncer.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYSYNCER_H #define GAMMARAY_PROPERTYSYNCER_H #include "gammaray_common_export.h" #include #include #include namespace GammaRay { class Message; /** Infrastructure for syncing property values between a local and a remote object. */ class GAMMARAY_COMMON_EXPORT PropertySyncer : public QObject { Q_OBJECT public: explicit PropertySyncer(QObject *parent = 0); ~PropertySyncer(); /** Add an object that should be monitored for to be synced property changes. */ void addObject(Protocol::ObjectAddress addr, QObject *obj); /** Enable property syncing for the object with address @p addr. * Use this to suspend property syncing for objects that aren't used on the client. * Property syncing is disabled by default. */ void setObjectEnabled(Protocol::ObjectAddress addr, bool enabled); /** Object address of the property syncer, for communicating with the other side. */ Protocol::ObjectAddress address() const; void setAddress(Protocol::ObjectAddress addr); /** Request the initial property states when adding new objects. * This is typically enabled on the client side. */ void setRequestInitialSync(bool initialSync); public slots: /** Feed in incoming network messages here. */ void handleMessage(const GammaRay::Message &msg); signals: /** Outgoing network messages, send those via Endpoint. */ void message(const GammaRay::Message &msg); private slots: void propertyChanged(); void objectDestroyed(QObject* obj); private: struct ObjectInfo { Protocol::ObjectAddress addr; QObject *obj; bool recursionLock; bool enabled; }; QVector m_objects; Protocol::ObjectAddress m_address; bool m_initialSync; }; } #endif // GAMMARAY_PROPERTYSYNCER_H gammaray-2.3.0/common/protocol.cpp000066400000000000000000000036011255003167400171520ustar00rootroot00000000000000/* protocol.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "protocol.h" namespace GammaRay { namespace Protocol { Protocol::ModelIndex fromQModelIndex(const QModelIndex& index) { if (!index.isValid()) return ModelIndex(); ModelIndex result = fromQModelIndex(index.parent()); result.push_back(qMakePair(index.row(), index.column())); return result; } QModelIndex toQModelIndex(const QAbstractItemModel* model, const Protocol::ModelIndex& index) { QModelIndex qmi; for (int i = 0; i < index.size(); ++i) { qmi = model->index(index.at(i).first, index.at(i).second, qmi); if (!qmi.isValid()) { return QModelIndex(); // model isn't loaded to the full depth, so don't restart from the top } } return qmi; } qint32 version() { return 14; } qint32 broadcastFormatVersion() { return 2; } } } gammaray-2.3.0/common/protocol.h000066400000000000000000000061241255003167400166220ustar00rootroot00000000000000/* protocol.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROTOCOL_H #define GAMMARAY_PROTOCOL_H #include "gammaray_common_export.h" #include #include #include #include namespace GammaRay { /** @brief Helper functions and constants defining the communication protocol between client and server. */ namespace Protocol { typedef qint32 PayloadSize; typedef quint8 ObjectAddress; typedef quint8 MessageType; static const ObjectAddress InvalidObjectAddress = 0; static const ObjectAddress LauncherAddress = 255; static const MessageType InvalidMessageType = 0; enum BuildInMessageType { // object management // client -> server ObjectMonitored = InvalidMessageType + 1, ObjectUnmonitored, // server -> client ServerVersion, ObjectMapReply, ObjectAdded, ObjectRemoved, // remote model messages // client -> server ModelRowColumnCountRequest, ModelContentRequest, ModelHeaderRequest, ModelSetDataRequest, ModelSyncBarrier, // server -> client ModelRowColumnCountReply, ModelContentReply, ModelContentChanged, ModelHeaderReply, ModelHeaderChanged, ModelRowsAdded, ModelRowsMoved, ModelRowsRemoved, ModelColumnsAdded, ModelColumnsMoved, ModelColumnsRemoved, ModelReset, ModelLayoutChanged, // server <-> client SelectionModelSelect, SelectionModelCurrent, MethodCall, PropertySyncRequest, PropertyValuesChanged, ServerInfo, // probe settings provided by the launcher ProbeSettings, ServerAddress }; typedef QVector > ModelIndex; /** Serializes a QModelIndex. */ GAMMARAY_COMMON_EXPORT ModelIndex fromQModelIndex(const QModelIndex &index); /** Deserializes a QModelIndex. */ GAMMARAY_COMMON_EXPORT QModelIndex toQModelIndex(const QAbstractItemModel *model, const ModelIndex &index); /** Protocol version, must match exactly between client and server. */ GAMMARAY_COMMON_EXPORT qint32 version(); /** Broadcast format version. */ GAMMARAY_COMMON_EXPORT qint32 broadcastFormatVersion(); } } #endif gammaray-2.3.0/common/proxyfactorybase.cpp000066400000000000000000000036741255003167400207270ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "proxyfactorybase.h" #include #include using namespace GammaRay; ProxyFactoryBase::ProxyFactoryBase(const PluginInfo& pluginInfo, QObject* parent): QObject(parent), m_factory(0), m_pluginInfo(pluginInfo) { } ProxyFactoryBase::~ProxyFactoryBase() { } PluginInfo ProxyFactoryBase::pluginInfo() const { return m_pluginInfo; } QString ProxyFactoryBase::errorString() const { return m_errorString; } void ProxyFactoryBase::loadPlugin() { if (m_factory) return; QPluginLoader loader(pluginInfo().path(), this); m_factory = loader.instance(); if (m_factory) { m_factory->setParent(this); } else { m_errorString = loader.errorString(); std::cerr << "error loading plugin " << qPrintable(pluginInfo().path()) << ": " << qPrintable(loader.errorString()) << std::endl; } } gammaray-2.3.0/common/proxyfactorybase.h000066400000000000000000000047571255003167400203770ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROXYFACTORYBASE_H #define GAMMARAY_PROXYFACTORYBASE_H #include "plugininfo.h" #include #include #include namespace GammaRay { /** Base class for wrappers for potentially not yet loaded plugins. */ class ProxyFactoryBase : public QObject { Q_OBJECT public: explicit ProxyFactoryBase(const PluginInfo &pluginInfo, QObject *parent = 0); ~ProxyFactoryBase(); PluginInfo pluginInfo() const; QString errorString() const; protected: void loadPlugin(); QObject *m_factory; QString m_errorString; private: PluginInfo m_pluginInfo; }; template class ProxyFactory : public ProxyFactoryBase, public IFace { public: explicit inline ProxyFactory(const PluginInfo &pluginInfo, QObject *parent = 0) : ProxyFactoryBase(pluginInfo, parent) {} inline ~ProxyFactory() {} inline /*override*/ QString id() const { return pluginInfo().id(); } protected: IFace *factory() { loadPlugin(); IFace *iface = qobject_cast(m_factory); if (!iface) { m_errorString = QObject::tr("Plugin does not provide an instance of %1."). arg(qobject_interface_iid()); std::cerr << "Failed to cast object from " << qPrintable(pluginInfo().path()) << " to " << qobject_interface_iid() << std::endl; } return iface; } }; } #endif // GAMMARAY_PROXYFACTORYBASE_H gammaray-2.3.0/common/resourcebrowserinterface.cpp000066400000000000000000000026641255003167400224350ustar00rootroot00000000000000/* resourcebrowserinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "resourcebrowserinterface.h" #include "objectbroker.h" using namespace GammaRay; ResourceBrowserInterface::ResourceBrowserInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } ResourceBrowserInterface::~ResourceBrowserInterface() { } gammaray-2.3.0/common/resourcebrowserinterface.h000066400000000000000000000040151255003167400220720ustar00rootroot00000000000000/* resourcebrowserinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_RESOURCEBROWSERINTERFACE_H #define GAMMARAY_RESOURCEBROWSERINTERFACE_H #include class QPixmap; namespace GammaRay { class ResourceBrowserInterface : public QObject { Q_OBJECT public: explicit ResourceBrowserInterface(QObject *parent = 0); virtual ~ResourceBrowserInterface(); public slots: virtual void downloadResource(const QString &sourceFilePath, const QString &targetFilePath) = 0; signals: void resourceDeselected(); void resourceSelected(const QPixmap &pixmap); void resourceSelected(const QByteArray &contents); void resourceDownloaded(const QString &targetFilePath, const QPixmap &pixmap); void resourceDownloaded(const QString &targetFilePath, const QByteArray &contents); }; } Q_DECLARE_INTERFACE(GammaRay::ResourceBrowserInterface, "com.kdab.GammaRay.ResourceBrowserInterface") #endif // GAMMARAY_RESOURCEBROWSERINTERFACE_H gammaray-2.3.0/common/settempvalue.h000066400000000000000000000031761255003167400175030ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SETTEMPVALUE_H #define GAMMARAY_SETTEMPVALUE_H namespace GammaRay { /** * @brief GammaRay utilities. */ namespace Util { /** * Temporarily overwrite a given object with a new value and reset the value * when the scope is exited. */ template struct SetTempValue { SetTempValue(T& obj, T newValue) : obj(obj) , oldValue(obj) { obj = newValue; } ~SetTempValue() { obj = oldValue; } T& obj; T oldValue; }; } } #endif // GAMMARAY_SETTEMPVALUE_H gammaray-2.3.0/common/sharedmemorylocker.h000066400000000000000000000031571255003167400206630ustar00rootroot00000000000000/* sharedmemorylocker.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SHAREDMEMORYLOCKER_H #define GAMMARAY_SHAREDMEMORYLOCKER_H #include namespace GammaRay { #ifndef QT_NO_SHAREDMEMORY /** RAII helper class for locking QSharedMemory. * @todo this should be upstream */ class SharedMemoryLocker { public: explicit inline SharedMemoryLocker(QSharedMemory *shm) : m_shm(shm) { Q_ASSERT(shm); shm->lock(); } inline ~SharedMemoryLocker() { m_shm->unlock(); } private: QSharedMemory *m_shm; }; #endif } #endif gammaray-2.3.0/common/streamoperators.cpp000066400000000000000000000040631255003167400205460ustar00rootroot00000000000000/* streamoperators.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "streamoperators.h" #include "enums.h" #include "metatypedeclarations.h" #include "variantwrapper.h" #include #include using namespace GammaRay; #define MAKE_ENUM_OPERATORS(enumType) \ QDataStream &operator<<(QDataStream &out, enumType value) \ { \ out << qint32(value); \ return out; \ } \ \ QDataStream &operator>>(QDataStream &in, enumType &value) \ { \ qint32 t; \ in >> t; \ value = static_cast(t); \ return in; \ } MAKE_ENUM_OPERATORS(QMetaMethod::MethodType) MAKE_ENUM_OPERATORS(PropertyWidgetDisplayState::State) MAKE_ENUM_OPERATORS(Qt::ConnectionType) void StreamOperators::registerOperators() { qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); } gammaray-2.3.0/common/streamoperators.h000066400000000000000000000026151255003167400202140ustar00rootroot00000000000000/* streamoperators.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STREAMOPERATORS_H #define GAMMARAY_STREAMOPERATORS_H namespace GammaRay { /** Custom QDataStream streaming operators. */ namespace StreamOperators { /** Call once early during startup. */ void registerOperators(); } } #endif // GAMMARAY_STREAMOPERATORS_H gammaray-2.3.0/common/tools/000077500000000000000000000000001255003167400157455ustar00rootroot00000000000000gammaray-2.3.0/common/tools/objectinspector/000077500000000000000000000000001255003167400211425ustar00rootroot00000000000000gammaray-2.3.0/common/tools/objectinspector/connectionsextensioninterface.cpp000066400000000000000000000030631255003167400300100ustar00rootroot00000000000000/* connectionsextensioninterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionsextensioninterface.h" #include using namespace GammaRay; ConnectionsExtensionInterface::ConnectionsExtensionInterface(const QString& name, QObject* parent): QObject(parent), m_name(name) { ObjectBroker::registerObject(name, this); } ConnectionsExtensionInterface::~ConnectionsExtensionInterface() { } QString ConnectionsExtensionInterface::name() const { return m_name; } gammaray-2.3.0/common/tools/objectinspector/connectionsextensioninterface.h000066400000000000000000000036101255003167400274530ustar00rootroot00000000000000/* connectionsextensioninterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONSEXTENSIONINTERFACE_H #define GAMMARAY_CONNECTIONSEXTENSIONINTERFACE_H #include namespace GammaRay { /** Communication interface for the connections tab in the property view. */ class ConnectionsExtensionInterface : public QObject { Q_OBJECT public: explicit ConnectionsExtensionInterface(const QString &name, QObject *parent = 0); ~ConnectionsExtensionInterface(); QString name() const; public slots: virtual void navigateToSender(int modelRow) = 0; virtual void navigateToReceiver(int modelRow) = 0; private: QString m_name; }; } Q_DECLARE_INTERFACE(GammaRay::ConnectionsExtensionInterface, "com.kdab.GammaRay.ConnectionsExtensionInterface") #endif // GAMMARAY_CONNECTIONSEXTENSIONINTERFACE_H gammaray-2.3.0/common/tools/objectinspector/connectionsmodelroles.h000066400000000000000000000032041255003167400257220ustar00rootroot00000000000000/* modelroles.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONSMODELROLES_H #define GAMMARAY_CONNECTIONSMODELROLES_H #include namespace GammaRay { /** @brief Roles for the object inspector connections models. */ namespace ConnectionsModelRoles { enum Role { WarningFlagRole = UserRole + 1, EndpointRole, ActionRole }; } /** @brief Connection actions. * Returns via ActionRole from the connections models. */ namespace ConnectionsModelActions { enum Action { NoAction = 0, NavigateToEndpoint = 1 }; } } #endif gammaray-2.3.0/common/tools/objectinspector/methodsextensioninterface.cpp000066400000000000000000000034451255003167400271350ustar00rootroot00000000000000/* methodsextensioninterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodsextensioninterface.h" #include "objectbroker.h" using namespace GammaRay; MethodsExtensionInterface::MethodsExtensionInterface(const QString &name, QObject *parent) : QObject(parent) , m_name(name) , m_hasObject(false) { ObjectBroker::registerObject(name, this); } MethodsExtensionInterface::~MethodsExtensionInterface() { } const QString &MethodsExtensionInterface::name() const { return m_name; } bool MethodsExtensionInterface::hasObject() const { return m_hasObject; } void MethodsExtensionInterface::setHasObject(bool hasObject) { if (m_hasObject == hasObject) return; m_hasObject = hasObject; emit hasObjectChanged(); } gammaray-2.3.0/common/tools/objectinspector/methodsextensioninterface.h000066400000000000000000000041401255003167400265730ustar00rootroot00000000000000/* methodsextensioninterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METHODSEXTENSIONINTERFACE_H #define GAMMARAY_METHODSEXTENSIONINTERFACE_H #include namespace GammaRay { /** @brief Client/Server interface of the methods viewer. */ class MethodsExtensionInterface : public QObject { Q_OBJECT Q_PROPERTY(bool hasObject READ hasObject WRITE setHasObject NOTIFY hasObjectChanged) public: explicit MethodsExtensionInterface(const QString &name, QObject *parent = 0); virtual ~MethodsExtensionInterface(); const QString &name() const; bool hasObject() const; void setHasObject(bool hasObject); signals: void hasObjectChanged(); public slots: virtual void activateMethod() = 0; virtual void invokeMethod(Qt::ConnectionType type) = 0; virtual void connectToSignal() = 0; private: QString m_name; bool m_hasObject; }; } Q_DECLARE_INTERFACE(GammaRay::MethodsExtensionInterface, "com.kdab.GammaRay.MethodsExtensionInterface") #endif // GAMMARAY_METHODSEXTENSIONINTERFACE_H gammaray-2.3.0/common/tools/objectinspector/propertiesextensioninterface.cpp000066400000000000000000000035311255003167400276620ustar00rootroot00000000000000/* propertycontrollerinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertiesextensioninterface.h" #include "objectbroker.h" using namespace GammaRay; PropertiesExtensionInterface::PropertiesExtensionInterface(const QString &name, QObject *parent) : QObject(parent) , m_name(name) , m_canAddProperty(false) { ObjectBroker::registerObject(name, this); } PropertiesExtensionInterface::~PropertiesExtensionInterface() { } const QString &PropertiesExtensionInterface::name() const { return m_name; } bool PropertiesExtensionInterface::canAddProperty() const { return m_canAddProperty; } void PropertiesExtensionInterface::setCanAddProperty(bool canAdd) { if (m_canAddProperty == canAdd) return; m_canAddProperty = canAdd; emit canAddPropertyChanged(); } gammaray-2.3.0/common/tools/objectinspector/propertiesextensioninterface.h000066400000000000000000000043201255003167400273240ustar00rootroot00000000000000/* propertycontrollerinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTIESEXTENSIONINTERFACE_H #define GAMMARAY_PROPERTIESEXTENSIONINTERFACE_H #include namespace GammaRay { /** @brief Client/Server interface of the property editor. */ class PropertiesExtensionInterface : public QObject { Q_OBJECT Q_PROPERTY(bool canAddProperty READ canAddProperty WRITE setCanAddProperty NOTIFY canAddPropertyChanged) public: explicit PropertiesExtensionInterface(const QString &name, QObject *parent = 0); virtual ~PropertiesExtensionInterface(); const QString &name() const; bool canAddProperty() const; void setCanAddProperty(bool canAdd); public slots: virtual void navigateToValue(int modelRow) = 0; virtual void setProperty(const QString &name, const QVariant &value) = 0; virtual void resetProperty(const QString &name) = 0; signals: void canAddPropertyChanged(); private: QString m_name; bool m_canAddProperty; }; } Q_DECLARE_INTERFACE(GammaRay::PropertiesExtensionInterface, "com.kdab.GammaRay.PropertiesExtensionInterface") #endif // GAMMARAY_PROPERTIESEXTENSIONINTERFACE_H gammaray-2.3.0/common/variantwrapper.h000066400000000000000000000040531255003167400200250ustar00rootroot00000000000000/* variantwrapper.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in acuordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_VARIANTWRAPPER_H #define GAMMARAY_VARIANTWRAPPER_H #include #include namespace GammaRay { /** Transport wrapper for variants that shall not be unpacked by GammaRay::MethodArgument. */ class VariantWrapper { public: inline VariantWrapper() {} explicit inline VariantWrapper(const QVariant &variant) : m_variant(variant) {} inline ~VariantWrapper() {} inline QVariant variant() const { return m_variant; } inline void setVariant(const QVariant &v) { m_variant = v; } inline operator QVariant() const { return QVariant::fromValue(*this); } private: QVariant m_variant; }; inline QDataStream &operator<<(QDataStream &out, const VariantWrapper& wrapper) { out << wrapper.variant(); return out; } inline QDataStream &operator>>(QDataStream &in, VariantWrapper &value) { QVariant v; in >> v; value.setVariant(v); return in; } } Q_DECLARE_METATYPE(GammaRay::VariantWrapper) #endif gammaray-2.3.0/config-gammaray-version.h.cmake000066400000000000000000000003511255003167400212700ustar00rootroot00000000000000#define GAMMARAY_VERSION_MAJOR ${GAMMARAY_VERSION_MAJOR} #define GAMMARAY_VERSION_MINOR ${GAMMARAY_VERSION_MINOR} #define GAMMARAY_VERSION_PATCH ${GAMMARAY_VERSION_PATCH} #define GAMMARAY_VERSION_STRING "${GAMMARAY_VERSION_STRING}" gammaray-2.3.0/config-gammaray.h.cmake000066400000000000000000000024171255003167400176120ustar00rootroot00000000000000#include // relative install dirs #ifdef Q_OS_ANDROID # define GAMMARAY_PLUGIN_INSTALL_DIR "lib" #else # define GAMMARAY_PLUGIN_INSTALL_DIR "${PLUGIN_INSTALL_DIR}" #endif #define GAMMARAY_LIBEXEC_INSTALL_DIR "${LIBEXEC_INSTALL_DIR}" #define GAMMARAY_BIN_INSTALL_DIR "${BIN_INSTALL_DIR}" #define GAMMARAY_PLUGIN_VERSION "${GAMMARAY_PLUGIN_VERSION}" #define GAMMARAY_PROBE_ABI "${GAMMARAY_PROBE_ABI}" // relative inverse install dirs #define GAMMARAY_INVERSE_BIN_DIR "${GAMMARAY_INVERSE_BIN_DIR}" #define GAMMARAY_INVERSE_PROBE_DIR "${GAMMARAY_INVERSE_PROBE_DIR}" #define GAMMARAY_INVERSE_LIBEXEC_DIR "${GAMMARAY_INVERSE_LIBEXEC_DIR}" // probe name #ifdef Q_OS_ANDROID #define GAMMARAY_PROBE_NAME "libgammaray_probe" #else #define GAMMARAY_PROBE_NAME "gammaray_probe" #endif // build options #cmakedefine BUILD_TIMER_PLUGIN #cmakedefine HAVE_PRIVATE_QT_HEADERS #cmakedefine HAVE_STDINT_H #cmakedefine HAVE_QT_WIDGETS #cmakedefine HAVE_QT_SVG #cmakedefine HAVE_QT_DESIGNER #cmakedefine HAVE_QT_PRINTSUPPORT #cmakedefine HAVE_QT_WEBKIT1 #cmakedefine HAVE_VTK #cmakedefine HAVE_GRAPHVIZ #cmakedefine HAVE_ELF_H #if !defined(QT_NO_SHAREDMEMORY) && !defined(QT_NO_SYSTEMSEMAPHORE) && !defined(Q_OS_ANDROID) #define HAVE_SHM #endif #cmakedefine GAMMARAY_UNKNOWN_CXX_MANGLED_NAMES gammaray-2.3.0/core/000077500000000000000000000000001255003167400142455ustar00rootroot00000000000000gammaray-2.3.0/core/CMakeLists.txt000066400000000000000000000107671255003167400170200ustar00rootroot00000000000000set(gammaray_srcs ${CMAKE_SOURCE_DIR}/3rdparty/qt/resourcemodel.cpp aggregatedpropertymodel.cpp metaobject.cpp metaobjecttreemodel.cpp metaobjectrepository.cpp metaproperty.cpp metapropertymodel.cpp probe.cpp probeguard.cpp probesettings.cpp probecontroller.cpp # proxydetacher.cpp objectlistmodel.cpp objectpropertymodel.cpp objectdynamicpropertymodel.cpp objectstaticpropertymodel.cpp objectclassinfomodel.cpp objectmethodmodel.cpp objectenummodel.cpp objecttreemodel.cpp connectionmodel.cpp connectionfilterproxymodel.cpp methodargumentmodel.cpp multisignalmapper.cpp signalspycallbackset.cpp toolmodel.cpp toolpluginmodel.cpp toolpluginerrormodel.cpp propertycontroller.cpp propertycontrollerextension.cpp proxytoolfactory.cpp util.cpp varianthandler.cpp tools/modelinspector/modeltester.cpp tools/modelinspector/modelmodel.cpp tools/modelinspector/modelcellmodel.cpp tools/metatypebrowser/metatypesmodel.cpp tools/localeinspector/localemodel.cpp tools/localeinspector/localedataaccessor.cpp tools/localeinspector/localeaccessormodel.cpp tools/textdocumentinspector/textdocumentmodel.cpp tools/textdocumentinspector/textdocumentformatmodel.cpp tools/messagehandler/messagehandler.cpp tools/messagehandler/messagehandlerinterface.cpp tools/messagehandler/messagemodel.cpp tools/connectioninspector/connectioninspector.cpp tools/localeinspector/localeinspector.cpp tools/metaobjectbrowser/metaobjectbrowser.cpp tools/metatypebrowser/metatypebrowser.cpp tools/modelinspector/modelinspector.cpp tools/modelinspector/safetyfilterproxymodel.cpp tools/objectinspector/objectinspector.cpp tools/objectinspector/propertiesextension.cpp tools/objectinspector/methodsextension.cpp tools/objectinspector/connectionsextension.cpp tools/objectinspector/abstractconnectionsmodel.cpp tools/objectinspector/inboundconnectionsmodel.cpp tools/objectinspector/outboundconnectionsmodel.cpp tools/objectinspector/enumsextension.cpp tools/objectinspector/classinfoextension.cpp tools/resourcebrowser/resourcebrowser.cpp tools/resourcebrowser/resourcefiltermodel.cpp tools/textdocumentinspector/textdocumentinspector.cpp remote/server.cpp remote/remotemodelserver.cpp remote/selectionmodelserver.cpp remote/serverdevice.cpp remote/tcpserverdevice.cpp remote/localserverdevice.cpp remote/serverproxymodel.cpp ) if(Qt5Core_FOUND) set(gammaray_srcs ${gammaray_srcs} tools/mimetypes/mimetypes.cpp tools/mimetypes/mimetypesmodel.cpp tools/standardpaths/standardpaths.cpp tools/standardpaths/standardpathsmodel.cpp ) endif() if(NOT WIN32) set(gammaray_srcs ${gammaray_srcs} tools/messagehandler/backtrace_unix.cpp) elseif(MINGW) set(gammaray_srcs ${gammaray_srcs} tools/messagehandler/backtrace_dummy.cpp) else() set(gammaray_srcs ${gammaray_srcs} tools/messagehandler/backtrace_win.cpp ${CMAKE_SOURCE_DIR}/3rdparty/StackWalker/StackWalker.cpp) endif() qt4_wrap_cpp(gammaray_srcs ${CMAKE_SOURCE_DIR}/3rdparty/qt/modeltest.h) qt4_add_resources(gammaray_srcs ${CMAKE_SOURCE_DIR}/resources/gammaray.qrc) add_definitions(-DMAKE_GAMMARAY_CORE_LIB) # core lib add_library(gammaray_core SHARED ${gammaray_srcs} ) target_link_libraries(gammaray_core LINK_PUBLIC gammaray_common LINK_PRIVATE gammaray_common_internal ) set_target_properties(gammaray_core PROPERTIES ${GAMMARAY_DEFAULT_LIBRARY_PROPERTIES} OUTPUT_NAME gammaray_core-${GAMMARAY_PROBE_ABI} ) if(Qt5Core_FOUND) target_link_libraries(gammaray_core LINK_PUBLIC Qt5::Core LINK_PRIVATE Qt5::Gui) else() target_link_libraries(gammaray_core LINK_PUBLIC ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} # GUI is needed for QItemSelectionModel LINK_PRIVATE ${QT_QTNETWORK_LIBRARIES} ) endif() install(TARGETS gammaray_core EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) gammaray_install_headers( gammaray_core_export.h metaobject.h metaobjectrepository.h metaproperty.h objectmodelbase.h objecttypefilterproxymodel.h probeinterface.h propertycontroller.h propertycontrollerextension.h signalspycallbackset.h singlecolumnobjectproxymodel.h toolfactory.h util.h varianthandler.h ) ecm_generate_pri_file(BASE_NAME GammaRayCore LIB_NAME gammaray_core-${GAMMARAY_PROBE_ABI} DEPS "core gui GammaRayCommon" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/.. ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) gammaray-2.3.0/core/aggregatedpropertymodel.cpp000066400000000000000000000110031255003167400216640ustar00rootroot00000000000000/* aggregatedpropertymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "aggregatedpropertymodel.h" using namespace GammaRay; AggregatedPropertyModel::AggregatedPropertyModel(QObject* parent) : QAbstractTableModel(parent) { } AggregatedPropertyModel::~AggregatedPropertyModel() { } void AggregatedPropertyModel::addModel(QAbstractItemModel* model) { beginResetModel(); // FIXME: use insertRows instead m_models.append(model); connect(model, SIGNAL(modelReset()), this, SLOT(sourceModelReset())); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); // TODO: connect signals endResetModel(); } QVariant AggregatedPropertyModel::data(const QModelIndex& index, int role) const { const QModelIndex sourceIndex = mapToSource(index); if (!sourceIndex.isValid()) return QVariant(); return sourceIndex.data(role); } bool AggregatedPropertyModel::setData(const QModelIndex& index, const QVariant& value, int role) { const QModelIndex sourceIndex = mapToSource(index); if (!sourceIndex.isValid()) return false; return const_cast(sourceIndex.model())->setData(sourceIndex, value, role); } int AggregatedPropertyModel::columnCount(const QModelIndex& parent) const { if (parent.isValid() || m_models.isEmpty()) return 0; return m_models.first()->columnCount(); } int AggregatedPropertyModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; int count = 0; foreach (QAbstractItemModel* model, m_models) count += model->rowCount(); return count; } Qt::ItemFlags AggregatedPropertyModel::flags(const QModelIndex& index) const { const QModelIndex sourceIndex = mapToSource(index); if (!sourceIndex.isValid()) return QAbstractTableModel::flags(QModelIndex()); return sourceIndex.flags(); } QVariant AggregatedPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (m_models.isEmpty()) return QVariant(); return m_models.first()->headerData(section, orientation, role); } void AggregatedPropertyModel::sourceModelReset() { reset(); } void AggregatedPropertyModel::sourceDataChanged(const QModelIndex& sourceTopLeft, const QModelIndex& sourceBottomRight) { const QModelIndex topLeft = mapFromSource(sourceTopLeft); const QModelIndex bottomRight = mapFromSource(sourceBottomRight); if (topLeft.isValid() && bottomRight.isValid()) emit dataChanged(topLeft, bottomRight); } QModelIndex AggregatedPropertyModel::mapToSource(const QModelIndex& aggregatedIndex) const { if (!aggregatedIndex.isValid()) return QModelIndex(); int row = aggregatedIndex.row(); foreach (QAbstractItemModel *model, m_models) { if (row < model->rowCount()) { return model->index(row, aggregatedIndex.column()); } else { row -= model->rowCount(); } } return QModelIndex(); } QModelIndex AggregatedPropertyModel::mapFromSource(const QModelIndex& sourceIndex) const { int count = 0; foreach (QAbstractItemModel* model, m_models) { if (model == sourceIndex.model()) { return index(count + sourceIndex.row(), sourceIndex.column()); } else { count += model->rowCount(); } } return QModelIndex(); } QMap AggregatedPropertyModel::itemData(const QModelIndex& index) const { const QModelIndex sourceIndex = mapToSource(index); if (index.isValid()) return sourceIndex.model()->itemData(sourceIndex); return QMap(); } gammaray-2.3.0/core/aggregatedpropertymodel.h000066400000000000000000000050621255003167400213410ustar00rootroot00000000000000/* aggregatedpropertymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_AGGREGATEDPROPERTYMODEL_H #define GAMMARAY_AGGREGATEDPROPERTYMODEL_H #include #include namespace GammaRay { /** Model that aggregates static and dynamic QObject properties and properties * from our own meta-type system. */ class AggregatedPropertyModel : public QAbstractTableModel { Q_OBJECT public: explicit AggregatedPropertyModel(QObject *parent = 0); ~AggregatedPropertyModel(); void addModel(QAbstractItemModel* model); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; private: QModelIndex mapToSource(const QModelIndex &aggregatedIndex) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; private slots: void sourceModelReset(); void sourceDataChanged(const QModelIndex &sourceTopLeft, const QModelIndex &sourceBottomRight); private: QVector m_models; }; } #endif // GAMMARAY_AGGREGATEDPROPERTYMODEL_H gammaray-2.3.0/core/connectionfilterproxymodel.cpp000066400000000000000000000064711255003167400224510ustar00rootroot00000000000000/* connectionfilterproxymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionfilterproxymodel.h" #include "connectionmodel.h" using namespace GammaRay; ConnectionFilterProxyModel::ConnectionFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_receiver(0), m_sender(0), m_filterOnReceiver(false), m_filterOnSender(false) { setDynamicSortFilter(true); } void ConnectionFilterProxyModel::setFilterOnReceiver(bool filter) { m_filterOnReceiver = filter; invalidateFilter(); } void ConnectionFilterProxyModel::filterReceiver(QObject *receiver) { m_receiver = receiver; invalidateFilter(); } void ConnectionFilterProxyModel::setFilterOnSender(bool filter) { m_filterOnSender = filter; invalidateFilter(); } void ConnectionFilterProxyModel::filterSender(QObject *sender) { m_sender = sender; invalidateFilter(); } bool ConnectionFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent); if (m_filterOnSender && (!m_sender || sourceIndex.data(ConnectionModel::SenderRole).value() != m_sender)) { return false; } if (m_filterOnReceiver && (!m_receiver || sourceIndex.data(ConnectionModel::ReceiverRole).value() != m_receiver)) { return false; } return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } bool ConnectionFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const { if (m_filterOnSender && source_column == 0) { return false; } if (m_filterOnReceiver && source_column == 2) { return false; } return QSortFilterProxyModel::filterAcceptsColumn(source_column, source_parent); } bool ConnectionFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const bool leftValid = left.data(ConnectionModel::ConnectionValidRole).toBool(); const bool rightValid = right.data(ConnectionModel::ConnectionValidRole).toBool(); if (leftValid == rightValid) { return QSortFilterProxyModel::lessThan(left, right); } else { return rightValid; } } gammaray-2.3.0/core/connectionfilterproxymodel.h000066400000000000000000000040651255003167400221130ustar00rootroot00000000000000/* connectionfilterproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONFILTERPROXYMODEL_H #define GAMMARAY_CONNECTIONFILTERPROXYMODEL_H #include namespace GammaRay { class ConnectionFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ConnectionFilterProxyModel(QObject *parent = 0); void setFilterOnReceiver(bool filter); void filterReceiver(QObject *receiver); void setFilterOnSender(bool filter); void filterSender(QObject *sender); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; private: QObject *m_receiver; QObject *m_sender; bool m_filterOnReceiver; bool m_filterOnSender; }; } #endif // GAMMARAY_CONNECTIONFILTERPROXYMODEL_H gammaray-2.3.0/core/connectionmodel.cpp000066400000000000000000000230331255003167400201320ustar00rootroot00000000000000/* connectionmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionmodel.h" #include "probe.h" #include #include "util.h" #include #include #include #include #include #include using namespace GammaRay; static bool checkMethodForObject(QObject *obj, const QByteArray &signature, bool isSender) { if (!obj || signature.isEmpty()) { return false; } const QMetaObject *mo = obj->metaObject(); const int methodIndex = mo->indexOfMethod(signature.constData() + 1); if (methodIndex < 0) { return false; } const QMetaMethod method = mo->method(methodIndex); if (method.methodType() != QMetaMethod::Signal && (isSender || method.methodType() != QMetaMethod::Slot)) { return false; } const int methodCode = signature.at(0) - '0'; if ((methodCode == QSLOT_CODE && method.methodType() != QMetaMethod::Slot) || (methodCode == QSIGNAL_CODE && method.methodType() != QMetaMethod::Signal)) { return false; } return true; } static QByteArray normalize(QObject *obj, const char *signature) { int idx = obj->metaObject()->indexOfMethod(signature + 1); if (idx == -1) { return QMetaObject::normalizedSignature(signature); } else { // oh how I'd like to use ::fromRawData here reliably ;-) return QByteArray(signature); } } ConnectionModel::ConnectionModel(QObject *parent) : QAbstractTableModel(parent) { qRegisterMetaType("const char*"); qRegisterMetaType("Qt::ConnectionType"); qRegisterMetaType(); } void ConnectionModel::connectionAdded(QObject *sender, const char *signal, QObject *receiver, const char *method, Qt::ConnectionType type) { if (sender == this || receiver == this || !sender || !receiver) { return; } Connection c; c.sender = sender; c.signal = normalize(sender, signal); c.receiver = receiver; c.method = normalize(receiver, method); c.type = type; c.location = SignalSlotsLocationStore::extractLocation(signal); // check if that's actually a valid connection if (checkMethodForObject(sender, c.signal, true) && checkMethodForObject(receiver, c.method, false)) { c.valid = QMetaObject::checkConnectArgs(c.signal, c.method); } else { c.valid = false; } //TODO: we could check more stuff here eg. if queued connection is possible etc. //and use verktygs heuristics to detect likely misconnects // when called from background, delay into foreground, otherwise call directly static const QMetaMethod m = metaObject()->method(metaObject()->indexOfMethod("connectionAddedMainThread(Connection)")); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_ASSERT(m.isValid()); #endif m.invoke(this, Qt::AutoConnection, Q_ARG(GammaRay::Connection, c)); } void ConnectionModel::connectionAddedMainThread(const Connection& connection) { Q_ASSERT(thread() == QThread::currentThread()); { QMutexLocker objectLock(Probe::objectLock()); if (!Probe::instance()->isValidObject(connection.sender) || !Probe::instance()->isValidObject(connection.receiver)) { return; } } beginInsertRows(QModelIndex(), m_connections.size(), m_connections.size()); m_connections.push_back(connection); endInsertRows(); } void ConnectionModel::connectionRemoved(QObject *sender, const char *signal, QObject *receiver, const char *method) { if (sender == this || receiver == this) { return; } QByteArray normalizedSignal, normalizedMethod; if (signal) { normalizedSignal = QMetaObject::normalizedSignature(signal); } if (method) { normalizedMethod = QMetaObject::normalizedSignature(method); } // when called from background, delay into foreground, otherwise call directly static const QMetaMethod m = metaObject()->method(metaObject()->indexOfMethod("connectionRemovedMainThread(QObject*,QByteArray,QObject*,QByteArray)")); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_ASSERT(m.isValid()); #endif m.invoke(this, Qt::AutoConnection, Q_ARG(QObject*, sender), Q_ARG(QByteArray, normalizedSignal), Q_ARG(QObject*, receiver), Q_ARG(QByteArray, normalizedMethod)); } void ConnectionModel::connectionRemovedMainThread(QObject *sender, const QByteArray &normalizedSignal, QObject *receiver, const QByteArray &normalizedMethod) { Q_ASSERT(thread() == QThread::currentThread()); for (int i = 0; i < m_connections.size();) { bool remove = false; const Connection &con = m_connections.at(i); if (!con.receiver || !con.sender) { // might be invalidated from a background thread remove = true; } else if ((sender == 0 || con.sender == sender) && (receiver == 0 || con.receiver == receiver) && (normalizedSignal.isEmpty() || con.signal == normalizedSignal) && (normalizedMethod.isEmpty() || con.method == normalizedMethod)) { // the connection was actually removed remove = true; } if (remove) { // note: QVector in Qt4 does not move objects when erasing, even though Connection is marked as movable. // To workaround this issue, we swap with the last entry and pop from the back which is cheap. if (i < m_connections.size() - 1) { qSwap(m_connections[i], m_connections.last()); emit dataChanged(index(i, 0), index(i, columnCount())); } beginRemoveRows(QModelIndex(), m_connections.size() - 1, m_connections. size() - 1); m_connections.pop_back(); endRemoveRows(); } else { ++i; } } } QVariant ConnectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() < 0 || index.row() >= m_connections.size()) { return QVariant(); } Connection con = m_connections.at(index.row()); QMutexLocker probeLock(Probe::objectLock()); if (!Probe::instance()->isValidObject(con.sender)) { con.sender = 0; } if (!Probe::instance()->isValidObject(con.receiver)) { con.receiver = 0; } if (role == Qt::DisplayRole) { if (index.column() == 0) { if (con.sender) { return Util::displayString(con.sender); } else { return QLatin1String(""); } } if (index.column() == 1) { return con.signal.mid(1); } if (index.column() == 2) { if (con.receiver) { return Util::displayString(con.receiver); } else { return QLatin1String(""); } } if (index.column() == 3) { return con.method.mid(1); } if (index.column() == 4) { switch (con.type) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) case Qt::AutoCompatConnection: return QLatin1String("AutoCompatConnection"); #endif case Qt::AutoConnection: return QLatin1String("AutoConnection"); case Qt::BlockingQueuedConnection: return QLatin1String("BlockingQueuedConnection"); case Qt::DirectConnection: return QLatin1String("DirectConnection"); case Qt::QueuedConnection: return QLatin1String("QueuedConnection"); case Qt::UniqueConnection: return QLatin1String("UniqueConnection"); default: return tr("Unknown connection type: %1").arg(con.type); } } if (index.column() == 5) { return con.location; } } else if (role == SenderRole) { return QVariant::fromValue(con.sender); } else if (role == ReceiverRole) { return QVariant::fromValue(con.receiver); } else if (role == Qt::ForegroundRole) { if (!con.valid) { return QVariant::fromValue(Qt::red); } } else if (role == ConnectionValidRole) { return con.valid; } return QVariant(); } QVariant ConnectionModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Sender"); case 1: return tr("Signal"); case 2: return tr("Receiver"); case 3: return tr("Method"); case 4: return tr("Connection Type"); case 5: return tr("Location"); } } return QAbstractItemModel::headerData(section, orientation, role); } int ConnectionModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 6; } int ConnectionModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_connections.size(); } gammaray-2.3.0/core/connectionmodel.h000066400000000000000000000060531255003167400176020ustar00rootroot00000000000000/* connectionmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONMODEL_H #define GAMMARAY_CONNECTIONMODEL_H #include #include #include #include "gammaray_core_export.h" #include namespace GammaRay { struct Connection { Connection() : sender(0), receiver(0), type(Qt::AutoConnection), valid(false) { } QObject *sender; QByteArray signal; QObject *receiver; QByteArray method; QByteArray location; Qt::ConnectionType type; bool valid; }; } Q_DECLARE_TYPEINFO(GammaRay::Connection, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(GammaRay::Connection) namespace GammaRay { class GAMMARAY_CORE_EXPORT ConnectionModel : public QAbstractTableModel { Q_OBJECT public: enum Role { SenderRole = UserRole + 1, ReceiverRole, ConnectionValidRole }; explicit ConnectionModel(QObject *parent = 0); /// can be called from arbitrary threads void connectionAdded(QObject *sender, const char *signal, QObject *receiver, const char *method, Qt::ConnectionType type); void connectionRemoved(QObject *sender, const char *signal, QObject *receiver, const char *method); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; private slots: void connectionAddedMainThread(const GammaRay::Connection &connection); void connectionRemovedMainThread(QObject *sender, const QByteArray &normalizedSignal, QObject *receiver, const QByteArray &normalizedMethod); private: QVector m_connections; }; } #endif // GAMMARAY_CONNECTIONMODEL_H gammaray-2.3.0/core/gammaray_core_export.h000066400000000000000000000027601255003167400206320ustar00rootroot00000000000000/* gammaray_core_export.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CORE_EXPORT_H #define GAMMARAY_CORE_EXPORT_H #include #ifdef GAMMARAY_CORE_STATICLIB # undef GAMMARAY_CORE_SHAREDLIB # define GAMMARAY_CORE_EXPORT #else # ifdef MAKE_GAMMARAY_CORE_LIB # define GAMMARAY_CORE_EXPORT Q_DECL_EXPORT # else # define GAMMARAY_CORE_EXPORT Q_DECL_IMPORT # endif #endif #endif /* GAMMARAY_CORE_EXPORT_H */ gammaray-2.3.0/core/metaobject.cpp000066400000000000000000000056561255003167400171020ustar00rootroot00000000000000/* metaobject.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaobject.h" using namespace GammaRay; MetaObject::MetaObject() { } MetaObject::~MetaObject() { qDeleteAll(m_properties); } int MetaObject::propertyCount() const { int count = 0; foreach (MetaObject *mo, m_baseClasses) { count += mo->propertyCount(); } return count + m_properties.size(); } MetaProperty *MetaObject::propertyAt(int index) const { foreach (MetaObject *mo, m_baseClasses) { if (index >= mo->propertyCount()) { index -= mo->propertyCount(); } else { return mo->propertyAt(index); } } Q_ASSERT(index >= 0 && index < m_properties.size()); return m_properties.at(index); } void MetaObject::addBaseClass(MetaObject *baseClass) { Q_ASSERT(baseClass); m_baseClasses.push_back(baseClass); } void MetaObject::addProperty(MetaProperty *property) { Q_ASSERT(property); // TODO: sort property->setMetaObject(this); m_properties.push_back(property); } QString MetaObject::className() const { return m_className; } void MetaObject::setClassName(const QString &className) { m_className = className; } void *MetaObject::castForPropertyAt(void *object, int index) const { for (int i = 0; i < m_baseClasses.size(); ++i) { const MetaObject *base = m_baseClasses.at(i); if (index >= base->propertyCount()) { index -= base->propertyCount(); } else { return base->castForPropertyAt(castToBaseClass(object, i), index); } } return object; // our own property } MetaObject* MetaObject::superClass(int index) const { if (m_baseClasses.size() <= index) return 0; return m_baseClasses[index]; } bool MetaObject::inherits(const QString& className) const { if (className == m_className) return true; foreach (MetaObject *metaObject, m_baseClasses) { if (metaObject->inherits(className)) return true; } return false; } gammaray-2.3.0/core/metaobject.h000066400000000000000000000066521255003167400165440ustar00rootroot00000000000000/* metaobject.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAOBJECT_H #define GAMMARAY_METAOBJECT_H #include "gammaray_core_export.h" #include "metaproperty.h" #include namespace GammaRay { /** @brief Compile-time introspection adaptor for non-QObject classes. */ class GAMMARAY_CORE_EXPORT MetaObject { public: MetaObject(); virtual ~MetaObject(); /** * Returns the amount of properties available in this class (including base classes). */ int propertyCount() const; /** * Returns the property adaptor for index @p index. */ MetaProperty *propertyAt(int index) const; /** Add a base class meta object. */ void addBaseClass(MetaObject *baseClass); /** Add a property for this class. This transfers ownership. */ void addProperty(MetaProperty *property); /// Returns the name of the class represented by this object. QString className() const; /** Casts a void pointer for an instance of this type to one appropriate * for use with the property at index @p index. * Make sure to use this when dealing with multi-inheritance. */ void *castForPropertyAt(void *object, int index) const; void setClassName(const QString &className); MetaObject *superClass(int index = 0) const; bool inherits(const QString &className) const; protected: /** Casts down to base class @p baseClassIndex. * This is important when traversing multi-inheritance trees. */ virtual void *castToBaseClass(void *object, int baseClassIndex) const = 0; protected: QVector m_baseClasses; private: QVector m_properties; QString m_className; }; /** @brief Template implementation of MetaObject. */ template class MetaObjectImpl : public MetaObject { public: void *castToBaseClass(void *object, int baseClassIndex) const { Q_ASSERT(baseClassIndex >= 0 && baseClassIndex < m_baseClasses.size()); switch (baseClassIndex) { case 0: return static_cast(static_cast(object)); case 1: return static_cast(static_cast(object)); case 2: return static_cast(static_cast(object)); } Q_ASSERT(!"WTF!?"); return 0; } }; } #endif // GAMMARAY_METAOBJECT_H gammaray-2.3.0/core/metaobjectmodel.h000066400000000000000000000103721255003167400175570ustar00rootroot00000000000000/* metaobjectmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAOBJECTMODEL_H #define GAMMARAY_METAOBJECTMODEL_H #include #include namespace GammaRay { template class MetaObjectModel : public QAbstractItemModel { public: explicit MetaObjectModel(QObject *parent = 0) : QAbstractItemModel(parent), m_metaObject(0) { } virtual void setMetaObject(const QMetaObject *metaObject) { const auto oldRowCount = rowCount(); if (oldRowCount) { beginRemoveRows(QModelIndex(), 0, oldRowCount - 1); m_metaObject = 0; endRemoveRows(); } else { m_metaObject = 0; } if (!metaObject) return; const auto newRowCount = (metaObject->*MetaCount)(); if (newRowCount) { beginInsertRows(QModelIndex(), 0, newRowCount - 1); m_metaObject = metaObject; endInsertRows(); } else { m_metaObject = metaObject; } } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { if (!index.isValid() || !m_metaObject || index.row() < 0 || index.row() >= rowCount(index.parent())) { return QVariant(); } const MetaThing metaThing = (m_metaObject->*MetaAccessor)(index.row()); if (index.column() == columnCount(index) - 1 && role == Qt::DisplayRole) { const QMetaObject *mo = m_metaObject; while ((mo->*MetaOffset)() > index.row()) { mo = mo->superClass(); } return mo->className(); } return metaData(index, metaThing, role); } QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == columnCount() - 1) { return tr("Class"); } return columnHeader(section); } return QAbstractItemModel::headerData(section, orientation, role); } int rowCount(const QModelIndex &parent = QModelIndex()) const { if (!m_metaObject || parent.isValid()) { return 0; } return (m_metaObject->*MetaCount)(); } QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const { if (row >= 0 && row < rowCount(parent) && column >= 0 && column < columnCount(parent) && !parent.isValid()) { return createIndex(row, column, -1); } return QModelIndex(); } QModelIndex parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); } protected: virtual QVariant metaData(const QModelIndex &index, const MetaThing &metaThing, int role) const = 0; virtual QString columnHeader(int index) const = 0; typedef MetaObjectModel super; protected: // let's assume that meta objects never get destroyed const QMetaObject *m_metaObject; }; } #endif // GAMMARAY_METAOBJECTMODEL_H gammaray-2.3.0/core/metaobjectrepository.cpp000066400000000000000000000327441255003167400212400ustar00rootroot00000000000000/* metaobjectrepository.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaobjectrepository.h" #include "metaobject.h" #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #include #include #include #include #include #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) #include #endif using namespace GammaRay; namespace GammaRay { class StaticMetaObjectRepository : public MetaObjectRepository { public: StaticMetaObjectRepository() : MetaObjectRepository() { } }; } Q_GLOBAL_STATIC(StaticMetaObjectRepository, s_instance) MetaObjectRepository::MetaObjectRepository() : m_initialized(false) { } MetaObjectRepository::~MetaObjectRepository() { qDeleteAll(m_metaObjects); } void MetaObjectRepository::initBuiltInTypes() { m_initialized = true; initQObjectTypes(); initIOTypes(); initNetworkTypes(); initGuiTypes(); initOpenGLTypes(); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_DECLARE_METATYPE(QThread*) #endif Q_DECLARE_METATYPE(QThread::Priority) void MetaObjectRepository::initQObjectTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT0(QObject); MO_ADD_PROPERTY_RO(QObject, QObject*, parent); MO_ADD_PROPERTY_RO(QObject, bool, signalsBlocked); // TODO setter has non-void return type MO_ADD_PROPERTY_RO(QObject, QThread*, thread); MO_ADD_METAOBJECT1(QThread, QObject) MO_ADD_PROPERTY_RO(QThread, bool, isFinished); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) MO_ADD_PROPERTY_RO(QThread, bool, isInterruptionRequested); #endif MO_ADD_PROPERTY_RO(QThread, bool, isRunning); MO_ADD_PROPERTY (QThread, QThread::Priority, priority, setPriority); MO_ADD_PROPERTY (QThread, uint, stackSize, setStackSize); MO_ADD_METAOBJECT0(QPaintDevice); MO_ADD_PROPERTY_RO(QPaintDevice, int, colorCount); MO_ADD_PROPERTY_RO(QPaintDevice, int, heightMM); MO_ADD_PROPERTY_RO(QPaintDevice, int, logicalDpiX); MO_ADD_PROPERTY_RO(QPaintDevice, int, logicalDpiY); MO_ADD_PROPERTY_RO(QPaintDevice, bool, paintingActive); MO_ADD_PROPERTY_RO(QPaintDevice, int, physicalDpiX); MO_ADD_PROPERTY_RO(QPaintDevice, int, physicalDpiY); MO_ADD_PROPERTY_RO(QPaintDevice, int, widthMM); MO_ADD_METAOBJECT1(QCoreApplication, QObject); MO_ADD_PROPERTY_ST(QCoreApplication, QString, applicationDirPath); MO_ADD_PROPERTY_ST(QCoreApplication, QString, applicationFilePath); MO_ADD_PROPERTY_ST(QCoreApplication, qint64, applicationPid); MO_ADD_PROPERTY_ST(QCoreApplication, QStringList, arguments); MO_ADD_PROPERTY_ST(QCoreApplication, bool, closingDown); MO_ADD_PROPERTY_ST(QCoreApplication, bool, hasPendingEvents); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_PROPERTY_ST(QCoreApplication, bool, isQuitLockEnabled); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) MO_ADD_PROPERTY_ST(QCoreApplication, bool, isSetuidAllowed); #endif MO_ADD_PROPERTY_ST(QCoreApplication, QStringList, libraryPaths); MO_ADD_PROPERTY_ST(QCoreApplication, bool, startingUp); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_METAOBJECT1(QGuiApplication, QCoreApplication); MO_ADD_PROPERTY_ST(QGuiApplication, Qt::ApplicationState, applicationState); MO_ADD_PROPERTY_ST(QGuiApplication, bool, desktopSettingsAware); MO_ADD_PROPERTY_RO(QGuiApplication, qreal, devicePixelRatio); MO_ADD_PROPERTY_ST(QGuiApplication, QObject*, focusObject); MO_ADD_PROPERTY_ST(QGuiApplication, QWindow*, focusWindow); MO_ADD_PROPERTY_ST(QGuiApplication, QFont, font); MO_ADD_PROPERTY_ST(QGuiApplication, bool, isLeftToRight); MO_ADD_PROPERTY_ST(QGuiApplication, bool, isRightToLeft); MO_ADD_PROPERTY_RO(QGuiApplication, bool, isSavingSession); MO_ADD_PROPERTY_RO(QGuiApplication, bool, isSessionRestored); MO_ADD_PROPERTY_ST(QGuiApplication, QPalette, palette); MO_ADD_PROPERTY_ST(QGuiApplication, QScreen*, primaryScreen); MO_ADD_PROPERTY_RO(QGuiApplication, QString, sessionId); MO_ADD_PROPERTY_RO(QGuiApplication, QString, sessionKey); #endif } Q_DECLARE_METATYPE(QAbstractSocket::SocketType) Q_DECLARE_METATYPE(QHostAddress) Q_DECLARE_METATYPE(QIODevice::OpenMode) Q_DECLARE_METATYPE(QSocketNotifier::Type) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_DECLARE_METATYPE(QAbstractSocket::PauseModes) Q_DECLARE_METATYPE(QFileDevice::FileError) Q_DECLARE_METATYPE(QFileDevice::Permissions) #else // !Qt5 Q_DECLARE_METATYPE(QAbstractSocket::SocketError) Q_DECLARE_METATYPE(QAbstractSocket::SocketState) #ifndef QT_NO_NETWORKPROXY Q_DECLARE_METATYPE(QNetworkProxy) #endif #endif void MetaObjectRepository::initIOTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT1(QIODevice, QObject); MO_ADD_PROPERTY_RO(QIODevice, QIODevice::OpenMode, openMode); MO_ADD_PROPERTY (QIODevice, bool, isTextModeEnabled, setTextModeEnabled); MO_ADD_PROPERTY_RO(QIODevice, bool, isOpen); MO_ADD_PROPERTY_RO(QIODevice, bool, isReadable); MO_ADD_PROPERTY_RO(QIODevice, bool, isWritable); MO_ADD_PROPERTY_RO(QIODevice, bool, isSequential); MO_ADD_PROPERTY_RO(QIODevice, qint64, pos); MO_ADD_PROPERTY_RO(QIODevice, qint64, size); MO_ADD_PROPERTY_RO(QIODevice, bool, atEnd); MO_ADD_PROPERTY_RO(QIODevice, qint64, bytesAvailable); MO_ADD_PROPERTY_RO(QIODevice, qint64, bytesToWrite); MO_ADD_PROPERTY_RO(QIODevice, bool, canReadLine); MO_ADD_PROPERTY_RO(QIODevice, QString, errorString); // FIXME: QIODevice::readAll() would be nice to have #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_METAOBJECT1(QFileDevice, QIODevice); MO_ADD_PROPERTY_RO(QFileDevice, QFileDevice::FileError, error); MO_ADD_PROPERTY_RO(QFileDevice, QString, fileName); MO_ADD_PROPERTY_RO(QFileDevice, int, handle); MO_ADD_PROPERTY_RO(QFileDevice, QFileDevice::Permissions, permissions); MO_ADD_METAOBJECT1(QFile, QFileDevice); MO_ADD_PROPERTY_RO(QFile, bool, exists); MO_ADD_PROPERTY_RO(QFile, QString, symLinkTarget); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) MO_ADD_METAOBJECT1(QSaveFile, QFileDevice); #endif #endif } void MetaObjectRepository::initNetworkTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT1(QAbstractSocket, QIODevice); MO_ADD_PROPERTY_RO(QAbstractSocket, bool, isValid); MO_ADD_PROPERTY_RO(QAbstractSocket, quint16, localPort); MO_ADD_PROPERTY_RO(QAbstractSocket, QHostAddress, localAddress); MO_ADD_PROPERTY_RO(QAbstractSocket, quint16, peerPort); MO_ADD_PROPERTY_RO(QAbstractSocket, QHostAddress, peerAddress); MO_ADD_PROPERTY_RO(QAbstractSocket, QString, peerName); MO_ADD_PROPERTY (QAbstractSocket, qint64, readBufferSize, setReadBufferSize); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_PROPERTY (QAbstractSocket, QAbstractSocket::PauseModes, pauseMode, setPauseMode); MO_ADD_PROPERTY_RO(QAbstractSocket, qintptr, socketDescriptor); #else // !Qt5 MO_ADD_PROPERTY_RO(QAbstractSocket, int, socketDescriptor); #endif MO_ADD_PROPERTY_RO(QAbstractSocket, QAbstractSocket::SocketType, socketType); MO_ADD_PROPERTY_RO(QAbstractSocket, QAbstractSocket::SocketState, state); MO_ADD_PROPERTY_RO(QAbstractSocket, QAbstractSocket::SocketError, error); #ifndef QT_NO_NETWORKPROXY MO_ADD_PROPERTY_RO(QAbstractSocket, QNetworkProxy, proxy); #endif // FIXME: QAbstractSocket::setSocketOption() would be nice to have // FIXME: QQAbstractSocket::socketOption() would be nice to have MO_ADD_METAOBJECT1(QTcpServer, QObject); MO_ADD_PROPERTY_RO(QTcpServer, bool, isListening); MO_ADD_PROPERTY (QTcpServer, int, maxPendingConnections, setMaxPendingConnections); MO_ADD_PROPERTY_RO(QTcpServer, quint16, serverPort); MO_ADD_PROPERTY_RO(QTcpServer, QHostAddress, serverAddress); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_PROPERTY_RO(QTcpServer, qintptr, socketDescriptor); #else // !QT5 MO_ADD_PROPERTY_RO(QTcpServer, int, socketDescriptor); #endif MO_ADD_PROPERTY_RO(QTcpServer, bool, hasPendingConnections); MO_ADD_PROPERTY_RO(QTcpServer, QAbstractSocket::SocketError, serverError); MO_ADD_PROPERTY_RO(QTcpServer, QString, errorString); #ifndef QT_NO_NETWORKPROXY MO_ADD_PROPERTY_RO(QTcpServer, QNetworkProxy, proxy); #endif MO_ADD_METAOBJECT1(QSocketNotifier, QObject); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_PROPERTY_RO(QSocketNotifier, qintptr, socket); #else // !Qt5 MO_ADD_PROPERTY_RO(QSocketNotifier, int, socket); #endif MO_ADD_PROPERTY_RO(QSocketNotifier, QSocketNotifier::Type, type); MO_ADD_PROPERTY (QSocketNotifier, bool, isEnabled, setEnabled); } void MetaObjectRepository::initGuiTypes() { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MetaObject *mo = 0; MO_ADD_METAOBJECT0(QSurface); MO_ADD_PROPERTY_RO(QSurface, QSurfaceFormat, format); MO_ADD_PROPERTY_RO(QSurface, QSize, size); MO_ADD_PROPERTY_RO(QSurface, QSurface::SurfaceClass, surfaceClass); MO_ADD_PROPERTY_RO(QSurface, QSurface::SurfaceType, surfaceType); MO_ADD_METAOBJECT2(QWindow, QObject, QSurface); MO_ADD_PROPERTY_CR(QWindow, QSize, baseSize, setBaseSize); #ifndef QT_NO_CURSOR MO_ADD_PROPERTY_CR(QWindow, QCursor, cursor, setCursor); #endif MO_ADD_PROPERTY_RO(QWindow, qreal, devicePixelRatio); MO_ADD_PROPERTY_CR(QWindow, QString, filePath, setFilePath); MO_ADD_PROPERTY_RO(QWindow, QObject*, focusObject); MO_ADD_PROPERTY_RO(QWindow, QRect, frameGeometry); MO_ADD_PROPERTY_RO(QWindow, QMargins, frameMargins); MO_ADD_PROPERTY_CR(QWindow, QPoint, framePosition, setFramePosition); MO_ADD_PROPERTY_CR(QWindow, QRect, geometry, setGeometry); MO_ADD_PROPERTY_CR(QWindow, QIcon, icon, setIcon); MO_ADD_PROPERTY_RO(QWindow, bool, isExposed); MO_ADD_PROPERTY_RO(QWindow, bool, isTopLevel); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) MO_ADD_PROPERTY_CR(QWindow, QRegion, mask, setMask); #endif MO_ADD_PROPERTY_CR(QWindow, QPoint, position, setPosition); MO_ADD_PROPERTY_RO(QWindow, QSurfaceFormat, requestedFormat); MO_ADD_PROPERTY_RO(QWindow, QScreen*, screen); MO_ADD_PROPERTY_CR(QWindow, QSize, sizeIncrement, setSizeIncrement); MO_ADD_PROPERTY (QWindow, Qt::WindowState, windowState, setWindowState); MO_ADD_PROPERTY_RO(QWindow, QWindow*, transientParent); MO_ADD_PROPERTY_RO(QWindow, Qt::WindowType, type); #endif } void MetaObjectRepository::initOpenGLTypes() { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MetaObject *mo = 0; MO_ADD_METAOBJECT1(QOpenGLShader, QObject); MO_ADD_PROPERTY_RO(QOpenGLShader, bool, isCompiled); MO_ADD_PROPERTY_RO(QOpenGLShader, QString, log); MO_ADD_PROPERTY_RO(QOpenGLShader, uint, shaderId); MO_ADD_PROPERTY_RO(QOpenGLShader, QOpenGLShader::ShaderType, shaderType); MO_ADD_PROPERTY_RO(QOpenGLShader, QByteArray, sourceCode); MO_ADD_METAOBJECT1(QOpenGLShaderProgram, QObject); MO_ADD_PROPERTY_RO(QOpenGLShaderProgram, bool, isLinked); MO_ADD_PROPERTY_RO(QOpenGLShaderProgram, QString, log); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) // FIXME calling this asserts in debug builds of some newer Qt versions // MO_ADD_PROPERTY_RO(QOpenGLShaderProgram, int, maxGeometryOutputVertices); MO_ADD_PROPERTY (QOpenGLShaderProgram, int, patchVertexCount, setPatchVertexCount); #endif MO_ADD_PROPERTY_RO(QOpenGLShaderProgram, uint, programId); MO_ADD_METAOBJECT1(QOpenGLContext, QObject); MO_ADD_PROPERTY_RO(QOpenGLContext, uint, defaultFramebufferObject); // crashes if context isn't current // MO_ADD_PROPERTY_RO(QOpenGLContext, QSet, extensions); MO_ADD_PROPERTY_RO(QOpenGLContext, QSurfaceFormat, format); MO_ADD_PROPERTY_RO(QOpenGLContext, bool, isValid); MO_ADD_PROPERTY_RO(QOpenGLContext, QScreen*, screen); MO_ADD_PROPERTY_RO(QOpenGLContext, QOpenGLContext*, shareContext); MO_ADD_PROPERTY_RO(QOpenGLContext, QOpenGLContextGroup*, shareGroup); // MO_ADD_PROPERTY_RO(QOpenGLContext, QSurface*, surface); #endif } MetaObjectRepository *MetaObjectRepository::instance() { if (!s_instance()->m_initialized) s_instance()->initBuiltInTypes(); return s_instance(); } void MetaObjectRepository::addMetaObject(MetaObject *mo) { Q_ASSERT(!mo->className().isEmpty()); m_metaObjects.insert(mo->className(), mo); } MetaObject *MetaObjectRepository::metaObject(const QString &typeName) const { QString typeName_ = typeName; typeName_.remove('*'); typeName_.remove('&'); typeName_.remove("const "); typeName_.remove(" const"); typeName_.remove(' '); return m_metaObjects.value(typeName_); } bool MetaObjectRepository::hasMetaObject(const QString &typeName) const { return m_metaObjects.contains(typeName); } gammaray-2.3.0/core/metaobjectrepository.h000066400000000000000000000114121255003167400206720ustar00rootroot00000000000000/* metaobjectrepository.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file metaobjectrepository.h * @brief MetaObject repository macros. */ #ifndef GAMMARAY_METAOBJECTREPOSITORY_H #define GAMMARAY_METAOBJECTREPOSITORY_H #include "gammaray_core_export.h" #include class QString; namespace GammaRay { class MetaObject; /** * @brief MetaObject repository. * * Repository of compile-time introspection information for stuff * not covered by the Qt meta object system. */ class GAMMARAY_CORE_EXPORT MetaObjectRepository { public: ~MetaObjectRepository(); /** Singleton accessor. */ static MetaObjectRepository *instance(); /** * Adds object type information to the repository. */ void addMetaObject(MetaObject *mo); /** * Returns the introspection information for the type with the given name. */ MetaObject *metaObject(const QString& typeName) const; /** * Returns whether a meta object is known for the given type name. */ bool hasMetaObject(const QString &typeName) const; protected: MetaObjectRepository(); private: void initBuiltInTypes(); void initQObjectTypes(); void initIOTypes(); void initNetworkTypes(); void initGuiTypes(); void initOpenGLTypes(); private: QHash m_metaObjects; bool m_initialized; }; } ///@cond internal #define MO_ADD_BASECLASS(Base) \ Q_ASSERT(GammaRay::MetaObjectRepository::instance()->hasMetaObject(QLatin1String(#Base))); \ mo->addBaseClass(GammaRay::MetaObjectRepository::instance()->metaObject(QLatin1String(#Base))); ///@endcond /** Register @p Class with the MetaObjectRepository. * Use this if @p Class has no base class. */ #define MO_ADD_METAOBJECT0(Class) \ mo = new GammaRay::MetaObjectImpl; \ mo->setClassName(QLatin1String(#Class)); \ GammaRay::MetaObjectRepository::instance()->addMetaObject(mo); /** Register @p Class with the MetaObjectRepository. * Use this if @p Class has one base class. */ #define MO_ADD_METAOBJECT1(Class, Base1) \ mo = new GammaRay::MetaObjectImpl; \ mo->setClassName(QLatin1String(#Class)); \ MO_ADD_BASECLASS(Base1) \ GammaRay::MetaObjectRepository::instance()->addMetaObject(mo); /** Register @p Class with the MetaObjectRepository. * Use this if @p Class has two base classes. */ #define MO_ADD_METAOBJECT2(Class, Base1, Base2) \ mo = new GammaRay::MetaObjectImpl; \ mo->setClassName(QLatin1String(#Class)); \ MO_ADD_BASECLASS(Base1) \ MO_ADD_BASECLASS(Base2) \ GammaRay::MetaObjectRepository::instance()->addMetaObject(mo); /** Register a read/write property for class @p Class. */ #define MO_ADD_PROPERTY(Class, Type, Getter, Setter) \ mo->addProperty(new GammaRay::MetaPropertyImpl( \ QLatin1String(#Getter), \ &Class::Getter, \ static_cast(&Class::Setter)) \ ); /** Register a read/write property for class @p Class with a type that is passed as const reference. */ #define MO_ADD_PROPERTY_CR(Class, Type, Getter, Setter) \ mo->addProperty(new GammaRay::MetaPropertyImpl( \ QLatin1String(#Getter), \ &Class::Getter, \ static_cast(&Class::Setter)) \ ); /** Register a read-only property for class @p Class. */ #define MO_ADD_PROPERTY_RO(Class, Type, Getter) \ mo->addProperty(new GammaRay::MetaPropertyImpl( \ QLatin1String(#Getter), \ &Class::Getter)); /** Register a static property for class @p Class. */ #define MO_ADD_PROPERTY_ST(Class, Type, Getter) \ mo->addProperty(new GammaRay::MetaStaticPropertyImpl( \ QLatin1String(#Getter), \ &Class::Getter)); #endif // GAMMARAY_METAOBJECTREPOSITORY_H gammaray-2.3.0/core/metaobjecttreemodel.cpp000066400000000000000000000165221255003167400207750ustar00rootroot00000000000000/* metaobjecttreemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaobjecttreemodel.h" #include "probe.h" #include #include using namespace GammaRay; #define IF_DEBUG(x) namespace GammaRay { /** * Open QObject for access to protected data members */ class UnprotectedQObject : public QObject { public: inline QObjectData* data() const { return d_ptr.data(); } }; } /** * Return true in case the object has a dynamic meta object * * If you look at the code generated by moc you'll see this: * @code * const QMetaObject *GammaRay::MessageModel::metaObject() const * { * return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; * } * @endcode * * QtQuick uses dynamic meta objects (subclasses of QAbstractDynamicMetaObject, defined in qobject_h.p) * for QML types. It's possible that these meta objects get destroyed * at runtime, so we need to protect against this. * * @note We cannot say if a specific QMetaObject* is dynamic or not * (QMetaObject is non-polymorphic, so we cannot dynamic_cast to QAbstractDynamicMetaObject*), * we can just judge by looking at QObjectData of QObject* * -- hence the QObject* parameter in hasDynamicMetaObject. * * @return Return true in case metaObject() does not point to staticMetaObject. */ static inline bool hasDynamicMetaObject(const QObject* object) { return reinterpret_cast(object)->data()->metaObject != 0; } MetaObjectTreeModel::MetaObjectTreeModel(QObject *parent) : QAbstractItemModel(parent) { scanMetaTypes(); } QVariant MetaObjectTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case ObjectColumn: return tr("Meta Object Class Hierarchy"); default: return QVariant(); } } return QAbstractItemModel::headerData(section, orientation, role); } QVariant MetaObjectTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const int column = index.column(); const QMetaObject *object = metaObjectForIndex(index); if (role == Qt::DisplayRole) { switch(column) { case ObjectColumn: return object->className(); default: break; } } else if (role == MetaObjectRole) { return QVariant::fromValue(object); } return QVariant(); } int MetaObjectTreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } int MetaObjectTreeModel::rowCount(const QModelIndex &parent) const { const QMetaObject *metaObject = metaObjectForIndex(parent); return m_parentChildMap.value(metaObject).size(); } QModelIndex MetaObjectTreeModel::parent(const QModelIndex &child) const { if (!child.isValid()) { return QModelIndex(); } const QMetaObject *object = metaObjectForIndex(child); Q_ASSERT(object); const QMetaObject *parentObject = object->superClass(); return indexForMetaObject(parentObject); } QModelIndex MetaObjectTreeModel::index(int row, int column, const QModelIndex &parent) const { const QMetaObject *parentObject = metaObjectForIndex(parent); const QVector children = m_parentChildMap.value(parentObject); if (row < 0 || column < 0 || row >= children.size() || column >= columnCount()) { return QModelIndex(); } const QMetaObject *object = children.at(row); return createIndex(row, column, const_cast(object)); } void MetaObjectTreeModel::objectAdded(QObject *obj) { // Probe::objectFullyConstructed calls us and ensures this already Q_ASSERT(thread() == QThread::currentThread()); Q_ASSERT(Probe::instance()->isValidObject(obj)); Q_ASSERT(!obj->parent() || Probe::instance()->isValidObject(obj->parent())); if (hasDynamicMetaObject(obj)) { // Encountered dynamic meta object, ignoring for now return; } const QMetaObject *metaObject = obj->metaObject(); addMetaObject(metaObject); } void MetaObjectTreeModel::scanMetaTypes() { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) for (int mtId = 0; mtId <= QMetaType::User || QMetaType::isRegistered(mtId); ++mtId) { if (!QMetaType::isRegistered(mtId)) continue; const auto *mt = QMetaType::metaObjectForType(mtId); if (mt) { addMetaObject(mt); } } #endif } void MetaObjectTreeModel::addMetaObject(const QMetaObject *metaObject) { if (isKnownMetaObject(metaObject)) { return; } const QMetaObject *parentMetaObject = metaObject->superClass(); if (parentMetaObject && !isKnownMetaObject(parentMetaObject)) { // add parent first addMetaObject(metaObject->superClass()); } const QModelIndex parentIndex = indexForMetaObject(parentMetaObject); // either we get a proper parent and hence valid index or there is no parent Q_ASSERT(parentIndex.isValid() || !parentMetaObject); QVector &children = m_parentChildMap[ parentMetaObject ]; beginInsertRows(parentIndex, children.size(), children.size()); children.push_back(metaObject); m_childParentMap.insert(metaObject, parentMetaObject); endInsertRows(); } void MetaObjectTreeModel::removeMetaObject(const QMetaObject *metaObject) { Q_UNUSED(metaObject); // TODO: Meta objects may be deleted, find a way to detect this } void MetaObjectTreeModel::objectRemoved(QObject *obj) { Q_UNUSED(obj); // TODO } bool MetaObjectTreeModel::isKnownMetaObject(const QMetaObject* metaObject) const { return m_childParentMap.contains(metaObject); } QModelIndex MetaObjectTreeModel::indexForMetaObject(const QMetaObject *metaObject) const { if (!metaObject) { return QModelIndex(); } const QMetaObject *parentObject = m_childParentMap.value(metaObject); const QModelIndex parentIndex = indexForMetaObject(parentObject); if (!parentIndex.isValid() && parentObject) { return QModelIndex(); } const int row = m_parentChildMap[parentObject].indexOf(metaObject); if (row < 0) { return QModelIndex(); } return index(row, 0, parentIndex); } const QMetaObject *MetaObjectTreeModel::metaObjectForIndex(const QModelIndex &index) const { if (!index.isValid()) { return 0; } void *internalPointer = index.internalPointer(); const QMetaObject* metaObject = reinterpret_cast(internalPointer); return metaObject; } gammaray-2.3.0/core/metaobjecttreemodel.h000066400000000000000000000056311255003167400204410ustar00rootroot00000000000000/* metaobjecttreemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAOBJECTTREEMODEL_H #define GAMMARAY_METAOBJECTTREEMODEL_H #include #include #include #include namespace GammaRay { class MetaObjectTreeModel : public QAbstractItemModel { Q_OBJECT public: enum Role { MetaObjectRole = UserRole + 1 }; enum Column { ObjectColumn }; explicit MetaObjectTreeModel(QObject *parent = 0); // reimplemented methods QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; // headers QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; // Probe callbacks void objectAdded(QObject *obj); void objectRemoved(QObject *obj); private: void scanMetaTypes(); void addMetaObject(const QMetaObject *metaObject); void removeMetaObject(const QMetaObject *metaObject); bool isKnownMetaObject(const QMetaObject *metaObject) const; QModelIndex indexForMetaObject(const QMetaObject *metaObject) const; const QMetaObject *metaObjectForIndex(const QModelIndex &index) const; mutable QReadWriteLock m_lock; // data QHash m_childParentMap; QHash > m_parentChildMap; }; } Q_DECLARE_METATYPE(const QMetaObject *) #endif // GAMMARAY_METAOBJECTTREEMODEL_H gammaray-2.3.0/core/metaproperty.cpp000066400000000000000000000033601255003167400175060ustar00rootroot00000000000000/* metaproperty.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaproperty.h" #include "metaobject.h" #include #include using namespace GammaRay; MetaProperty::MetaProperty(const QString& name) : m_class(0), m_name(name) { } MetaProperty::~MetaProperty() { } QString MetaProperty::name() const { return m_name; } void MetaProperty::setValue(void* object, const QVariant& value) { Q_UNUSED(object); Q_UNUSED(value); Q_ASSERT(isReadOnly()); // otherwise sub-class should have implement this... } MetaObject *MetaProperty::metaObject() const { Q_ASSERT(m_class); return m_class; } void MetaProperty::setMetaObject(MetaObject *om) { m_class = om; } gammaray-2.3.0/core/metaproperty.h000066400000000000000000000110331255003167400171470ustar00rootroot00000000000000/* metaproperty.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAPROPERTY_H #define GAMMARAY_METAPROPERTY_H #include "gammaray_core_export.h" #include #include namespace GammaRay { class MetaObject; /** @brief Introspectable adaptor to non-QObject properties. */ class GAMMARAY_CORE_EXPORT MetaProperty { public: explicit MetaProperty(const QString &name); virtual ~MetaProperty(); /// User-readable name of that property QString name() const; /// Current value of the property for object @p object. virtual QVariant value(void *object) const = 0; /// Returns @c true if this property is read-only. virtual bool isReadOnly() const = 0; /// Allows changing the property value, assuming it's not read-only, for the instance @p object. virtual void setValue(void *object, const QVariant &value); /// Returns the name of the data type of this property. virtual QString typeName() const = 0; /// Returns the class this property belongs to. MetaObject *metaObject() const; private: friend class MetaObject; void setMetaObject(MetaObject *om); MetaObject *m_class; QString m_name; }; ///@cond internal namespace detail { template struct strip_const_ref { typedef T type; }; template struct strip_const_ref { typedef T type; }; } ///@endcond /** @brief Template-ed implementation of MetaProperty for member properties. */ template class MetaPropertyImpl : public MetaProperty { private: typedef typename detail::strip_const_ref::type ValueType; public: inline MetaPropertyImpl( const QString &name, GetterReturnType (Class::*getter)() const, void (Class::*setter)(SetterArgType) = 0) : MetaProperty(name), m_getter(getter), m_setter(setter) { } inline bool isReadOnly() const { return m_setter == 0 ; } inline QVariant value(void *object) const { Q_ASSERT(object); Q_ASSERT(m_getter); const ValueType v = (static_cast(object)->*(m_getter))(); return QVariant::fromValue(v); } inline void setValue(void *object, const QVariant &value) { if (isReadOnly()) return; Q_ASSERT(object); Q_ASSERT(m_setter); (static_cast(object)->*(m_setter))(value.value()); } inline QString typeName() const { return QMetaType::typeName(qMetaTypeId()) ; } private: GetterReturnType (Class::*m_getter)() const; void (Class::*m_setter)(SetterArgType); }; /** @brief Template-ed implementation of MetaProperty for static properties. */ template class MetaStaticPropertyImpl : public MetaProperty { private: typedef typename detail::strip_const_ref::type ValueType; public: inline MetaStaticPropertyImpl(const QString &name, GetterReturnType (*getter)()) : MetaProperty(name), m_getter(getter) { } inline bool isReadOnly() const { return true; } inline QVariant value(void *object) const { Q_UNUSED(object); Q_ASSERT(m_getter); const ValueType v = m_getter(); return QVariant::fromValue(v); } inline QString typeName() const { return QMetaType::typeName(qMetaTypeId()) ; } private: GetterReturnType (*m_getter)(); }; } #endif gammaray-2.3.0/core/metapropertymodel.cpp000066400000000000000000000142731255003167400205340ustar00rootroot00000000000000/* metapropertymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metapropertymodel.h" #include "metaobjectrepository.h" #include "metaobject.h" #include "varianthandler.h" #include "toolmodel.h" #include "probe.h" #include "toolfactory.h" #include using namespace GammaRay; MetaPropertyModel::MetaPropertyModel(QObject *parent) : QAbstractTableModel(parent), m_metaObject(0), m_object(0) { } void MetaPropertyModel::setObject(void *object, const QString &typeName) { if (m_object == object) return; beginResetModel(); m_object = object; m_metaObject = MetaObjectRepository::instance()->metaObject(typeName); endResetModel(); } void MetaPropertyModel::setObject(QObject *object) { if (m_object == object) return; beginResetModel(); m_object = 0; m_metaObject = 0; if (object) { const QMetaObject *mo = object->metaObject(); while (mo && !m_metaObject) { m_metaObject = MetaObjectRepository::instance()->metaObject(mo->className()); mo = mo->superClass(); } if (m_metaObject) { m_object = object; } } endResetModel(); } int MetaPropertyModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } int MetaPropertyModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !m_metaObject) { return 0; } return m_metaObject->propertyCount(); } QVariant MetaPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Property"); case 1: return tr("Value"); case 2: return tr("Type"); case 3: return tr("Class"); } } return QAbstractItemModel::headerData(section, orientation, role); } QMap< int, QVariant > MetaPropertyModel::itemData(const QModelIndex& index) const { QMap d = QAbstractItemModel::itemData(index); d.insert(PropertyModel::ActionRole, data(index, PropertyModel::ActionRole)); d.insert(PropertyModel::AppropriateToolRole, data(index, PropertyModel::AppropriateToolRole)); return d; } QVariant MetaPropertyModel::data(const QModelIndex &index, int role) const { if (!m_metaObject || !index.isValid()) { return QVariant(); } MetaProperty *property = m_metaObject->propertyAt(index.row()); // TODO: cache values, to make this more robust against m_object becoming invalid if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return property->name(); case 2: return property->typeName(); case 3: return property->metaObject()->className(); } } if (index.column() == 1) { if (!m_object) { return QVariant(); } const QVariant value = property->value(m_metaObject->castForPropertyAt(m_object, index.row())); switch (role) { case Qt::DisplayRole: return VariantHandler::displayString(value); case Qt::DecorationRole: return VariantHandler::decoration(value); case Qt::EditRole: return VariantHandler::serializableVariant(value); } } if (role == PropertyModel::ActionRole) { const QVariant value = property->value(m_metaObject->castForPropertyAt(m_object, index.row())); return (MetaObjectRepository::instance()->metaObject(property->typeName()) && *reinterpret_cast(value.data())) || value.value() ? PropertyModel::NavigateTo : PropertyModel::NoAction; } else if (role == PropertyModel::ValueRole) { const QVariant value = property->value(m_metaObject->castForPropertyAt(m_object, index.row())); return value; } else if (role == PropertyModel::AppropriateToolRole) { ToolModel *toolModel = Probe::instance()->toolModel(); ToolFactory *factory; const QVariant value = property->value(m_metaObject->castForPropertyAt(m_object, index.row())); if (value.canConvert()) factory = toolModel->data(toolModel->toolForObject(value.value()), ToolModelRole::ToolFactory).value(); else factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast(value.data()), property->typeName()), ToolModelRole::ToolFactory).value(); if (factory) return factory->name(); return QVariant(); } return QVariant(); } bool MetaPropertyModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && index.column() == 1 && m_metaObject && m_object && role == Qt::EditRole) { MetaProperty *property = m_metaObject->propertyAt(index.row()); property->setValue(m_metaObject->castForPropertyAt(m_object, index.row()), value); emit dataChanged(index, index); return true; } return QAbstractItemModel::setData(index, value, role); } Qt::ItemFlags MetaPropertyModel::flags(const QModelIndex &index) const { const Qt::ItemFlags f = QAbstractItemModel::flags(index); if (!index.isValid() || index.column() != 1 || !m_metaObject || !m_object) { return f; } MetaProperty *property = m_metaObject->propertyAt(index.row()); if (property->isReadOnly()) { return f; } return f | Qt::ItemIsEditable; } gammaray-2.3.0/core/metapropertymodel.h000066400000000000000000000050201255003167400201670ustar00rootroot00000000000000/* metapropertymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAPROPERTYMODEL_H #define GAMMARAY_METAPROPERTYMODEL_H #include "gammaray_core_export.h" #include namespace GammaRay { class MetaObject; /** Model showing non-QObject object properties. * @todo needs better name, but ObjectPropertyModel is already in use... * @todo maybe it's a good to merge those to anyway? */ class GAMMARAY_CORE_EXPORT MetaPropertyModel : public QAbstractTableModel { Q_OBJECT public: explicit MetaPropertyModel(QObject *parent = 0); /** Sets the object that should be represented by this model. */ void setObject(void *object, const QString &typeName); void setObject(QObject *object); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap< int, QVariant > itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; private: MetaObject *m_metaObject; void *m_object; }; } #endif // GAMMARAY_METAPROPERTYMODEL_H gammaray-2.3.0/core/methodargumentmodel.cpp000066400000000000000000000077021255003167400210230ustar00rootroot00000000000000/* methodargumentmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodargumentmodel.h" using namespace GammaRay; MethodArgumentModel::MethodArgumentModel(QObject *parent) : QAbstractTableModel(parent) { } void MethodArgumentModel::setMethod(const QMetaMethod &method) { m_method = method; m_arguments.clear(); m_arguments.resize(method.parameterTypes().size()); for (int i = 0; i < m_arguments.size(); ++i) { const QByteArray typeName = method.parameterTypes().at(i); const QVariant::Type variantType = QVariant::nameToType(typeName); m_arguments[i] = QVariant(variantType); } reset(); } QVariant MethodArgumentModel::data(const QModelIndex &index, int role) const { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) if(!m_method.signature() || #else if(m_method.methodSignature().isEmpty() || #endif m_arguments.isEmpty() || index.row() < 0 || index.row() >= m_arguments.size()) { return QVariant(); } if (role == Qt::DisplayRole || role == Qt::EditRole) { const QVariant value = m_arguments.at(index.row()); const QByteArray parameterName = m_method.parameterNames().at(index.row()); const QByteArray parameterType = m_method.parameterTypes().at(index.row()); switch (index.column()) { case 0: if (parameterName.isEmpty()) { return tr(" (%1)").arg(QString::fromLatin1(parameterType)); } return parameterName; case 1: return value; case 2: return parameterType; } } return QVariant(); } int MethodArgumentModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } int MethodArgumentModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_arguments.size(); } bool MethodArgumentModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.row() >= 0 && index.row() < m_arguments.size() && role == Qt::EditRole) { m_arguments[index.row()] = value; emit dataChanged(index, index); return true; } return QAbstractItemModel::setData(index, value, role); } QVariant MethodArgumentModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Argument"); case 1: return tr("Value"); case 2: return tr("Type"); } } return QAbstractItemModel::headerData(section, orientation, role); } Qt::ItemFlags MethodArgumentModel::flags(const QModelIndex &index) const { const Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.column() == 1) { return flags | Qt::ItemIsEditable; } return flags; } QVector MethodArgumentModel::arguments() const { QVector args(10); for (int i = 0; i < rowCount(); ++i) { args[i] = MethodArgument(m_arguments.at(i)); } return args; } gammaray-2.3.0/core/methodargumentmodel.h000066400000000000000000000043331255003167400204650ustar00rootroot00000000000000/* methodargumentmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METHODARGUMENTMODEL_H #define GAMMARAY_METHODARGUMENTMODEL_H #include #include #include #include namespace GammaRay { class MethodArgumentModel : public QAbstractTableModel { Q_OBJECT public: explicit MethodArgumentModel(QObject *parent = 0); void setMethod(const QMetaMethod &method); QVector arguments() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; private: QMetaMethod m_method; QVector m_arguments; }; } #endif // GAMMARAY_METHODARGUMENTMODEL_H gammaray-2.3.0/core/multisignalmapper.cpp000066400000000000000000000061771255003167400205210ustar00rootroot00000000000000/* multisignalmapper.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "multisignalmapper.h" #include #include #include #include namespace GammaRay { class MultiSignalMapperPrivate : public QObject { public: explicit MultiSignalMapperPrivate(MultiSignalMapper* parent) : QObject(parent), q(parent) {} ~MultiSignalMapperPrivate() {} int qt_metacall(QMetaObject::Call call, int methodId, void** args) { methodId = QObject::qt_metacall(call, methodId, args); if (methodId < 0) return methodId; if (call == QMetaObject::InvokeMetaMethod) { Q_ASSERT(sender()); const QVector v = convertArguments(sender(), methodId, args); emit q->signalEmitted(sender(), methodId, v); return -1; // indicates we handled the call } return methodId; } QVector convertArguments(QObject *sender, int signalIndex, void** args) { Q_ASSERT(sender); Q_ASSERT(signalIndex >= 0); const QMetaMethod signal = sender->metaObject()->method(signalIndex); Q_ASSERT(signal.methodType() == QMetaMethod::Signal); QVector v; const QList paramTypes = signal.parameterTypes(); for (int i = 0; i < paramTypes.size(); ++i) { int type = QMetaType::type(paramTypes[i]); if (type == QMetaType::Void || !type) { qWarning() << Q_FUNC_INFO << "unknown metatype for signal argument type" << paramTypes[i]; continue; } v.push_back(QVariant(type, args[i + 1])); } return v; } private: MultiSignalMapper* q; }; } using namespace GammaRay; MultiSignalMapper::MultiSignalMapper(QObject *parent) : QObject(parent), d(new MultiSignalMapperPrivate(this)) { } MultiSignalMapper::~MultiSignalMapper() { } void MultiSignalMapper::connectToSignal(QObject *sender, const QMetaMethod &signal) { QMetaObject::connect(sender, signal.methodIndex(), d, QObject::metaObject()->methodCount() + signal.methodIndex(), Qt::AutoConnection | Qt::UniqueConnection, 0); } gammaray-2.3.0/core/multisignalmapper.h000066400000000000000000000035021255003167400201530ustar00rootroot00000000000000/* multisignalmapper.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MULTISIGNALMAPPER_H #define GAMMARAY_MULTISIGNALMAPPER_H #include #include namespace GammaRay { class MultiSignalMapperPrivate; /** * A signal mapper that can deal with multiple signals from the same sender. */ class MultiSignalMapper : public QObject { Q_OBJECT public: explicit MultiSignalMapper(QObject *parent = 0); ~MultiSignalMapper(); void connectToSignal(QObject *sender, const QMetaMethod &signal); signals: void signalEmitted(QObject *sender, int signalIndex, const QVector &arguments); private: friend class MultiSignalMapperPrivate; MultiSignalMapperPrivate* const d; }; } #endif // GAMMARAY_MULTISIGNALMAPPER_H gammaray-2.3.0/core/objectclassinfomodel.cpp000066400000000000000000000040741255003167400211470ustar00rootroot00000000000000/* objectclassinfomodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectclassinfomodel.h" using namespace GammaRay; ObjectClassInfoModel::ObjectClassInfoModel(QObject *parent) : MetaObjectModel(parent) { } QVariant ObjectClassInfoModel::metaData(const QModelIndex &index, const QMetaClassInfo &classInfo, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return classInfo.name(); } if (index.column() == 1) { return classInfo.value(); } } return QVariant(); } int ObjectClassInfoModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } QString GammaRay::ObjectClassInfoModel::columnHeader(int index) const { switch (index) { case 0: return tr("Name"); case 1: return tr("Value"); } return QString(); } gammaray-2.3.0/core/objectclassinfomodel.h000066400000000000000000000037071255003167400206160ustar00rootroot00000000000000/* objectclassinfomodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTCLASSINFOMODEL_H #define GAMMARAY_OBJECTCLASSINFOMODEL_H #include "metaobjectmodel.h" #include namespace GammaRay { class ObjectClassInfoModel : public MetaObjectModel { public: explicit ObjectClassInfoModel(QObject *parent = 0); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant metaData(const QModelIndex &index, const QMetaClassInfo &classInfo, int role) const Q_DECL_OVERRIDE; QString columnHeader(int index) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_OBJECTCLASSINFOMODEL_H gammaray-2.3.0/core/objectdynamicpropertymodel.cpp000066400000000000000000000133221255003167400224130ustar00rootroot00000000000000/* objectdynamicpropertymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectdynamicpropertymodel.h" #include "varianthandler.h" #include "toolmodel.h" #include "probe.h" #include "toolfactory.h" #include "metaobjectrepository.h" #include #include using namespace GammaRay; ObjectDynamicPropertyModel::ObjectDynamicPropertyModel(QObject *parent) : ObjectPropertyModel(parent), m_propertyCount(0) { connect(this, SIGNAL(modelReset()), SLOT(updatePropertyCount())); } QVariant ObjectDynamicPropertyModel::data(const QModelIndex &index, int role) const { if (!m_obj) { return QVariant(); } const QList propNames = m_obj.data()->dynamicPropertyNames(); if (index.row() < 0 || index.row() >= propNames.size()) { return QVariant(); } const QByteArray propName = propNames.at(index.row()); const QVariant propValue = m_obj.data()->property(propName); if (role == Qt::DisplayRole || role == Qt::EditRole) { if (index.column() == 0) { return QString::fromUtf8(propName); } else if (index.column() == 1) { return role == Qt::EditRole ? propValue : VariantHandler::displayString(propValue); } else if (index.column() == 2) { return propValue.typeName(); } else if (index.column() == 3) { return tr(""); } } else if (role == PropertyModel::ActionRole) { return PropertyModel::Delete | ((MetaObjectRepository::instance()->metaObject(propValue.typeName()) && *reinterpret_cast(propValue.data())) || propValue.value() ? PropertyModel::NavigateTo : PropertyModel::NoAction); } else if (role == PropertyModel::ValueRole) { return propValue; } else if (role == PropertyModel::AppropriateToolRole) { ToolModel *toolModel = Probe::instance()->toolModel(); ToolFactory *factory; if (propValue.canConvert()) factory = toolModel->data(toolModel->toolForObject(propValue.value()), ToolModelRole::ToolFactory).value(); else factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast(propValue.data()), propValue.typeName()), ToolModelRole::ToolFactory).value(); if (factory) { return factory->name(); } return QVariant(); } return QVariant(); } bool ObjectDynamicPropertyModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!m_obj) { return false; } const QList propNames = m_obj.data()->dynamicPropertyNames(); if (index.row() < 0 || index.row() >= propNames.size()) { return false; } if (role == Qt::EditRole) { const QByteArray propName = propNames.at(index.row()); m_obj.data()->setProperty(propName, value); emit dataChanged(index, index); return true; } return QAbstractItemModel::setData(index, value, role); } Qt::ItemFlags ObjectDynamicPropertyModel::flags(const QModelIndex &index) const { const Qt::ItemFlags flags = ObjectPropertyModel::flags(index); if (!index.isValid() || !m_obj || index.column() != 1) { return flags; } return flags | Qt::ItemIsEditable; } int ObjectDynamicPropertyModel::rowCount(const QModelIndex &parent) const { if (!m_obj || parent.isValid()) { return 0; } return m_obj.data()->dynamicPropertyNames().size(); } int ObjectDynamicPropertyModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; } return 4; } QVariant ObjectDynamicPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Property"); case 1: return tr("Value"); case 2: return tr("Type"); case 3: return tr("Class"); } } return QAbstractItemModel::headerData(section, orientation, role); } void ObjectDynamicPropertyModel::monitorObject(QObject* obj) { obj->installEventFilter(this); } void ObjectDynamicPropertyModel::unmonitorObject(QObject* obj) { obj->removeEventFilter(this); } bool ObjectDynamicPropertyModel::eventFilter(QObject* receiver, QEvent* event) { if (receiver == m_obj && event->type() == QEvent::DynamicPropertyChange) { const int newPropertyCount = m_obj->dynamicPropertyNames().size(); if (newPropertyCount != m_propertyCount) { // FIXME: this can be done more efficiently... reset(); } else { // FIXME: send dataChanged for the affected cell only updateAll(); } } return ObjectPropertyModel::eventFilter(receiver, event); } void ObjectDynamicPropertyModel::updatePropertyCount() { m_propertyCount = rowCount(); } gammaray-2.3.0/core/objectdynamicpropertymodel.h000066400000000000000000000044501255003167400220620ustar00rootroot00000000000000/* objectdynamicpropertymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTDYNAMICPROPERTYMODEL_H #define GAMMARAY_OBJECTDYNAMICPROPERTYMODEL_H #include "objectpropertymodel.h" namespace GammaRay { class ObjectDynamicPropertyModel : public ObjectPropertyModel { Q_OBJECT public: explicit ObjectDynamicPropertyModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool eventFilter(QObject *receiver, QEvent *event) Q_DECL_OVERRIDE; protected: void monitorObject(QObject *obj) Q_DECL_OVERRIDE; void unmonitorObject(QObject *obj) Q_DECL_OVERRIDE; private slots: void updatePropertyCount(); private: int m_propertyCount; }; } #endif // GAMMARAY_OBJECTDYNAMICPROPERTYMODEL_H gammaray-2.3.0/core/objectenummodel.cpp000066400000000000000000000065601255003167400201340ustar00rootroot00000000000000/* objectenummodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectenummodel.h" #include #include using namespace GammaRay; typedef MetaObjectModel SuperClass; GammaRay::ObjectEnumModel::ObjectEnumModel(QObject *parent) : SuperClass(parent) { } int ObjectEnumModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { return SuperClass::rowCount(parent); } if (parent.parent().isValid()) { return 0; } const QMetaEnum e = m_metaObject->enumerator(parent.row()); return e.keyCount(); } int GammaRay::ObjectEnumModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } QVariant ObjectEnumModel::data(const QModelIndex &index, int role) const { if (!index.parent().isValid()) { return SuperClass::data(index, role); } if (role == Qt::DisplayRole) { const QMetaEnum e = m_metaObject->enumerator(index.parent().row()); if (index.column() == 0) { return e.key(index.row()); } if (index.column() == 1) { return e.value(index.row()); } } return QVariant(); } QVariant ObjectEnumModel::metaData(const QModelIndex &index, const QMetaEnum &enumerator, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return QString::fromLatin1(enumerator.name()); } if (index.column() == 1) { return tr("%n element(s)", "", enumerator.keyCount()); } } return QVariant(); } QString ObjectEnumModel::columnHeader(int index) const { switch (index) { case 0: return tr("Name"); case 1: return tr("Value"); } return QString(); } QModelIndex GammaRay::ObjectEnumModel::index(int row, int column, const QModelIndex &parent) const { if (!parent.isValid()) { return SuperClass::index(row, column, parent); } return createIndex(row, column, parent.row()); } QModelIndex GammaRay::ObjectEnumModel::parent(const QModelIndex &child) const { // note: Qt4 doesn't have qintptr if (static_cast(child.internalId()) == -1) { return SuperClass::parent(child); } return SuperClass::index(child.internalId(), 0, QModelIndex()); } gammaray-2.3.0/core/objectenummodel.h000066400000000000000000000042631255003167400175770ustar00rootroot00000000000000/* objectenummodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTENUMMODEL_H #define GAMMARAY_OBJECTENUMMODEL_H #include "metaobjectmodel.h" namespace GammaRay { class ObjectEnumModel : public MetaObjectModel { public: explicit ObjectEnumModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QString columnHeader(int index) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant metaData(const QModelIndex &index, const QMetaEnum &enumerator, int role) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_OBJECTENUMMODEL_H gammaray-2.3.0/core/objectlistmodel.cpp000066400000000000000000000065271255003167400201460ustar00rootroot00000000000000/* objectlistmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectlistmodel.h" #include "probe.h" #include #include #include using namespace GammaRay; using namespace std; ObjectListModel::ObjectListModel(Probe *probe) : ObjectModelBase< QAbstractTableModel >(probe) { connect(probe, SIGNAL(objectCreated(QObject*)), this, SLOT(objectAdded(QObject*))); connect(probe, SIGNAL(objectDestroyed(QObject*)), this, SLOT(objectRemoved(QObject*))); } QVariant ObjectListModel::data(const QModelIndex &index, int role) const { QMutexLocker lock(Probe::objectLock()); if (index.row() >= 0 && index.row() < m_objects.size()) { QObject *obj = m_objects.at(index.row()); if (Probe::instance()->isValidObject(obj)) { return dataForObject(obj, index, role); } } return QVariant(); } int ObjectListModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return ObjectModelBase::columnCount(parent); } int ObjectListModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_objects.size(); } void ObjectListModel::objectAdded(QObject *obj) { // see Probe::objectCreated, that promises a valid object in the main thread Q_ASSERT(QThread::currentThread() == thread()); Q_ASSERT(obj); Q_ASSERT(Probe::instance()->isValidObject(obj)); QVector::iterator it = std::lower_bound(m_objects.begin(), m_objects.end(), obj); Q_ASSERT(it == m_objects.end() || *it != obj); const int row = std::distance(m_objects.begin(), it); Q_ASSERT(row >= 0 && row <= m_objects.size()); beginInsertRows(QModelIndex(), row, row); m_objects.insert(it, obj); Q_ASSERT(m_objects.at(row) == obj); endInsertRows(); } void ObjectListModel::objectRemoved(QObject *obj) { Q_ASSERT(thread() == QThread::currentThread()); QVector::iterator it = std::lower_bound(m_objects.begin(), m_objects.end(), obj); if (it == m_objects.end() || *it != obj) { // not found return; } const int row = std::distance(m_objects.begin(), it); Q_ASSERT(row >= 0 && row < m_objects.size()); Q_ASSERT(m_objects.at(row) == obj); beginRemoveRows(QModelIndex(), row, row); m_objects.erase(it); endRemoveRows(); } gammaray-2.3.0/core/objectlistmodel.h000066400000000000000000000047401255003167400176060ustar00rootroot00000000000000/* objectlistmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTLISTMODEL_H #define GAMMARAY_OBJECTLISTMODEL_H #include "objectmodelbase.h" #include #include #include namespace GammaRay { class Probe; /** * NOTE: Making the model itself threadsafe works in theory, * but as soon as we put a proxymodel on top everything breaks. * Esp. the {begin,end}{InsertRemove}Rows() calls trigger * signals which apparently must be delivered directly to the proxy, * otherwise it's internal state may be messed up and assertions * start flying around... * So the solution: only call these methods in the main thread * and on remove. when called from a background thread, invalidate * the data first. */ class ObjectListModel : public ObjectModelBase { Q_OBJECT public: explicit ObjectListModel(Probe *probe); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; private slots: void objectAdded(QObject *obj); void objectRemoved(QObject *obj); private: void removeObject(QObject *obj); // sorted vector for stable iterators/indexes, esp. for the model methods QVector m_objects; }; } #endif // GAMMARAY_OBJECTLISTMODEL_H gammaray-2.3.0/core/objectmethodmodel.cpp000066400000000000000000000073161255003167400204500ustar00rootroot00000000000000/* objectmethodmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectmethodmodel.h" #include "util.h" using namespace GammaRay; ObjectMethodModel::ObjectMethodModel(QObject *parent) : MetaObjectModel(parent) { } int GammaRay::ObjectMethodModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } QVariant ObjectMethodModel::metaData(const QModelIndex &index, const QMetaMethod &method, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::prettyMethodSignature(method); } if (index.column() == 1) { switch (method.methodType()) { case QMetaMethod::Method: return tr("Method"); case QMetaMethod::Constructor: return tr("Constructor"); case QMetaMethod::Slot: return tr("Slot"); case QMetaMethod::Signal: return tr("Signal"); default: return tr("Unknown"); } } if (index.column() == 2) { switch (method.access()) { case QMetaMethod::Public: return tr("Public"); case QMetaMethod::Protected: return tr("Protected"); case QMetaMethod::Private: return tr("Private"); default: return tr("Unknown"); } } } else if (role == Qt::ToolTipRole) { QString tt = Util::prettyMethodSignature(method); tt += tr("\nTag: %1\n").arg(qstrlen(method.tag()) > 0 ? method.tag() : ""); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) tt += tr("Revision: %1").arg(method.revision()); #endif return tt; } else if (role == ObjectMethodModelRole::MetaMethod) { return QVariant::fromValue(method); } else if (role == ObjectMethodModelRole::MetaMethodType) { return QVariant::fromValue(method.methodType()); } else if (role == ObjectMethodModelRole::MethodSignature) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return method.signature(); #else return method.methodSignature(); #endif } return QVariant(); } QString GammaRay::ObjectMethodModel::columnHeader(int index) const { switch (index) { case 0: return tr("Signature"); case 1: return tr("Type"); case 2: return tr("Access"); } return QString(); } QMap< int, QVariant > ObjectMethodModel::itemData(const QModelIndex& index) const { QMap m = super::itemData(index); m.insert(ObjectMethodModelRole::MetaMethodType, data(index, ObjectMethodModelRole::MetaMethodType)); m.insert(ObjectMethodModelRole::MethodSignature, data(index, ObjectMethodModelRole::MethodSignature)); return m; } gammaray-2.3.0/core/objectmethodmodel.h000066400000000000000000000040241255003167400201060ustar00rootroot00000000000000/* objectmethodmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTMETHODMODEL_H #define GAMMARAY_OBJECTMETHODMODEL_H #include "metaobjectmodel.h" #include #include #include namespace GammaRay { class ObjectMethodModel : public MetaObjectModel { public: explicit ObjectMethodModel(QObject *parent = 0); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QMap< int, QVariant > itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; protected: QVariant metaData(const QModelIndex &index, const QMetaMethod &method, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QString columnHeader(int index) const Q_DECL_OVERRIDE; }; } Q_DECLARE_METATYPE(QMetaMethod) #endif // GAMMARAY_OBJECTMETHODMODEL_H gammaray-2.3.0/core/objectmodelbase.h000066400000000000000000000077261255003167400175540ustar00rootroot00000000000000/* objectmodelbase.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares a template for an ObjectModelBase class. @brief Declares a template for an ObjectModelBase class. @author Volker Krause \ */ #ifndef GAMMARAY_OBJECTMODELBASE_H #define GAMMARAY_OBJECTMODELBASE_H #include "util.h" #include #include #include namespace GammaRay { /** * @brief A container for a generic Object Model derived from some Base. */ template class ObjectModelBase : public Base { public: /** * Constructor. * @param parent is the parent object for this instance. */ explicit ObjectModelBase(QObject *parent) : Base(parent) { } /** * Returns the number of columns in the specified model (currently this is * always 2). * @param parent is the model QModelIndex. * @return the column count for specified model. */ int columnCount(const QModelIndex &parent = QModelIndex()) const { Q_UNUSED(parent); return 2; } /** * Returns the data for the specified object. * @param object is a pointer to a QObject. * @param index is the model QModelIndex. * @param role is the Qt role. * * @return on success, a QVariant containing the data for the specified QObject; * QVariant() if some anamoly occurs. */ QVariant dataForObject(QObject *object, const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::shortDisplayString(object); } else if (index.column() == 1) { return object->metaObject()->className(); } } else if (role == ObjectModel::ObjectRole) { return QVariant::fromValue(object); } else if (role == Qt::ToolTipRole) { return Util::tooltipForObject(object); } else if (role == Qt::DecorationRole && index.column() == 0) { return Util::iconForObject(object); } return QVariant(); } /** * Returns the header data for the Object, given a section (column), * orientation and role. * @param section an integer (either 0 or 1) corresponding to the section (column). * @param orientation is the Qt::Orientation. * @param role is the Qt role. * * @return on success, a QVariant containing the header data; * QVariant() if some anamoly occurs. * */ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return QObject::tr("Object"); case 1: return QObject::tr("Type"); } } return Base::headerData(section, orientation, role); } }; } #endif gammaray-2.3.0/core/objectpropertymodel.cpp000066400000000000000000000051221255003167400210450ustar00rootroot00000000000000/* objectpropertymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectpropertymodel.h" #include #include #include using namespace GammaRay; ObjectPropertyModel::ObjectPropertyModel(QObject *parent) : QAbstractTableModel(parent), m_metaObject(0), m_updateTimer(new QTimer(this)) { connect(m_updateTimer, SIGNAL(timeout()), SLOT(doEmitChanged())); m_updateTimer->setSingleShot(true); } void ObjectPropertyModel::setObject(QObject *object) { if (m_obj == object) return; beginResetModel(); if (m_obj) { unmonitorObject(m_obj.data()); disconnect(m_obj.data(), SIGNAL(destroyed(QObject*)), this, SLOT(slotReset())); } m_obj = object; m_metaObject = object ? object->metaObject() : 0; if (object) { connect(object, SIGNAL(destroyed(QObject*)), SLOT(slotReset())); monitorObject(object); } endResetModel(); } QMap< int, QVariant > ObjectPropertyModel::itemData(const QModelIndex& index) const { QMap d = QAbstractItemModel::itemData(index); d.insert(PropertyModel::ActionRole, data(index, PropertyModel::ActionRole)); d.insert(PropertyModel::AppropriateToolRole, data(index, PropertyModel::AppropriateToolRole)); return d; } void ObjectPropertyModel::updateAll() { if (m_updateTimer->isActive()) { return; } m_updateTimer->start(100); } void ObjectPropertyModel::doEmitChanged() { emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } void ObjectPropertyModel::slotReset() { reset(); } gammaray-2.3.0/core/objectpropertymodel.h000066400000000000000000000040421255003167400205120ustar00rootroot00000000000000/* objectpropertymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTPROPERTYMODEL_H #define GAMMARAY_OBJECTPROPERTYMODEL_H #include #include class QTimer; namespace GammaRay { // ### very little value left in here, dissolve into sub-classes? class ObjectPropertyModel : public QAbstractTableModel { Q_OBJECT public: explicit ObjectPropertyModel(QObject *parent = 0); void setObject(QObject *object); QMap itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; protected: /** Reimplement to set up watching property change notifications. */ virtual void monitorObject(QObject* obj) = 0; virtual void unmonitorObject(QObject* obj) = 0; QPointer m_obj; const QMetaObject* m_metaObject; protected slots: void updateAll(); private slots: void slotReset(); void doEmitChanged(); private: QTimer *m_updateTimer; }; } #endif // GAMMARAY_OBJECTPROPERTYMODEL_H gammaray-2.3.0/core/objectstaticpropertymodel.cpp000066400000000000000000000212251255003167400222570ustar00rootroot00000000000000/* objectstaticpropertymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectstaticpropertymodel.h" #include "varianthandler.h" #include "util.h" #include "probe.h" #include "toolmodel.h" #include "toolfactory.h" #include "metaobjectrepository.h" #include #include #include using namespace GammaRay; ObjectStaticPropertyModel::ObjectStaticPropertyModel(QObject *parent) : ObjectPropertyModel(parent) { } static QString translateBool(bool value) { return value ? QObject::tr("yes") : QObject::tr("no"); } void ObjectStaticPropertyModel::setMetaObject(const QMetaObject* mo) { setObject(0); if (mo == m_metaObject) return; beginResetModel(); m_metaObject = mo; endResetModel(); } QVariant ObjectStaticPropertyModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_metaObject || index.row() < 0 || index.row() >= m_metaObject->propertyCount()) { return QVariant(); } const QMetaProperty prop = m_metaObject->property(index.row()); const QVariant value = m_obj ? prop.read(m_obj.data()) : QVariant(); if (role == Qt::DisplayRole) { if (index.column() == propertyColumnIndex()) { return prop.name(); } else if (index.column() == valueColumnIndex()) { // QMetaProperty::read sets QVariant::typeName to int for enums, // so we need to handle that separately here const QString enumStr = Util::enumToString(value, prop.typeName(), m_obj.data()); if (!enumStr.isEmpty()) { return enumStr; } return VariantHandler::displayString(value); } else if (index.column() == typeColumnIndex()) { return prop.typeName(); } else if (index.column() == classColumnIndex()) { const QMetaObject *mo = m_metaObject; while (mo->propertyOffset() > index.row()) { mo = mo->superClass(); } return mo->className(); } } else if (role == Qt::DecorationRole) { if (index.column() == valueColumnIndex()) { return VariantHandler::decoration(value); } } else if (role == Qt::EditRole) { if (index.column() == valueColumnIndex()) { return value; } } else if (role == Qt::ToolTipRole) { return detailString(prop); } else if (role == PropertyModel::ActionRole) { if (!m_obj) return PropertyModel::NoAction; return (prop.isResettable() ? PropertyModel::Reset : PropertyModel::NoAction) | ((MetaObjectRepository::instance()->metaObject(value.typeName()) && *reinterpret_cast(value.data())) || value.value() ? PropertyModel::NavigateTo : PropertyModel::NoAction); } else if (role == PropertyModel::ValueRole) { return value; } else if (role == PropertyModel::AppropriateToolRole) { ToolModel *toolModel = Probe::instance()->toolModel(); ToolFactory *factory; if (value.canConvert()) factory = toolModel->data(toolModel->toolForObject(value.value()), ToolModelRole::ToolFactory).value(); else factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast(value.data()), value.typeName()), ToolModelRole::ToolFactory).value(); if (factory) { return factory->name(); } return QVariant(); } return QVariant(); } bool ObjectStaticPropertyModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && m_obj && index.column() == valueColumnIndex() && index.row() >= 0 && index.row() < m_obj.data()->metaObject()->propertyCount() && role == Qt::EditRole) { const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row()); const bool result = prop.write(m_obj.data(), value); if (result) { emit dataChanged(index, index); } return result; } return ObjectPropertyModel::setData(index, value, role); } int ObjectStaticPropertyModel::rowCount(const QModelIndex &parent) const { if (!m_metaObject || parent.isValid()) { return 0; } return m_metaObject->propertyCount(); } int ObjectStaticPropertyModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; } return isObjectMode() ? 4 : 3; } Qt::ItemFlags ObjectStaticPropertyModel::flags(const QModelIndex &index) const { const Qt::ItemFlags flags = ObjectPropertyModel::flags(index); if (!index.isValid() || !m_obj || index.column() != valueColumnIndex() || index.row() < 0 || index.row() >= m_obj.data()->metaObject()->propertyCount()) { return flags; } const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row()); if (prop.isWritable()) { return flags | Qt::ItemIsEditable; } return flags; } QVariant ObjectStaticPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == propertyColumnIndex()) return tr("Property"); if (section == valueColumnIndex()) return tr("Value"); if (section == typeColumnIndex()) return tr("Type"); if (section == classColumnIndex()) return tr("Class"); } return QAbstractItemModel::headerData(section, orientation, role); } void ObjectStaticPropertyModel::monitorObject(QObject* obj) { for (int i = 0; i < obj->metaObject()->propertyCount(); ++i) { const QMetaProperty prop = obj->metaObject()->property(i); if (prop.hasNotifySignal()) { connect(obj, QByteArray("2") + #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) prop.notifySignal().signature() #else prop.notifySignal().methodSignature() #endif , this, SLOT(propertyUpdated())); m_notifyToPropertyMap.insert(prop.notifySignalIndex(), i); } } } void ObjectStaticPropertyModel::unmonitorObject(QObject* obj) { disconnect(obj, 0, this, SLOT(propertyUpdated())); m_notifyToPropertyMap.clear(); } void ObjectStaticPropertyModel::propertyUpdated() { #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) Q_ASSERT(senderSignalIndex() >= 0); const int propertyIndex = m_notifyToPropertyMap.value(senderSignalIndex()); emit dataChanged(index(propertyIndex, valueColumnIndex()), index(propertyIndex, valueColumnIndex())); #else emit dataChanged(index(0,valueColumnIndex()), index(rowCount() - 1, valueColumnIndex())); #endif } QString ObjectStaticPropertyModel::detailString(const QMetaProperty& prop) const { QStringList s; s << tr("Constant: %1").arg(translateBool(prop.isConstant())); s << tr("Designable: %1").arg(translateBool(prop.isDesignable(m_obj.data()))); s << tr("Final: %1").arg(translateBool(prop.isFinal())); if (prop.hasNotifySignal()) { s << tr("Notification: %1").arg(Util::prettyMethodSignature(prop.notifySignal())); } else { s << tr("Notification: no"); } s << tr("Resetable: %1").arg(translateBool(prop.isResettable())); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) s << tr("Revision: %1").arg(prop.revision()); #endif s << tr("Scriptable: %1").arg(translateBool(prop.isScriptable(m_obj.data()))); s << tr("Stored: %1").arg(translateBool(prop.isStored(m_obj.data()))); s << tr("User: %1").arg(translateBool(prop.isUser(m_obj.data()))); s << tr("Writable: %1").arg(translateBool(prop.isWritable())); return s.join("\n"); } bool ObjectStaticPropertyModel::isObjectMode() const { return m_obj || !m_metaObject; } int ObjectStaticPropertyModel::propertyColumnIndex() const { return 0; } int ObjectStaticPropertyModel::valueColumnIndex() const { return isObjectMode() ? 1: -1; } int ObjectStaticPropertyModel::typeColumnIndex() const { return isObjectMode() ? 2 : 1; } int ObjectStaticPropertyModel::classColumnIndex() const { return isObjectMode() ? 3 : 2; } gammaray-2.3.0/core/objectstaticpropertymodel.h000066400000000000000000000051071255003167400217250ustar00rootroot00000000000000/* objectstaticpropertymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTSTATICPROPERTYMODEL_H #define GAMMARAY_OBJECTSTATICPROPERTYMODEL_H #include "objectpropertymodel.h" namespace GammaRay { class ObjectStaticPropertyModel : public ObjectPropertyModel { Q_OBJECT public: explicit ObjectStaticPropertyModel(QObject *parent = 0); void setMetaObject(const QMetaObject *mo); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; void monitorObject(QObject* obj) Q_DECL_OVERRIDE; void unmonitorObject(QObject* obj) Q_DECL_OVERRIDE; private slots: void propertyUpdated(); private: QString detailString(const QMetaProperty& prop) const; /// object mode: show all 4 columns, meta object mode: hide the value column bool isObjectMode() const; int propertyColumnIndex() const; int valueColumnIndex() const; int typeColumnIndex() const; int classColumnIndex() const; QHash m_notifyToPropertyMap; }; } #endif // GAMMARAY_OBJECTSTATICPROPERTYMODEL_H gammaray-2.3.0/core/objecttreemodel.cpp000066400000000000000000000202201255003167400201140ustar00rootroot00000000000000/* objecttreemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objecttreemodel.h" #include "probe.h" #include #include #include #include #include #define IF_DEBUG(x) extern void dumpObject(QObject *); using namespace std; using namespace GammaRay; ObjectTreeModel::ObjectTreeModel(Probe *probe) : ObjectModelBase< QAbstractItemModel >(probe) { connect(probe, SIGNAL(objectCreated(QObject*)), this, SLOT(objectAdded(QObject*))); connect(probe, SIGNAL(objectDestroyed(QObject*)), this, SLOT(objectRemoved(QObject*))); connect(probe, SIGNAL(objectReparented(QObject*)), this, SLOT(objectReparented(QObject*))); } static inline QObject *parentObject(QObject *obj) { return obj->parent(); } void ObjectTreeModel::objectAdded(QObject *obj) { // see Probe::objectCreated, that promises a valid object in the main thread here Q_ASSERT(thread() == QThread::currentThread()); Q_ASSERT(Probe::instance()->isValidObject(obj)); IF_DEBUG(cout << "tree obj added: " << hex << obj << " p: " << parentObject(obj) << endl;) Q_ASSERT(!obj->parent() || Probe::instance()->isValidObject(parentObject(obj))); if (indexForObject(obj).isValid()) { IF_DEBUG(cout << "tree double obj added: " << hex << obj << endl;) return; } // this is ugly, but apparently it can happen // that an object gets created without parent // then later the delayed signal comes in // so catch this gracefully by first adding the // parent if required if (parentObject(obj)) { const QModelIndex index = indexForObject(parentObject(obj)); if (!index.isValid()) { IF_DEBUG(cout << "tree: handle parent first" << endl;) objectAdded(parentObject(obj)); } } const QModelIndex index = indexForObject(parentObject(obj)); // either we get a proper parent and hence valid index or there is no parent Q_ASSERT(index.isValid() || !parentObject(obj)); QVector &children = m_parentChildMap[ parentObject(obj) ]; QVector::iterator it = std::lower_bound(children.begin(), children.end(), obj); const int row = std::distance(children.begin(), it); beginInsertRows(index, row, row); children.insert(it, obj); m_childParentMap.insert(obj, parentObject(obj)); endInsertRows(); } void ObjectTreeModel::objectRemoved(QObject *obj) { // slot, hence should always land in main thread due to auto connection Q_ASSERT(thread() == QThread::currentThread()); IF_DEBUG(cout << "tree removed: " << hex << obj << " " << hex << obj->parent() << dec << " " << m_parentChildMap.value(obj->parent()).size() << " " << m_parentChildMap.contains(obj) << endl;) if (!m_childParentMap.contains(obj)) { Q_ASSERT(!m_parentChildMap.contains(obj)); return; } QObject *parentObj = m_childParentMap[ obj ]; const QModelIndex parentIndex = indexForObject(parentObj); if (parentObj && !parentIndex.isValid()) { return; } QVector &siblings = m_parentChildMap[ parentObj ]; QVector::iterator it = std::lower_bound(siblings.begin(), siblings.end(), obj); if (it == siblings.end() || *it != obj) { return; } const int row = std::distance(siblings.begin(), it); beginRemoveRows(parentIndex, row, row); siblings.erase(it); m_childParentMap.remove(obj); m_parentChildMap.remove(obj); endRemoveRows(); } void ObjectTreeModel::objectReparented(QObject *obj) { // slot, hence should always land in main thread due to auto connection Q_ASSERT(thread() == QThread::currentThread()); IF_DEBUG(cout << "object reparented: " << hex << obj << dec << endl;) QMutexLocker objectLock(Probe::objectLock()); if (!Probe::instance()->isValidObject(obj)) { objectRemoved(obj); return; } // we didn't know obj yet if (!m_childParentMap.contains(obj)) { Q_ASSERT(!m_parentChildMap.contains(obj)); objectAdded(obj); return; } QObject *oldParent = m_childParentMap.value(obj); const auto sourceParent = indexForObject(oldParent); if ((oldParent && !sourceParent.isValid()) || (oldParent == parentObject(obj))) return; QVector &oldSiblings = m_parentChildMap[oldParent]; QVector::iterator oldIt = std::lower_bound(oldSiblings.begin(), oldSiblings.end(), obj); if (oldIt == oldSiblings.end() || *oldIt != obj) return; const int sourceRow = std::distance(oldSiblings.begin(), oldIt); IF_DEBUG(cout << "actually reparenting! " << hex << obj << " old parent: " << oldParent << " new parent: " << parentObject(obj) << dec << endl;) const auto destParent = indexForObject(parentObject(obj)); Q_ASSERT(destParent.isValid() || !parentObject(obj)); QVector &newSiblings = m_parentChildMap[parentObject(obj)]; QVector::iterator newIt = std::lower_bound(newSiblings.begin(), newSiblings.end(), obj); const int destRow = std::distance(newSiblings.begin(), newIt); beginMoveRows(sourceParent, sourceRow, sourceRow, destParent, destRow); oldSiblings.erase(oldIt); newSiblings.insert(newIt, obj); m_childParentMap.insert(obj, parentObject(obj)); endMoveRows(); } QVariant ObjectTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QObject *obj = reinterpret_cast(index.internalPointer()); QMutexLocker lock(Probe::objectLock()); if (Probe::instance()->isValidObject(obj)) { return dataForObject(obj, index, role); } else if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::addressToString(obj); } else { return tr(""); } } return QVariant(); } int ObjectTreeModel::rowCount(const QModelIndex &parent) const { if (parent.column() == 1) { return 0; } QObject *parentObj = reinterpret_cast(parent.internalPointer()); return m_parentChildMap.value(parentObj).size(); } QModelIndex ObjectTreeModel::parent(const QModelIndex &child) const { QObject *childObj = reinterpret_cast(child.internalPointer()); return indexForObject(m_childParentMap.value(childObj)); } QModelIndex ObjectTreeModel::index(int row, int column, const QModelIndex &parent) const { QObject *parentObj = reinterpret_cast(parent.internalPointer()); const QVector children = m_parentChildMap.value(parentObj); if (row < 0 || column < 0 || row >= children.size() || column >= columnCount()) { return QModelIndex(); } return createIndex(row, column, children.at(row)); } QModelIndex ObjectTreeModel::indexForObject(QObject *object) const { if (!object) { return QModelIndex(); } QObject *parent = m_childParentMap.value(object); const QModelIndex parentIndex = indexForObject(parent); if (!parentIndex.isValid() && parent) { return QModelIndex(); } const QVector &siblings = m_parentChildMap[ parent ]; QVector::const_iterator it = std::lower_bound(siblings.constBegin(), siblings.constEnd(), object); if (it == siblings.constEnd() || *it != object) { return QModelIndex(); } const int row = std::distance(siblings.constBegin(), it); return index(row, 0, parentIndex); } gammaray-2.3.0/core/objecttreemodel.h000066400000000000000000000041521255003167400175670ustar00rootroot00000000000000/* objecttreemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTTREEMODEL_H #define GAMMARAY_OBJECTTREEMODEL_H #include "objectmodelbase.h" #include namespace GammaRay { class Probe; class ObjectTreeModel : public ObjectModelBase { Q_OBJECT public: explicit ObjectTreeModel(Probe *probe); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; private slots: void objectAdded(QObject *obj); void objectRemoved(QObject *obj); void objectReparented(QObject *obj); private: QModelIndex indexForObject(QObject *object) const; private: QHash m_childParentMap; QHash > m_parentChildMap; }; } #endif // GAMMARAY_OBJECTTREEMODEL_H gammaray-2.3.0/core/objecttypefilterproxymodel.h000066400000000000000000000071761255003167400221320ustar00rootroot00000000000000/* objecttypefilterproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares a template for an ObjectTypeFilterProxyModel class. @brief Declares a template for an ObjectTypeFilterProxyModel class. @author Volker Krause \ */ #ifndef GAMMARAY_OBJECTTYPEFILTERPROXYMODEL_H #define GAMMARAY_OBJECTTYPEFILTERPROXYMODEL_H #include "objectmodelbase.h" #include namespace GammaRay { /** * @brief A QSortFilterProxyModel for generic Objects. */ class ObjectFilterProxyModelBase : public QSortFilterProxyModel { public: /** * Constructor. * @param parent is the parent object for this instance. */ explicit ObjectFilterProxyModelBase(QObject *parent = 0) : QSortFilterProxyModel(parent) { setDynamicSortFilter(true); } protected: /** * Determines if the item in the specified row can be included in the model. * @param source_row is a non-zero integer representing the row of the item. * @param source_parent is the parent QModelIndex for this model. * @return true if the item in the row can be included in the model; * otherwise returns false. */ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent); if (!source_index.isValid()) { return false; } QObject *obj = source_index.data(ObjectModel::ObjectRole).value(); if (!obj || !filterAcceptsObject(obj)) { return false; } return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } /** * Determines if the specified QObject can be included in the model. * @param object is a pointer to the QObject to test. * @return true if the QObject can be included in the model; false otherwise. */ virtual bool filterAcceptsObject(QObject *object) const = 0; }; /** * @brief A templated generic ObjectFilterProxyModelBase for some data type. */ template class ObjectTypeFilterProxyModel : public ObjectFilterProxyModelBase { public: /** * Constructor. * @param parent is the parent object for this instance. */ explicit ObjectTypeFilterProxyModel(QObject *parent = 0) : ObjectFilterProxyModelBase(parent) { } protected: virtual bool filterAcceptsObject(QObject *object) const { return qobject_cast(object); } }; } #endif // GAMMARAY_OBJECTTYPEFILTERPROXYMODEL_H gammaray-2.3.0/core/probe.cpp000066400000000000000000000717341255003167400160740ustar00rootroot00000000000000/* probe.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //krazy:excludeall=null,captruefalse,staticobjects #include #include "probe.h" #include "objectlistmodel.h" #include "objecttreemodel.h" #include "metaobjecttreemodel.h" #include "connectionmodel.h" #include "toolmodel.h" #include "probesettings.h" #include "probecontroller.h" #include "toolpluginmodel.h" #include "util.h" #include <3rdparty/qt/modeltest.h> #include "remote/server.h" #include "remote/remotemodelserver.h" #include "remote/serverproxymodel.h" #include "remote/selectionmodelserver.h" #include "toolpluginerrormodel.h" #include "toolfactory.h" #include "probeguard.h" #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #endif #include #include #include #include #include #include #include #ifdef HAVE_PRIVATE_QT_HEADERS #include #else struct QSignalSpyCallbackSet { typedef void (*BeginCallback)(QObject *caller, int method_index, void **argv); typedef void (*EndCallback)(QObject *caller, int method_index); BeginCallback signal_begin_callback, slot_begin_callback; EndCallback signal_end_callback, slot_end_callback; }; extern void qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set); extern QSignalSpyCallbackSet qt_signal_spy_callback_set; #endif #include #include #include #define IF_DEBUG(x) using namespace GammaRay; using namespace std; QAtomicPointer Probe::s_instance = QAtomicPointer(0); namespace GammaRay { #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) static bool probeConnectCallback(void ** args) { QObject *sender = reinterpret_cast(args[0]); const char *signal = reinterpret_cast(args[1]); QObject *receiver = reinterpret_cast(args[2]); const char *method = reinterpret_cast(args[3]); const Qt::ConnectionType *type = reinterpret_cast(args[4]); Probe::connectionAdded(sender, signal, receiver, method, *type); return false; } static bool probeDisconnectCallback(void ** args) { QObject *sender = reinterpret_cast(args[0]); const char *signal = reinterpret_cast(args[1]); QObject *receiver = reinterpret_cast(args[2]); const char *method = reinterpret_cast(args[3]); Probe::connectionRemoved(sender, signal, receiver, method); return false; } #endif // QT_VERSION static void signal_begin_callback(QObject *caller, int method_index, void **argv) { if (method_index == 0 || Probe::instance()->filterObject(caller)) return; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) method_index = Util::signalIndexToMethodIndex(caller->metaObject(), method_index); #endif Probe::executeSignalCallback([=](const SignalSpyCallbackSet &callbacks) { if (callbacks.signalBeginCallback) { callbacks.signalBeginCallback(caller, method_index, argv); } }); } static void signal_end_callback(QObject *caller, int method_index) { if (method_index == 0) return; QMutexLocker locker(Probe::objectLock()); if (!Probe::instance()->isValidObject(caller)) // implies filterObject() return; // deleted in the slot #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) method_index = Util::signalIndexToMethodIndex(caller->metaObject(), method_index); #endif Probe::executeSignalCallback([=](const SignalSpyCallbackSet &callbacks) { if (callbacks.signalEndCallback) { callbacks.signalEndCallback(caller, method_index); } }); } static void slot_begin_callback(QObject *caller, int method_index, void **argv) { if (method_index == 0 || Probe::instance()->filterObject(caller)) return; Probe::executeSignalCallback([=](const SignalSpyCallbackSet &callbacks) { if (callbacks.slotBeginCallback) { callbacks.slotBeginCallback(caller, method_index, argv); } }); } static void slot_end_callback(QObject *caller, int method_index) { if (method_index == 0) return; QMutexLocker locker(Probe::objectLock()); if (!Probe::instance()->isValidObject(caller)) // implies filterObject() return; // deleted in the slot Probe::executeSignalCallback([=](const SignalSpyCallbackSet &callbacks) { if (callbacks.slotEndCallback) { callbacks.slotEndCallback(caller, method_index); } }); } static QItemSelectionModel *selectionModelFactory(QAbstractItemModel *model) { Q_ASSERT(!model->objectName().isEmpty()); return new SelectionModelServer(model->objectName() + ".selection", model, Probe::instance()); } } // useful for debugging, dumps the object and all it's parents // also useable from GDB! void dumpObject(QObject *obj) { if (!obj) { cout << "QObject(0x0)" << endl; return; } const std::ios::fmtflags oldFlags(cout.flags()); do { cout << obj->metaObject()->className() << "(" << hex << obj << ")"; obj = obj->parent(); if (obj) { cout << " <- "; } } while(obj); cout << endl; cout.flags(oldFlags); } struct Listener { Listener() : trackDestroyed(true) { } bool trackDestroyed; QVector addedBeforeProbeInstance; }; Q_GLOBAL_STATIC(Listener, s_listener) // ensures proper information is returned by isValidObject by // locking it in objectAdded/Removed Q_GLOBAL_STATIC_WITH_ARGS(QMutex, s_lock, (QMutex::Recursive)) Probe::Probe(QObject *parent): QObject(parent), m_objectListModel(new ObjectListModel(this)), m_objectTreeModel(new ObjectTreeModel(this)), m_metaObjectTreeModel(new MetaObjectTreeModel(this)), m_connectionModel(new ConnectionModel(this)), m_toolModel(0), m_window(0), m_queueTimer(new QTimer(this)) { Q_ASSERT(thread() == qApp->thread()); IF_DEBUG(cout << "attaching GammaRay probe" << endl;) ProbeSettings::receiveSettings(); m_toolModel = new ToolModel(this); auto sortedToolModel = new ServerProxyModel(this); sortedToolModel->setSourceModel(m_toolModel); sortedToolModel->setDynamicSortFilter(true); sortedToolModel->sort(0); Server *server = new Server(this); ProbeSettings::sendServerAddress(server->externalAddress()); StreamOperators::registerOperators(); ObjectBroker::setSelectionModelFactoryCallback(selectionModelFactory); ObjectBroker::registerObject(new ProbeController(this)); registerModel(QLatin1String("com.kdab.GammaRay.ObjectTree"), m_objectTreeModel); registerModel(QLatin1String("com.kdab.GammaRay.ObjectList"), m_objectListModel); registerModel(QLatin1String("com.kdab.GammaRay.MetaObjectModel"), m_metaObjectTreeModel); registerModel(QLatin1String("com.kdab.GammaRay.ToolModel"), sortedToolModel); registerModel(QLatin1String("com.kdab.GammaRay.ConnectionModel"), m_connectionModel); m_toolSelectionModel = ObjectBroker::selectionModel(sortedToolModel); ToolPluginModel *toolPluginModel = new ToolPluginModel(m_toolModel->plugins(), this); registerModel(QLatin1String("com.kdab.GammaRay.ToolPluginModel"), toolPluginModel); ToolPluginErrorModel *toolPluginErrorModel = new ToolPluginErrorModel(m_toolModel->pluginErrors(), this); registerModel(QLatin1String("com.kdab.GammaRay.ToolPluginErrorModel"), toolPluginErrorModel); if (qgetenv("GAMMARAY_MODELTEST") == "1") { new ModelTest(m_objectListModel, m_objectListModel); new ModelTest(m_objectTreeModel, m_objectTreeModel); new ModelTest(m_connectionModel, m_connectionModel); new ModelTest(m_toolModel, m_toolModel); } #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) QInternal::registerCallback(QInternal::ConnectCallback, &GammaRay::probeConnectCallback); QInternal::registerCallback(QInternal::DisconnectCallback, &GammaRay::probeDisconnectCallback); #endif m_queueTimer->setSingleShot(true); m_queueTimer->setInterval(0); connect(m_queueTimer, SIGNAL(timeout()), this, SLOT(queuedObjectsFullyConstructed())); m_previousSignalSpyCallbackSet.signalBeginCallback = qt_signal_spy_callback_set.signal_begin_callback; m_previousSignalSpyCallbackSet.signalEndCallback =qt_signal_spy_callback_set.signal_end_callback; m_previousSignalSpyCallbackSet.slotBeginCallback = qt_signal_spy_callback_set.slot_begin_callback; m_previousSignalSpyCallbackSet.slotEndCallback = qt_signal_spy_callback_set.slot_end_callback; registerSignalSpyCallbackSet(m_previousSignalSpyCallbackSet); // daisy-chain existing callbacks } Probe::~Probe() { IF_DEBUG(cerr << "detaching GammaRay probe" << endl;) const QSignalSpyCallbackSet prevCallbacks = { m_previousSignalSpyCallbackSet.signalBeginCallback, m_previousSignalSpyCallbackSet.slotBeginCallback, m_previousSignalSpyCallbackSet.signalEndCallback, m_previousSignalSpyCallbackSet.slotEndCallback }; qt_register_signal_spy_callbacks(prevCallbacks); #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) QInternal::unregisterCallback(QInternal::ConnectCallback, &GammaRay::probeConnectCallback); QInternal::unregisterCallback(QInternal::DisconnectCallback, &GammaRay::probeDisconnectCallback); #endif ObjectBroker::clear(); ProbeSettings::resetLauncherIdentifier(); s_instance = QAtomicPointer(0); } void Probe::setWindow(QObject *window) { m_window = window; } QObject *Probe::window() const { return m_window; } Probe *GammaRay::Probe::instance() { if (!qApp) { return NULL; } #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) return s_instance; #else return s_instance.load(); #endif } bool Probe::isInitialized() { return instance() && qApp; } bool Probe::canShowWidgets() { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) const QApplication * const qGuiApplication = qobject_cast(qApp); return qGuiApplication && qGuiApplication->type() != QApplication::Tty; #else return QCoreApplication::instance()->inherits("QApplication"); #endif } void Probe::createProbe(bool findExisting) { Q_ASSERT(!isInitialized()); // first create the probe and its children // we must not hold the object lock here as otherwise we can deadlock // with other QObject's we create and other threads are using. One // example are QAbstractSocketEngine. IF_DEBUG(cout << "setting up new probe instance" << endl;) Probe *probe = 0; { ProbeGuard guard; probe = new Probe; } IF_DEBUG(cout << "done setting up new probe instance" << endl;) connect(qApp, SIGNAL(aboutToQuit()), probe, SLOT(deleteLater())); // now we can get the lock and add items which where added before this point in time { QMutexLocker lock(s_lock()); // now we set the instance while holding the lock, // all future calls to object{Added,Removed} will // act directly on the data structures there instead // of using addedBeforeProbeInstance // this will only happen _after_ the object lock above is released though Q_ASSERT(!instance()); s_instance = QAtomicPointer(probe); // add objects to the probe that were tracked before its creation foreach (QObject *obj, s_listener()->addedBeforeProbeInstance) { objectAdded(obj); } s_listener()->addedBeforeProbeInstance.clear(); // try to find existing objects by other means if (findExisting) { probe->findExistingObjects(); } } // eventually initialize the rest QMetaObject::invokeMethod(probe, "delayedInit", Qt::QueuedConnection); } void Probe::startupHookReceived() { #ifdef Q_OS_ANDROID QDir root = QDir::home(); root.cdUp(); Paths::setRootPath(root.absolutePath()); #endif s_listener()->trackDestroyed = false; } void Probe::delayedInit() { QCoreApplication::instance()->installEventFilter(this); QString appName = qApp->applicationName(); if (appName.isEmpty() && !qApp->arguments().isEmpty()) { appName = qApp->arguments().first().remove(qApp->applicationDirPath()); if (appName.startsWith('.')) { appName = appName.right(appName.length() - 1); } if (appName.startsWith('/')) { appName = appName.right(appName.length() - 1); } } if (appName.isEmpty()) { appName = tr("PID %1").arg(qApp->applicationPid()); } Server::instance()->setLabel(appName); if (ProbeSettings::value("InProcessUi", false).toBool()) { showInProcessUi(); } } void Probe::showInProcessUi() { if (!canShowWidgets()) { cerr << "Unable to show in-process UI in a non-QWidget based application." << endl; return; } IF_DEBUG(cout << "creating GammaRay::MainWindow" << endl;) ProbeGuard guard; QString path = Paths::currentProbePath(); if (!path.isEmpty()) { path += QDir::separator(); } path += "gammaray_inprocessui"; QLibrary lib; lib.setFileName(path); if (!lib.load()) { std::cerr << "Failed to load in-process UI module: " << qPrintable(lib.errorString()) << std::endl; } else { void(*factory)() = reinterpret_cast(lib.resolve("gammaray_create_inprocess_mainwindow")); if (!factory) { std::cerr << Q_FUNC_INFO << ' ' << qPrintable(lib.errorString()) << endl; } else { factory(); } } IF_DEBUG(cout << "creation done" << endl;) } bool Probe::filterObject(QObject *obj) const { if (obj->thread() != thread()) { // shortcut, never filter objects from a different thread return false; } QSet visitedObjects; int iteration = 0; QObject *o = obj; do { if (iteration > 100) { // Probably we have a loop in the tree. Do loop detection. if (visitedObjects.contains(o)) { std::cerr << "We detected a loop in the object tree for object " << o; if (!o->objectName().isEmpty()) { std::cerr << " \"" << qPrintable(o->objectName()) << "\""; } std::cerr << " (" << o->metaObject()->className() << ")." << std::endl; return true; } visitedObjects << o; } ++iteration; if (o == this || o == window()) return true; o = o->parent(); } while (o); return false; } void Probe::registerModel(const QString &objectName, QAbstractItemModel *model) { RemoteModelServer *ms = new RemoteModelServer(objectName, model); ms->setModel(model); ObjectBroker::registerModelInternal(objectName, model); } QAbstractItemModel *Probe::objectListModel() const { return m_objectListModel; } QAbstractItemModel *Probe::objectTreeModel() const { return m_objectTreeModel; } QAbstractItemModel *Probe::metaObjectModel() const { return m_metaObjectTreeModel; } QAbstractItemModel *Probe::connectionModel() const { return m_connectionModel; } ToolModel *Probe::toolModel() const { return m_toolModel; } QObject *Probe::probe() const { return const_cast(this); } bool Probe::isValidObject(QObject *obj) const { ///TODO: can we somehow assert(s_lock().isLocked()) ?! return m_validObjects.contains(obj); } QMutex *Probe::objectLock() { return s_lock(); } void Probe::objectAdded(QObject *obj, bool fromCtor) { QMutexLocker lock(s_lock()); // attempt to ignore objects created by GammaRay itself, especially short-lived ones if (fromCtor && ProbeGuard::insideProbe() && obj->thread() == QThread::currentThread()) { return; } if (!isInitialized()) { IF_DEBUG(cout << "objectAdded Before: " << hex << obj << (fromCtor ? " (from ctor)" : "") << endl;) s_listener()->addedBeforeProbeInstance << obj; return; } if (instance()->filterObject(obj)) { IF_DEBUG(cout << "objectAdded Filter: " << hex << obj << (fromCtor ? " (from ctor)" : "") << endl;) return; } if (instance()->m_validObjects.contains(obj)) { // this happens when we get a child event before the objectAdded call from the ctor // or when we add an item from addedBeforeProbeInstance who got added already // due to the add-parent-before-child logic IF_DEBUG(cout << "objectAdded Known: " << hex << obj << (fromCtor ? " (from ctor)" : "") << endl;) return; } // make sure we already know the parent if (obj->parent() && !instance()->m_validObjects.contains(obj->parent())) { objectAdded(obj->parent(), fromCtor); } Q_ASSERT(!obj->parent() || instance()->m_validObjects.contains(obj->parent())); instance()->m_validObjects << obj; if (!instance()->hasReliableObjectTracking()) { // when we did not use a preload variant that // overwrites qt_removeObject we must track object // deletion manually connect(obj, SIGNAL(destroyed(QObject*)), instance(), SLOT(handleObjectDestroyed(QObject*)), Qt::DirectConnection); } if (!fromCtor && obj->parent() && instance()->m_queuedObjects.contains(obj->parent())) { // when a child event triggers a call to objectAdded while inside the ctor // the parent is already tracked but it's call to objectFullyConstructed // was delayed. hence we must do the same for the child for integrity fromCtor = true; } IF_DEBUG(cout << "objectAdded: " << hex << obj << (fromCtor ? " (from ctor)" : "") << ", p: " << obj->parent() << endl;) if (fromCtor) { Q_ASSERT(!instance()->m_queuedObjects.contains(obj)); instance()->m_queuedObjects << obj; if (!instance()->m_queueTimer->isActive()) { // timers must not be started from a different thread QMetaObject::invokeMethod(instance()->m_queueTimer, "start", Qt::AutoConnection); } } else { instance()->objectFullyConstructed(obj); } } void Probe::queuedObjectsFullyConstructed() { QMutexLocker lock(s_lock()); IF_DEBUG(cout << Q_FUNC_INFO << " " << m_queuedObjects.size() << endl;) // must be called from the main thread via timeout Q_ASSERT(QThread::currentThread() == thread()); // when this is called no object must be in the queue twice // otherwise the cleanup procedures failed Q_ASSERT(m_queuedObjects.size() == m_queuedObjects.toSet().size()); foreach (QObject *obj, m_queuedObjects) { objectFullyConstructed(obj); } IF_DEBUG(cout << Q_FUNC_INFO << " done" << endl;) m_queuedObjects.clear(); foreach (QObject *obj, m_pendingReparents) { if (!isValidObject(obj)) continue; if (filterObject(obj)) // the move might have put it under a hidden parent objectRemoved(obj); else emit objectReparented(obj); } m_pendingReparents.clear(); } void Probe::objectFullyConstructed(QObject *obj) { if (!m_validObjects.contains(obj)) { // deleted already IF_DEBUG(cout << "stale fully constructed: " << hex << obj << endl;) return; } if (filterObject(obj)) { // when the call was delayed from the ctor construction, // the parent might not have been set properly yet. hence // apply the filter again m_validObjects.remove(obj); IF_DEBUG(cout << "now filtered fully constructed: " << hex << obj << endl;) return; } IF_DEBUG(cout << "fully constructed: " << hex << obj << endl;) // ensure we know all our ancestors already for (QObject *parent = obj->parent(); parent; parent = parent->parent()) { if (!m_validObjects.contains(parent)) { objectAdded(parent); // will also handle any further ancestors break; } } Q_ASSERT(!obj->parent() || m_validObjects.contains(obj->parent())); // QQuickItem has the briliant idea of suppressing child events, so we need an // alternative way of detecting reparenting... // Without linking to the QtQuick library of course, for extra fun. if (obj->inherits("QQuickItem")) { connect(obj, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(objectParentChanged())); } m_metaObjectTreeModel->objectAdded(obj); m_toolModel->objectAdded(obj); emit objectCreated(obj); } void Probe::objectRemoved(QObject *obj) { QMutexLocker lock(s_lock()); if (!isInitialized()) { IF_DEBUG(cout << "objectRemoved Before: " << hex << obj << " have statics: " << s_listener() << endl;) if (!s_listener()) { return; } QVector &addedBefore = s_listener()->addedBeforeProbeInstance; for (QVector::iterator it = addedBefore.begin(); it != addedBefore.end();) { if (*it == obj) { it = addedBefore.erase(it); } else { ++it; } } return; } IF_DEBUG(cout << "object removed:" << hex << obj << " " << obj->parent() << endl;) bool success = instance()->m_validObjects.remove(obj); if (!success) { // object was not tracked by the probe, probably a gammaray object return; } instance()->m_queuedObjects.removeOne(obj); instance()->connectionRemoved(obj, 0, 0, 0); instance()->connectionRemoved(0, 0, obj, 0); emit instance()->objectDestroyed(obj); } void Probe::handleObjectDestroyed(QObject *obj) { objectRemoved(obj); } void Probe::objectParentChanged() { if (sender()) { emit objectReparented(sender()); } } void Probe::connectionAdded(QObject *sender, const char *signal, QObject *receiver, const char *method, Qt::ConnectionType type) { if (!isInitialized() || !sender || !receiver || ProbeGuard::insideProbe()) { return; } QMutexLocker lock(s_lock()); if (instance()->filterObject(sender) || instance()->filterObject(receiver)) { return; } instance()->m_connectionModel->connectionAdded(sender, signal, receiver, method, type); } void Probe::connectionRemoved(QObject *sender, const char *signal, QObject *receiver, const char *method) { if (!isInitialized() || !s_listener() || ProbeGuard::insideProbe()) { return; } QMutexLocker lock(s_lock()); if ((sender && instance()->filterObject(sender)) || (receiver && instance()->filterObject(receiver))) { return; } instance()->m_connectionModel->connectionRemoved(sender, signal, receiver, method); } bool Probe::eventFilter(QObject *receiver, QEvent *event) { if (ProbeGuard::insideProbe() && receiver->thread() == QThread::currentThread()) { return QObject::eventFilter(receiver, event); } if (event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildRemoved) { QChildEvent *childEvent = static_cast(event); QObject *obj = childEvent->child(); QMutexLocker lock(s_lock()); const bool tracked = m_validObjects.contains(obj); const bool filtered = filterObject(obj); IF_DEBUG(cout << "child event: " << hex << obj << ", p: " << obj->parent() << dec << ", tracked: " << tracked << ", filtered: " << filtered << ", type: " << (childEvent->added() ? "added" : "removed") << endl;) if (!filtered && childEvent->added()) { if (!tracked) { // was not tracked before, add to all models // child added events are sent before qt_addObject is called, // so we assumes this comes from the ctor objectAdded(obj, true); } else if (!m_queuedObjects.contains(obj)) { // object is known already, just update the position in the tree // BUT: only when we did not queue this item before IF_DEBUG(cout << "update pos: " << hex << obj << endl;) m_pendingReparents.removeAll(obj); emit objectReparented(obj); } } else if (tracked) { if (hasReliableObjectTracking()) { // defer processing this until we know its final location m_pendingReparents.push_back(obj); if (!m_queueTimer->isActive()) { // timers must not be started from a different thread QMetaObject::invokeMethod(instance()->m_queueTimer, "start", Qt::AutoConnection); } } else { objectRemoved(obj); } } } // widget only unfortunately, but more precise than ChildAdded/Removed... if (event->type() == QEvent::ParentChange) { QMutexLocker lock(s_lock()); const bool tracked = m_validObjects.contains(receiver); const bool filtered = filterObject(receiver); if (!filtered && tracked && !m_queuedObjects.contains(receiver)) { m_pendingReparents.removeAll(receiver); emit objectReparented(receiver); } } // we have no preloading hooks, so recover all objects we see if (!hasReliableObjectTracking() && event->type() != QEvent::ChildAdded && event->type() != QEvent::ChildRemoved && event->type() != QEvent::ParentChange && // already handled above event->type() != QEvent::Destroy && event->type() != QEvent::WinIdChange && // unsafe since emitted from dtors !filterObject(receiver)) { QMutexLocker lock(s_lock()); const bool tracked = m_validObjects.contains(receiver); if (!tracked) { discoverObject(receiver); } } // filters provided by plugins if (!filterObject(receiver)) { foreach (QObject *filter, m_globalEventFilters) { filter->eventFilter(receiver, event); } } return QObject::eventFilter(receiver, event); } void Probe::findExistingObjects() { discoverObject(QCoreApplication::instance()); } void Probe::discoverObject(QObject *obj) { if (!obj) { return; } QMutexLocker lock(s_lock()); if (m_validObjects.contains(obj)) { return; } objectAdded(obj); foreach (QObject *child, obj->children()) { discoverObject(child); } } void Probe::installGlobalEventFilter(QObject *filter) { Q_ASSERT(!m_globalEventFilters.contains(filter)); m_globalEventFilters.push_back(filter); } bool Probe::hasReliableObjectTracking() const { return !s_listener()->trackDestroyed; } void Probe::selectObject(QObject *object, const QPoint &pos) { emit objectSelected(object, pos); const auto srcIdx = m_toolModel->toolForObject(object); const auto idx = qobject_cast(m_toolSelectionModel->model())->mapFromSource(srcIdx); m_toolSelectionModel->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } void Probe::selectObject(void *object, const QString &typeName) { emit nonQObjectSelected(object, typeName); const auto srcIdx = m_toolModel->toolForObject(object, typeName); const auto idx = qobject_cast(m_toolSelectionModel->model())->mapFromSource(srcIdx); m_toolSelectionModel->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } void Probe::registerSignalSpyCallbackSet(const SignalSpyCallbackSet &callbacks) { if (callbacks.isNull()) return; m_signalSpyCallbacks.push_back(callbacks); setupSignalSpyCallbacks(); } void Probe::setupSignalSpyCallbacks() { QSignalSpyCallbackSet cbs = { 0, 0, 0, 0 }; foreach (const auto &it, m_signalSpyCallbacks) { if (it.signalBeginCallback) cbs.signal_begin_callback = signal_begin_callback; if (it.signalEndCallback) cbs.signal_end_callback = signal_end_callback; if (it.slotBeginCallback) cbs.slot_begin_callback = slot_begin_callback; if (it.slotEndCallback) cbs.slot_end_callback = slot_end_callback; } qt_register_signal_spy_callbacks(cbs); } template void Probe::executeSignalCallback(const Func &func) { std::for_each(instance()->m_signalSpyCallbacks.constBegin(), instance()->m_signalSpyCallbacks.constEnd(), func); } //BEGIN: SignalSlotsLocationStore // taken from qobject.cpp const int gammaray_flagged_locations_count = 2; const char *gammaray_flagged_locations[gammaray_flagged_locations_count] = {0}; static int gammaray_idx = 0; void SignalSlotsLocationStore::flagLocation(const char *method) { gammaray_flagged_locations[gammaray_idx] = method; gammaray_idx = (gammaray_idx+1) % gammaray_flagged_locations_count; } const char *SignalSlotsLocationStore::extractLocation(const char *member) { for (int i = 0; i < gammaray_flagged_locations_count; ++i) { if (member == gammaray_flagged_locations[i]) { // signature includes location information after the first null-terminator const char *location = member + qstrlen(member) + 1; if (*location != '\0') { return location; } return 0; } } return 0; } //END gammaray-2.3.0/core/probe.h000066400000000000000000000166301255003167400155330ustar00rootroot00000000000000/* probe.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBE_H #define GAMMARAY_PROBE_H #include "gammaray_core_export.h" #include "probeinterface.h" #include "signalspycallbackset.h" #include #include #include #include class QItemSelectionModel; class QThread; class QPoint; class QTimer; class QMutex; namespace GammaRay { class ProbeCreator; class MetaObjectTreeModel; class ConnectionModel; class ObjectListModel; class ObjectTreeModel; class ToolModel; class MainWindow; class BenchSuite; class GAMMARAY_CORE_EXPORT Probe : public QObject, public ProbeInterface { Q_OBJECT public: ~Probe(); /** * NOTE: You must hold the object lock when operating on the instance! */ static Probe *instance(); /** * Returns true if the probe is initialized, false otherwise. */ static bool isInitialized(); static void objectAdded(QObject *obj, bool fromCtor = false); static void objectRemoved(QObject *obj); static void connectionAdded(QObject *sender, const char *signal, QObject *receiver, const char *method, Qt::ConnectionType type); static void connectionRemoved(QObject *sender, const char *signal, QObject *receiver, const char *method); QAbstractItemModel *objectListModel() const Q_DECL_OVERRIDE; QAbstractItemModel *objectTreeModel() const Q_DECL_OVERRIDE; QAbstractItemModel *metaObjectModel() const; QAbstractItemModel *connectionModel() const Q_DECL_OVERRIDE; ToolModel *toolModel() const; void registerModel(const QString& objectName, QAbstractItemModel* model) Q_DECL_OVERRIDE; void installGlobalEventFilter(QObject* filter) Q_DECL_OVERRIDE; bool hasReliableObjectTracking() const Q_DECL_OVERRIDE; void discoverObject(QObject* object) Q_DECL_OVERRIDE; void selectObject(QObject* object, const QPoint& pos = QPoint()) Q_DECL_OVERRIDE; void selectObject(void* object, const QString& typeName) Q_DECL_OVERRIDE; void registerSignalSpyCallbackSet(const SignalSpyCallbackSet& callbacks) Q_DECL_OVERRIDE; QObject *window() const; void setWindow(QObject *window); QObject *probe() const Q_DECL_OVERRIDE; /** * Lock this to check the validity of a QObject * and to access it safely afterwards. */ static QMutex *objectLock(); /** * check whether @p obj is still valid * * NOTE: the objectLock must be locked when this is called! */ bool isValidObject(QObject *obj) const; bool filterObject(QObject *obj) const Q_DECL_OVERRIDE; /// internal static void startupHookReceived(); template static void executeSignalCallback(const Func &func); signals: /** * Emitted when the user selected @p object at position @p pos in the probed application. */ void objectSelected(QObject *object, const QPoint &pos); void nonQObjectSelected(void *object, const QString &typeName); /** * Emitted for newly created QObjects. * * Note: * - This signal is always emitted from the thread the probe exists in. * - The signal is emitted delayed enough for the QObject to have been fully constructed, * i.e. on the next event loop re-entry. * - The signal is not emitted if the object has been destroyed completely again meanwhile, * e.g. for objects that only existed on the stack. * - For objects created and destroyed in other threads, this signal might be emitted after * its dtor has been entered (in case of short-lived objects), but before it has been finished. * At this point the dtor might have already emitted the destroyed() signal and informed smart * pointers about the destruction. This means you must not rely on any of this for object lifetime * tracking for objects from other threads. Use objectDestroyed() instead. * - Do not put @p obj into a QWeakPointer, even if it's exclusively handled in the same thread as * the Probe instance. Qt4 asserts if target code tries to put @p obj into a QSharedPointer afterwards. * - The objectLock() is locked. */ void objectCreated(QObject *obj); /** * Emitted for destroyed objects. * * Note: * - This signal is emitted from the thread calling the dtor of @p obj, so make sure to use * the correct connection type when connecting to it. * - The signal is emitted from the end of the QObject dtor, dereferencing @p obj is no longer * safe at this point. * - When using a queued connection on this signal (relevant for e.g. models), see isValidObject() * for a way to check if the object has not yet been deleted when accessing it. */ void objectDestroyed(QObject *obj); void objectReparented(QObject *obj); protected: bool eventFilter(QObject *receiver, QEvent *event) Q_DECL_OVERRIDE; private slots: void delayedInit(); void queuedObjectsFullyConstructed(); void handleObjectDestroyed(QObject *obj); void objectParentChanged(); private: friend class ProbeCreator; friend class BenchSuite; void objectFullyConstructed(QObject *obj); void findExistingObjects(); /** Check if we are capable of showing widgets. */ static bool canShowWidgets(); void showInProcessUi(); static void createProbe(bool findExisting); explicit Probe(QObject *parent = 0); static QAtomicPointer s_instance; /** Set up all needed signal spy callbacks. */ void setupSignalSpyCallbacks(); ObjectListModel *m_objectListModel; ObjectTreeModel *m_objectTreeModel; MetaObjectTreeModel *m_metaObjectTreeModel; ConnectionModel *m_connectionModel; ToolModel *m_toolModel; QItemSelectionModel *m_toolSelectionModel; QObject *m_window; QSet m_validObjects; QQueue m_queuedObjects; QList m_pendingReparents; QTimer *m_queueTimer; QVector m_globalEventFilters; QVector m_signalSpyCallbacks; SignalSpyCallbackSet m_previousSignalSpyCallbackSet; }; class GAMMARAY_CORE_EXPORT SignalSlotsLocationStore { public: /// store the location of @p method static void flagLocation(const char *method); /// retrieve the location of @p member static const char *extractLocation(const char *member); }; } #endif // GAMMARAY_PROBE_H gammaray-2.3.0/core/probecontroller.cpp000066400000000000000000000027031255003167400201660ustar00rootroot00000000000000/* probecontroller.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probecontroller.h" #include "probe.h" #include using namespace GammaRay; ProbeController::ProbeController(QObject* parent): QObject(parent) { } void ProbeController::detachProbe() { Probe::instance()->deleteLater(); } void ProbeController::quitHost() { QCoreApplication::instance()->quit(); } gammaray-2.3.0/core/probecontroller.h000066400000000000000000000031131255003167400176270ustar00rootroot00000000000000/* probecontroller.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBECONTROLLER_H #define GAMMARAY_PROBECONTROLLER_H #include namespace GammaRay { class ProbeController : public QObject, public ProbeControllerInterface { Q_OBJECT Q_INTERFACES(GammaRay::ProbeControllerInterface) public: explicit ProbeController(QObject *parent = 0); public slots: void detachProbe() Q_DECL_OVERRIDE; void quitHost() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROBECONTROLLER_H gammaray-2.3.0/core/probeguard.cpp000066400000000000000000000031561255003167400171100ustar00rootroot00000000000000/* probeguard.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probeguard.h" #include static QThreadStorage s_probeGuards; using namespace GammaRay; ProbeGuard::ProbeGuard() : m_previousState(insideProbe()) { setInsideProbe(true); } ProbeGuard::~ProbeGuard() { setInsideProbe(m_previousState); } bool ProbeGuard::insideProbe() { if (!s_probeGuards.hasLocalData()) return false; return s_probeGuards.localData(); } void ProbeGuard::setInsideProbe(bool inside) { s_probeGuards.localData() = inside; } gammaray-2.3.0/core/probeguard.h000066400000000000000000000037221255003167400165540ustar00rootroot00000000000000/* probeguard.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBEGUARD_H #define GAMMARAY_PROBEGUARD_H #include "gammaray_core_export.h" namespace GammaRay { /** Use this inside probe code that might trigger expensive or otherwise problematic side-effects in * GammaRay itself, so the triggered probe part can skip reacting to that action. * * This works per-thread, and is supposed to be used RAII-style. * * Example: Creating a short-lived QObject inside a probe plugin. */ class GAMMARAY_CORE_EXPORT ProbeGuard { public: ProbeGuard(); ~ProbeGuard(); /** Use this inside your probe code to check if you have been called from other probe code. * In that case you might want to skip some operations, */ static bool insideProbe(); private: Q_DISABLE_COPY(ProbeGuard) void setInsideProbe(bool inside); bool m_previousState; }; } #endif // GAMMARAY_PROBEGUARD_H gammaray-2.3.0/core/probeinterface.h000066400000000000000000000123711255003167400174120ustar00rootroot00000000000000/* probeinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares the ProbeInterface abstract base class. @brief Declares the ProbeInterface abstract base class. @author Volker Krause \ */ #ifndef GAMMARAY_PROBEINTERFACE_H #define GAMMARAY_PROBEINTERFACE_H #include class QObject; class QAbstractItemModel; class QString; namespace GammaRay { struct SignalSpyCallbackSet; /** * @brief An abstract interface for accessing the core GammaRay probe. * * The ProbeInterface is an abstract interface that allows one to access * the core GammaRay probe without linking to it. */ class ProbeInterface { public: virtual inline ~ProbeInterface() { } /** * Returns the object list model. * @return a pointer to a QAbstractItemModel instance. */ virtual QAbstractItemModel *objectListModel() const = 0; /** * Returns the object tree model. * @return a pointer to a QAbstractItemModel instance. */ virtual QAbstractItemModel *objectTreeModel() const = 0; /** * Returns the connection model. * @return a pointer to a QAbstractItemModel instance. */ virtual QAbstractItemModel *connectionModel() const = 0; /** * Determines if the specified QObject belongs to the GammaRay Probe or Window. * * These objects should not be tracked or shown to the user, * hence must be explictly filtered. * @param object is a pointer to a QObject instance. * * @return true if the specified QObject belongs to the GammaRay Probe * or Window; false otherwise. */ virtual bool filterObject(QObject *object) const = 0; /** * Returns the probe QObject for connecting signals. * @return a pointer to a QObject instance. */ virtual QObject *probe() const = 0; /** * Register a model for remote usage. * @param objectName unique identifier for the model, typically in reverse domain notation. */ virtual void registerModel(const QString &objectName, QAbstractItemModel* model) = 0; /** * Install a global event filter. * Use this rather than installing the filter manually on QCoreApplication, * this will filter out GammaRay-internal events and objects already for you. */ virtual void installGlobalEventFilter(QObject *filter) = 0; /** * Returns @c true if we have working hooks in QtCore, that is we are notified reliably * about every QObject creation/destruction. * If this is not the case, we try to discover QObjects by walking the hierarchy, starting * from known singletons, and by watching out for unknown receivers of events. * This is far from complete obviously, and plug-ins can help finding more objects, using * specific knowledge about the types they are responsible for. * * Connect to the objectAdded(QObject*) signal on probe(), and call discoverObject(QObject*) * for "your" objects. * * @since 2.0 */ virtual bool hasReliableObjectTracking() const = 0; /** * Notify the probe about QObjects your plug-in can discover by using information about * the types it can handle. * Only use this if hasReliableObjectTracking() returns @c false. * * @see hasReliableObjectTracking() * @since 2.0 */ virtual void discoverObject(QObject *object) = 0; /** * Notify the probe about the user selecting one of "your" objects via in-app interaction. * If you know the exact position the user interacted with, pass that in as @p pos. * * @since 2.0 */ virtual void selectObject(QObject *object, const QPoint &pos = QPoint()) = 0; /** * Notify the probe about the user selecting one of "your" objects. * * @since 2.1 */ virtual void selectObject(void* object, const QString& typeName) = 0; /** * Register a signal spy callback set. * Signal indexes provided as arguments are mapped to method indexes, ie. argument semantics * are the same with Qt4 and Qt5. * * @since 2.2 */ virtual void registerSignalSpyCallbackSet(const SignalSpyCallbackSet &callbacks) = 0; }; } #endif gammaray-2.3.0/core/probesettings.cpp000066400000000000000000000130711255003167400176430ustar00rootroot00000000000000/* probesettings.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "probesettings.h" #include "common/sharedmemorylocker.h" #include "common/message.h" #include "common/paths.h" #include #include #include #include #include #include #include using namespace GammaRay; static QHash s_probeSettings; QVariant ProbeSettings::value(const QString& key, const QVariant& defaultValue) { QByteArray v = s_probeSettings.value(key.toUtf8()); if (v.isEmpty()) v = qgetenv("GAMMARAY_" + key.toLocal8Bit()); if (v.isEmpty()) return defaultValue; switch (defaultValue.type()) { case QVariant::String: return QString::fromUtf8(v); case QVariant::Bool: return v == "true" || v == "1" || v == "TRUE"; case QVariant::Int: return v.toInt(); default: return v; } } void ProbeSettings::receiveSettings() { #ifdef HAVE_SHM QSharedMemory shm(QLatin1String("gammaray-") + QString::number(launcherIdentifier())); if (!shm.attach()) { #if QT_VERSION < 0x040800 qWarning() << "Unable to receive probe settings, cannot attach to shared memory region" << shm.key() << ", error is:" << shm.errorString(); #else qWarning() << "Unable to receive probe settings, cannot attach to shared memory region" << shm.key() << shm.nativeKey() << ", error is:" << shm.errorString(); #endif qWarning() << "Continueing anyway, with default settings."; // see if we got fallback data via environment variables const QString probePath = value("ProbePath").toString(); if (!probePath.isEmpty()) Paths::setRootPath(probePath + QDir::separator() + GAMMARAY_INVERSE_PROBE_DIR); return; } SharedMemoryLocker locker(&shm); QByteArray ba = QByteArray::fromRawData(static_cast(shm.data()), shm.size()); QBuffer buffer(&ba); buffer.open(QIODevice::ReadOnly); while (Message::canReadMessage(&buffer)) { const Message msg = Message::readMessage(&buffer); switch (msg.type()) { case Protocol::ServerVersion: { qint32 version; msg.payload() >> version; if (version != Protocol::version()) { qWarning() << "Unable to receive probe settings, mismatching protocol versions (expected:" << Protocol::version() << "got:" << version << ")"; qWarning() << "Continueing anyway, but this is likely going to fail."; return; } break; } case Protocol::ProbeSettings: { msg.payload() >> s_probeSettings; //qDebug() << Q_FUNC_INFO << s_probeSettings; const QString probePath = value("ProbePath").toString(); if (!probePath.isEmpty()) Paths::setRootPath(probePath + QDir::separator() + GAMMARAY_INVERSE_PROBE_DIR); } default: continue; } } #endif } qint64 ProbeSettings::launcherIdentifier() { bool ok; const qint64 id = qgetenv("GAMMARAY_LAUNCHER_ID").toLongLong(&ok); if (ok && id > 0) return id; return QCoreApplication::applicationPid(); } void ProbeSettings::resetLauncherIdentifier() { // if we were launch by GammaRay, and we later try to re-attach, we need to make sure // to not end up with an outdated launcher id qputenv("GAMMARAY_LAUNCHER_ID", ""); } void ProbeSettings::sendServerAddress(const QUrl& addr) { #ifdef HAVE_SHM QSharedMemory shm(QLatin1String("gammaray-") + QString::number(launcherIdentifier())); if (!shm.attach()) { #if QT_VERSION < 0x040800 qWarning() << "Unable to receive probe settings, cannot attach to shared memory region" << shm.key() << ", error is:" << shm.errorString(); #else qWarning() << "Unable to receive probe settings, cannot attach to shared memory region" << shm.key() << shm.nativeKey() << ", error is:" << shm.errorString(); #endif qWarning() << "Continueing anyway, with default settings."; return; } QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); { Message msg(Protocol::LauncherAddress, Protocol::ServerAddress); msg.payload() << addr; msg.write(&buffer); } buffer.close(); if(shm.size() < ba.size()) qFatal("SHM region too small!"); { SharedMemoryLocker locker(&shm); qMemCopy(shm.data(), ba.constData(), ba.size()); qMemSet(static_cast(shm.data()) + ba.size(), 0xff, shm.size() - ba.size()); } QSystemSemaphore sem("gammaray-semaphore-" + QString::number(launcherIdentifier()), QSystemSemaphore::Open); sem.release(); #else Q_UNUSED(addr); #endif } gammaray-2.3.0/core/probesettings.h000066400000000000000000000037371255003167400173200ustar00rootroot00000000000000/* probesettings.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBESETTINGS_H #define GAMMARAY_PROBESETTINGS_H #include "gammaray_core_export.h" #include class QUrl; namespace GammaRay { /** General purpose settings of the probe provided by the launcher. */ namespace ProbeSettings { GAMMARAY_CORE_EXPORT QVariant value(const QString &key, const QVariant &defaultValue = QString()); /** Call if using runtime attaching to obtain settings provided via shared memory. */ void receiveSettings(); /** Identifier used for finding the communication channels to the launcher. */ qint64 launcherIdentifier(); /** Reset the launcher Identifier. Call this when detaching the probe. */ void resetLauncherIdentifier(); /** Sends the server address used for communication with the client back to the launcher. */ void sendServerAddress(const QUrl &addr); } } #endif // GAMMARAY_PROBESETTINGS_H gammaray-2.3.0/core/propertycontroller.cpp000066400000000000000000000070521255003167400207450ustar00rootroot00000000000000/* propertycontroller.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertycontroller.h" #include "probe.h" #include using namespace GammaRay; QVector PropertyController::s_extensionFactories = QVector(); QVector PropertyController::s_instances = QVector(); PropertyController::PropertyController(const QString &baseName, QObject *parent) : PropertyControllerInterface(baseName + ".controller", parent), m_objectBaseName(baseName) { s_instances << this; foreach (PropertyControllerExtensionFactoryBase *factory, s_extensionFactories) { m_extensions << factory->create(this); } } PropertyController::~PropertyController() { const auto i = s_instances.indexOf(this); if (i >= 0) s_instances.remove(i); } void PropertyController::loadExtension(PropertyControllerExtensionFactoryBase* factory) { m_extensions << factory->create(this); } const QString &PropertyController::objectBaseName() { return m_objectBaseName; } void PropertyController::registerModel(QAbstractItemModel *model, const QString &nameSuffix) { Probe::instance()->registerModel(m_objectBaseName + '.' + nameSuffix, model); } void PropertyController::setObject(QObject *object) { if (m_object) disconnect(m_object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed())); if (object) connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed())); m_object = object; QStringList availableExtensions; foreach (PropertyControllerExtension *extension, m_extensions) { if (extension->setQObject(object)) availableExtensions << extension->name(); } setAvailableExtensions(availableExtensions); } void PropertyController::setObject(void *object, const QString &className) { setObject(0); QStringList availableExtensions; foreach (PropertyControllerExtension *extension, m_extensions) { if (extension->setObject(object, className)) availableExtensions << extension->name(); } setAvailableExtensions(availableExtensions); } void PropertyController::setMetaObject(const QMetaObject *metaObject) { setObject(0); QStringList availableExtensions; foreach (PropertyControllerExtension *extension, m_extensions) { if (extension->setMetaObject(metaObject)) availableExtensions << extension->name(); } setAvailableExtensions(availableExtensions); } void PropertyController::objectDestroyed() { setObject(0); } gammaray-2.3.0/core/propertycontroller.h000066400000000000000000000054171255003167400204150ustar00rootroot00000000000000/* propertycontroller.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYCONTROLLER_H #define GAMMARAY_PROPERTYCONTROLLER_H #include "gammaray_core_export.h" #include "propertycontrollerextension.h" #include #include #include class QAbstractItemModel; namespace GammaRay { class ConnectionFilterProxyModel; /** @brief Non-UI part of the property widget. */ class GAMMARAY_CORE_EXPORT PropertyController : public PropertyControllerInterface { Q_OBJECT Q_INTERFACES(GammaRay::PropertyControllerInterface) public: explicit PropertyController(const QString &baseName, QObject *parent); ~PropertyController(); const QString &objectBaseName(); void setObject(QObject *object); void setObject(void *object, const QString &className); void setMetaObject(const QMetaObject *metaObject); void registerModel(QAbstractItemModel *model, const QString &nameSuffix); template static void registerExtension() { PropertyControllerExtensionFactoryBase *factory = PropertyControllerExtensionFactory::instance(); if (s_extensionFactories.indexOf(factory) >= 0) return; s_extensionFactories << factory; foreach (PropertyController *instance, s_instances) instance->loadExtension(factory); } private slots: void objectDestroyed(); private: void loadExtension(PropertyControllerExtensionFactoryBase *factory); private: QString m_objectBaseName; QPointer m_object; QVector m_extensions; static QVector s_extensionFactories; static QVector s_instances; }; } #endif // GAMMARAY_PROPERTYCONTROLLER_H gammaray-2.3.0/core/propertycontrollerextension.cpp000066400000000000000000000034551255003167400227050ustar00rootroot00000000000000/* propertycontrollerextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertycontrollerextension.h" using namespace GammaRay; PropertyControllerExtension::PropertyControllerExtension(const QString& name) : m_name(name) { } PropertyControllerExtension::~PropertyControllerExtension() { } QString PropertyControllerExtension::name() const { return m_name; } bool PropertyControllerExtension::setObject(void* object, const QString& typeName) { Q_UNUSED(object); Q_UNUSED(typeName); return false; } bool PropertyControllerExtension::setQObject(QObject* object) { Q_UNUSED(object); return false; } bool PropertyControllerExtension::setMetaObject(const QMetaObject* metaObject) { Q_UNUSED(metaObject); return false; } gammaray-2.3.0/core/propertycontrollerextension.h000066400000000000000000000076071255003167400223550ustar00rootroot00000000000000/* propertycontrollerextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PROPERTYCONTROLLEREXTENSION_H #define PROPERTYCONTROLLEREXTENSION_H #include "gammaray_core_export.h" #include class QObject; struct QMetaObject; namespace GammaRay { class PropertyController; /** * @brief Base-class for server-side property editor extensions. * * This can be used to add your own tabs to the property widget. * Re-implement the corresponding variant of setObject/setMetaObject * you can handle, the default implementations do nothing and return * @c false. * * @since 2.1 */ class GAMMARAY_CORE_EXPORT PropertyControllerExtension { public: /** @brief Create a new property extension. * @param name The extension identifier used for client/server communication. */ explicit PropertyControllerExtension(const QString &name); virtual ~PropertyControllerExtension(); /** @brief Sets the object that should be represented by this extension. * This variant is used for non-QObject types using Gammaray::MetaObjectRepository. * @return @c true if the extension can handle @p object, @c false otherwise. */ virtual bool setObject(void *object, const QString &typeName); /** @brief Sets the QObject that should be represented by this extension. * This variant is used for QObject-derived types. * @return @c true if the extension can handle @p object, @c false otherwise. */ virtual bool setQObject(QObject *object); /** @brief Sets the meta object that should be represented by this extension. * This variant is used for QMetaObjects without a specific object instance. * @return @c true if the extension can handle @p object, @c false otherwise. */ virtual bool setMetaObject(const QMetaObject *metaObject); /** @brief Returns the identifier of this extension, used for client/server communication. */ QString name() const; private: QString m_name; }; ///@cond internal class PropertyControllerExtensionFactoryBase { public: explicit PropertyControllerExtensionFactoryBase() {} virtual PropertyControllerExtension *create(PropertyController *controller) = 0; }; template class PropertyControllerExtensionFactory : public PropertyControllerExtensionFactoryBase { public: static PropertyControllerExtensionFactoryBase* instance() { if (!s_instance) s_instance = new PropertyControllerExtensionFactory(); return s_instance; } PropertyControllerExtension *create(PropertyController *controller) { return new T(controller); } private: explicit PropertyControllerExtensionFactory() {} static PropertyControllerExtensionFactory* s_instance; }; template PropertyControllerExtensionFactory* PropertyControllerExtensionFactory::s_instance = 0; ///@endcond } #endif // PROPERTYCONTROLLEREXTENSION_H gammaray-2.3.0/core/proxydetacher.cpp000066400000000000000000000037141255003167400176370ustar00rootroot00000000000000/* proxydetacher.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "proxydetacher.h" #include #include #include #include using namespace GammaRay; ProxyDetacher::ProxyDetacher(QWidget *widget, QAbstractProxyModel *proxyModel, QAbstractItemModel *sourceModel) : QObject(widget), m_widget(widget), m_proxy(proxyModel), m_source(sourceModel) { widget->installEventFilter(this); } bool ProxyDetacher::eventFilter(QObject *obj, QEvent *e) { Q_ASSERT(obj == m_widget); if (dynamic_cast(e)) { Q_ASSERT(m_proxy->sourceModel() == m_source || !m_proxy->sourceModel()); m_proxy->setSourceModel(0); } else if (dynamic_cast(e)) { Q_ASSERT(!m_proxy->sourceModel()); m_proxy->setSourceModel(m_source); } return QObject::eventFilter(obj, e); } gammaray-2.3.0/core/proxydetacher.h000066400000000000000000000035321255003167400173020ustar00rootroot00000000000000/* proxydetacher.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROXYDETACHER_H #define GAMMARAY_PROXYDETACHER_H #include class QWidget; class QAbstractItemModel; class QAbstractProxyModel; namespace GammaRay { /** * Optimization Helper * * Detaches source model of proxy when widget gets hidden. * Re-attaches source model when widget gets shown again. */ class ProxyDetacher : public QObject { Q_OBJECT public: explicit ProxyDetacher(QWidget *widget, QAbstractProxyModel *proxyModel, QAbstractItemModel *sourceModel); virtual bool eventFilter(QObject *obj, QEvent *e); private: QWidget *m_widget; QAbstractProxyModel *m_proxy; QAbstractItemModel *m_source; }; } #endif // PROXYDETACHER_H gammaray-2.3.0/core/proxytoolfactory.cpp000066400000000000000000000036021255003167400204210ustar00rootroot00000000000000/* proxytoolfactory.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "proxytoolfactory.h" using namespace GammaRay; using namespace std; ProxyToolFactory::ProxyToolFactory(const PluginInfo &pluginInfo, QObject *parent) : ProxyFactory(pluginInfo, parent) { } bool ProxyToolFactory::isValid() const { return pluginInfo().isValid() && !name().isEmpty() && !supportedTypes().isEmpty(); } QString ProxyToolFactory::name() const { return pluginInfo().name(); } QStringList ProxyToolFactory::supportedTypes() const { return pluginInfo().supportedTypes(); } void ProxyToolFactory::init(ProbeInterface *probe) { loadPlugin(); ToolFactory *fac = factory(); if (!fac) { return; } Q_ASSERT(fac); fac->init(probe); } bool ProxyToolFactory::isHidden() const { return pluginInfo().isHidden(); } gammaray-2.3.0/core/proxytoolfactory.h000066400000000000000000000040451255003167400200700ustar00rootroot00000000000000/* proxytoolfactory.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROXYTOOLFACTORY_H #define GAMMARAY_PROXYTOOLFACTORY_H #include #include "toolfactory.h" namespace GammaRay { /** * A wrapper around a plugin ToolFactory that only loads the actual plugin * once initialized. * Until then, meta-data is provided based on a plugin spec file. * * TODO: Improve error reporting */ class ProxyToolFactory : public ProxyFactory { public: /** * @param path Path to the plugin spec file */ explicit ProxyToolFactory(const PluginInfo &pluginInfo, QObject *parent = 0); /** Returns @c true if the plugin seems valid from all the information we have so far. */ bool isValid() const; QString name() const Q_DECL_OVERRIDE; QStringList supportedTypes() const Q_DECL_OVERRIDE; bool isHidden() const Q_DECL_OVERRIDE; void init(ProbeInterface *probe) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROXYTOOLFACTORY_H gammaray-2.3.0/core/remote/000077500000000000000000000000001255003167400155405ustar00rootroot00000000000000gammaray-2.3.0/core/remote/localserverdevice.cpp000066400000000000000000000034071255003167400217510ustar00rootroot00000000000000/* localserverdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localserverdevice.h" #include #include using namespace GammaRay; LocalServerDevice::LocalServerDevice(QObject* parent): ServerDeviceImpl(parent) { m_server = new QLocalServer(this); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_server->setSocketOptions(QLocalServer::WorldAccessOption); #endif connect(m_server, SIGNAL(newConnection()), this, SIGNAL(newConnection())); } bool LocalServerDevice::listen() { QLocalServer::removeServer(m_address.path()); return m_server->listen(m_address.path()); } QUrl LocalServerDevice::externalAddress() const { return m_address; } gammaray-2.3.0/core/remote/localserverdevice.h000066400000000000000000000030631255003167400214140ustar00rootroot00000000000000/* localserverdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALSERVERDEVICE_H #define GAMMARAY_LOCALSERVERDEVICE_H #include "serverdevice.h" #include #include namespace GammaRay { class LocalServerDevice : public ServerDeviceImpl { Q_OBJECT public: explicit LocalServerDevice(QObject* parent = 0); bool listen() Q_DECL_OVERRIDE; QUrl externalAddress() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_LOCALSERVERDEVICE_H gammaray-2.3.0/core/remote/remotemodelserver.cpp000066400000000000000000000330441255003167400220130ustar00rootroot00000000000000/* remotemodelserver.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "remotemodelserver.h" #include "server.h" #include #include #include #include #include #include #include #include #include using namespace GammaRay; using namespace std; void (*RemoteModelServer::s_registerServerCallback)() = 0; RemoteModelServer::RemoteModelServer(const QString &objectName, QObject *parent) : QObject(parent), m_model(0), m_dummyBuffer(new QBuffer(&m_dummyData, this)), m_monitored(false) { setObjectName(objectName); m_dummyBuffer->open(QIODevice::WriteOnly); registerServer(); } RemoteModelServer::~RemoteModelServer() { } QAbstractItemModel* RemoteModelServer::model() const { return m_model; } void RemoteModelServer::setModel(QAbstractItemModel *model) { if (model == m_model) return; if (m_model) disconnectModel(); m_model = model; if (m_model && m_monitored) connectModel(); if (m_monitored) modelReset(); } void RemoteModelServer::connectModel() { Q_ASSERT(m_model); connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(dataChanged(QModelIndex,QModelIndex))); connect(m_model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), SLOT(headerDataChanged(Qt::Orientation,int,int))); connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); connect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(rowsRemoved(QModelIndex,int,int))); connect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), SLOT(columnsInserted(QModelIndex,int,int))); connect(m_model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(columnsMoved(QModelIndex,int,int,QModelIndex,int))); connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), SLOT(columnsRemoved(QModelIndex,int,int))); connect(m_model, SIGNAL(layoutChanged()), SLOT(layoutChanged())); connect(m_model, SIGNAL(modelReset()), SLOT(modelReset())); connect(m_model, SIGNAL(destroyed(QObject*)), SLOT(modelDeleted())); } void RemoteModelServer::disconnectModel() { Q_ASSERT(m_model); disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex))); disconnect(m_model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(headerDataChanged(Qt::Orientation,int,int))); disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(columnsInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(columnsMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(columnsRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); disconnect(m_model, SIGNAL(modelReset()), this, SLOT(modelReset())); disconnect(m_model, SIGNAL(destroyed(QObject*)), this, SLOT(modelDeleted())); } void RemoteModelServer::newRequest(const GammaRay::Message &msg) { if (!m_model && msg.type() != Protocol::ModelSyncBarrier) return; ProbeGuard g; switch (msg.type()) { case Protocol::ModelRowColumnCountRequest: { Protocol::ModelIndex index; msg.payload() >> index; const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index); Message msg(m_myAddress, Protocol::ModelRowColumnCountReply); msg.payload() << index << m_model->rowCount(qmIndex) << m_model->columnCount(qmIndex); sendMessage(msg); break; } case Protocol::ModelContentRequest: { quint32 size; msg.payload() >> size; Q_ASSERT(size > 0); QVector indexes; indexes.reserve(size); for (quint32 i = 0; i < size; ++i) { Protocol::ModelIndex index; msg.payload() >> index; const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index); if (!qmIndex.isValid()) continue; indexes.push_back(qmIndex); } if (indexes.isEmpty()) break; Message msg(m_myAddress, Protocol::ModelContentReply); msg.payload() << quint32(indexes.size()); foreach (const auto &qmIndex, indexes) { msg.payload() << Protocol::fromQModelIndex(qmIndex) << filterItemData(m_model->itemData(qmIndex)) << qint32(m_model->flags(qmIndex)); } sendMessage(msg); break; } case Protocol::ModelHeaderRequest: { qint8 orientation; qint32 section; msg.payload() >> orientation >> section; Q_ASSERT(orientation == Qt::Horizontal || orientation == Qt::Vertical); Q_ASSERT(section >= 0); QHash data; // TODO: add all roles data.insert(Qt::DisplayRole, m_model->headerData(section, static_cast(orientation), Qt::DisplayRole)); data.insert(Qt::ToolTipRole, m_model->headerData(section, static_cast(orientation), Qt::ToolTipRole)); Message msg(m_myAddress, Protocol::ModelHeaderReply); msg.payload() << orientation << section << data; sendMessage(msg); break; } case Protocol::ModelSetDataRequest: { Protocol::ModelIndex index; int role; QVariant value; msg.payload() >> index >> role >> value; m_model->setData(Protocol::toQModelIndex(m_model, index), value, role); break; } case Protocol::ModelSyncBarrier: { qint32 barrierId; msg.payload() >> barrierId; Message reply(m_myAddress, Protocol::ModelSyncBarrier); reply.payload() << barrierId; sendMessage(reply); break; } } } QMap RemoteModelServer::filterItemData(const QMap< int, QVariant >& data) const { QMap itemData(data); for (QMap::iterator it = itemData.begin(); it != itemData.end();) { if (!it.value().isValid()) { it = itemData.erase(it); } else if (it.value().userType() == qMetaTypeId()) { // see also: https://bugreports.qt-project.org/browse/QTBUG-33321 const QIcon icon = it.value().value(); ///TODO: what size to use? icon.availableSizes is empty... if (!icon.isNull()) it.value() = icon.pixmap(QSize(16, 16)); ++it; } else if (qstrcmp(it.value().typeName(), "QJSValue") == 0) { // QJSValue tries to serialize nested elements and asserts if that fails // too bad it can contain QObject* as nested element, which obviously can't be serialized... it = itemData.erase(it); } else if (canSerialize(it.value())) { ++it; } else { // qWarning() << "Cannot serialize QVariant of type" << it.value().typeName(); it = itemData.erase(it); } } return itemData; } bool RemoteModelServer::canSerialize(const QVariant& value) const { // recurse into containers #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (value.canConvert()) { QSequentialIterable it = value.value(); foreach (const QVariant &v, it) { if (!canSerialize(v)) return false; } } #endif // ugly, but there doesn't seem to be a better way atm to find out without trying m_dummyBuffer->seek(0); QDataStream stream(m_dummyBuffer); return QMetaType::save(stream, value.userType(), value.constData()); } void RemoteModelServer::modelMonitored(bool monitored) { if (m_monitored == monitored) return; m_monitored = monitored; if (m_model) { if (m_monitored) connectModel(); else disconnectModel(); } } void RemoteModelServer::dataChanged(const QModelIndex& begin, const QModelIndex& end) { // TODO check if somebody is listening (here or in Server?) if (!isConnected()) return; Message msg(m_myAddress, Protocol::ModelContentChanged); msg.payload() << Protocol::fromQModelIndex(begin) << Protocol::fromQModelIndex(end); sendMessage(msg); } void RemoteModelServer::headerDataChanged(Qt::Orientation orientation, int first, int last) { if (!isConnected()) return; Message msg(m_myAddress, Protocol::ModelHeaderChanged); msg.payload() << qint8(orientation) << first << last; sendMessage(msg); } void RemoteModelServer::rowsInserted(const QModelIndex& parent, int start, int end) { sendAddRemoveMessage(Protocol::ModelRowsAdded, parent, start, end); } void RemoteModelServer::rowsAboutToBeMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow) { Q_UNUSED(sourceStart); Q_UNUSED(sourceEnd); Q_UNUSED(destinationRow); m_preOpIndexes.push_back(Protocol::fromQModelIndex(sourceParent)); m_preOpIndexes.push_back(Protocol::fromQModelIndex(destinationParent)); } void RemoteModelServer::rowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow) { Q_UNUSED(sourceParent); Q_UNUSED(destinationParent); Q_ASSERT(m_preOpIndexes.size() >= 2); const auto destParentIdx = m_preOpIndexes.takeLast(); const auto sourceParentIdx = m_preOpIndexes.takeLast(); sendMoveMessage(Protocol::ModelRowsMoved, sourceParentIdx, sourceStart, sourceEnd, destParentIdx, destinationRow); } void RemoteModelServer::rowsRemoved(const QModelIndex& parent, int start, int end) { sendAddRemoveMessage(Protocol::ModelRowsRemoved, parent, start, end); } void RemoteModelServer::columnsInserted(const QModelIndex& parent, int start, int end) { sendAddRemoveMessage(Protocol::ModelColumnsAdded, parent, start, end); } void RemoteModelServer::columnsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationColumn) { sendMoveMessage(Protocol::ModelColumnsMoved, Protocol::fromQModelIndex(sourceParent), sourceStart, sourceEnd, Protocol::fromQModelIndex(destinationParent), destinationColumn); } void RemoteModelServer::columnsRemoved(const QModelIndex& parent, int start, int end) { sendAddRemoveMessage(Protocol::ModelColumnsRemoved, parent, start, end); } void RemoteModelServer::layoutChanged() { if (!isConnected()) return; sendMessage(Message(m_myAddress, Protocol::ModelLayoutChanged)); } void RemoteModelServer::modelReset() { if (!isConnected()) return; sendMessage(Message(m_myAddress, Protocol::ModelReset)); } void RemoteModelServer::sendAddRemoveMessage(Protocol::MessageType type, const QModelIndex& parent, int start, int end) { if (!isConnected()) return; Message msg(m_myAddress, type); msg.payload() << Protocol::fromQModelIndex(parent) << start << end; sendMessage(msg); } void RemoteModelServer::sendMoveMessage(Protocol::MessageType type, const Protocol::ModelIndex& sourceParent, int sourceStart, int sourceEnd, const Protocol::ModelIndex& destinationParent, int destinationIndex) { if (!isConnected()) return; Message msg(m_myAddress, type); msg.payload() << sourceParent << qint32(sourceStart) << qint32(sourceEnd) << destinationParent << qint32(destinationIndex); sendMessage(msg); } void RemoteModelServer::modelDeleted() { m_model = 0; if (m_monitored) modelReset(); } void RemoteModelServer::registerServer() { if (Q_UNLIKELY(s_registerServerCallback)) { // called from the ctor, so we can't rely on virtuals s_registerServerCallback(); return; } m_myAddress = Server::instance()->registerObject(objectName(), this, "newRequest"); Server::instance()->registerMonitorNotifier(m_myAddress, this, "modelMonitored"); connect(Endpoint::instance(), SIGNAL(disconnected()), this, SLOT(modelMonitored())); } bool RemoteModelServer::isConnected() const { return Endpoint::isConnected(); } void RemoteModelServer::sendMessage(const Message& msg) const { Endpoint::send(msg); } gammaray-2.3.0/core/remote/remotemodelserver.h000066400000000000000000000107611255003167400214610ustar00rootroot00000000000000/* remotemodelserver.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_REMOTEMODELSERVER_H #define GAMMARAY_REMOTEMODELSERVER_H #include #include #include class QBuffer; class QAbstractItemModel; namespace GammaRay { class Message; /** Provides the server-side interface for a QAbstractItemModel to be used from a separate process. */ class RemoteModelServer : public QObject { Q_OBJECT public: /** Registers a new model server object with name @p objectName (must be unique). */ explicit RemoteModelServer(const QString &objectName, QObject *parent = 0); ~RemoteModelServer(); /** Returns the source model. */ QAbstractItemModel* model() const; /** Set the source model for this model server instance. */ void setModel(QAbstractItemModel *model); public slots: void newRequest(const GammaRay::Message &msg); /** Notifications about an object on the client side (un)monitoring this object. * If no one is watching, we don't send out any change notification to reduce network traffice. */ void modelMonitored(bool monitored = false); private: void connectModel(); void disconnectModel(); void sendAddRemoveMessage(Protocol::MessageType type, const QModelIndex &parent, int start, int end); void sendMoveMessage(Protocol::MessageType type, const Protocol::ModelIndex &sourceParent, int sourceStart, int sourceEnd, const Protocol::ModelIndex &destinationParent, int destinationIndex); QMap< int, QVariant > filterItemData(const QMap< int, QVariant >& data) const; bool canSerialize(const QVariant &value) const; // unit test hooks static void (*s_registerServerCallback)(); void registerServer(); virtual bool isConnected() const; virtual void sendMessage(const Message &msg) const; friend class FakeRemoteModelServer; private slots: void dataChanged(const QModelIndex &begin, const QModelIndex &end); void headerDataChanged(Qt::Orientation orientation, int first, int last); void rowsInserted(const QModelIndex &parent, int start, int end); void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow); void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow); void rowsRemoved(const QModelIndex &parent, int start, int end); void columnsInserted(const QModelIndex &parent, int start, int end); void columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn); void columnsRemoved(const QModelIndex &parent, int start, int end); void layoutChanged(); void modelReset(); void modelDeleted(); private: QPointer m_model; // those two are used for canSerialize, since recreating the QBuffer is somewhat expensive, // especially since being a QObject triggers all kind of GammaRay internals QByteArray m_dummyData; QBuffer *m_dummyBuffer; // converted model indexes from aboutToBeX signals, needed in cases where the operation changes // the serialized index (move to sub-tree of source parent for example) // as operations can occur nested, we need to have a stack for this QList m_preOpIndexes; Protocol::ObjectAddress m_myAddress; bool m_monitored; }; } #endif gammaray-2.3.0/core/remote/selectionmodelserver.cpp000066400000000000000000000030001255003167400224720ustar00rootroot00000000000000/* selectionmodelserver.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "selectionmodelserver.h" #include "server.h" using namespace GammaRay; SelectionModelServer::SelectionModelServer(const QString& objectName, QAbstractItemModel* model, QObject* parent): NetworkSelectionModel(objectName, model, parent) { m_myAddress = Server::instance()->registerObject(objectName, this, "newMessage"); } SelectionModelServer::~SelectionModelServer() { } gammaray-2.3.0/core/remote/selectionmodelserver.h000066400000000000000000000031231255003167400221450ustar00rootroot00000000000000/* selectionmodelserver.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SELECTIONMODELSERVER_H #define GAMMARAY_SELECTIONMODELSERVER_H #include namespace GammaRay { /** Server-side of the network transparent QItemSelection model. */ class SelectionModelServer : public NetworkSelectionModel { Q_OBJECT public: explicit SelectionModelServer(const QString& objectName, QAbstractItemModel* model, QObject* parent); ~SelectionModelServer(); }; } #endif // GAMMARAY_SELECTIONMODELSERVER_H gammaray-2.3.0/core/remote/server.cpp000066400000000000000000000213011255003167400175470ustar00rootroot00000000000000/* server.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "server.h" #include "serverdevice.h" #include "probe.h" #include "probesettings.h" #include "multisignalmapper.h" #include #include #include #ifdef Q_OS_ANDROID # include #endif #include #include #include #include using namespace GammaRay; using namespace std; Server::Server(QObject *parent) : Endpoint(parent), m_serverDevice(0), m_nextAddress(endpointAddress()), m_broadcastTimer(new QTimer(this)), m_signalMapper(new MultiSignalMapper(this)) { if (!ProbeSettings::value("RemoteAccessEnabled", true).toBool()) return; m_serverDevice = ServerDevice::create(serverAddress(), this); if (!m_serverDevice) return; connect(m_serverDevice, SIGNAL(newConnection()), this, SLOT(newConnection())); if (!m_serverDevice->listen()) { qWarning() << "Failed to start server:" << m_serverDevice->errorString(); return; } m_broadcastTimer->setInterval(5 * 1000); m_broadcastTimer->setSingleShot(false); #ifndef Q_OS_ANDROID m_broadcastTimer->start(); #endif connect(m_broadcastTimer, SIGNAL(timeout()), SLOT(broadcast())); connect(this, SIGNAL(disconnected()), m_broadcastTimer, SLOT(start())); connect(m_signalMapper, SIGNAL(signalEmitted(QObject*,int,QVector)), this, SLOT(forwardSignal(QObject*,int,QVector))); Endpoint::registerObjectInternal("com.kdab.GammaRay.PropertySyncer", ++m_nextAddress); m_propertySyncer->setAddress(m_nextAddress); Endpoint::registerObject("com.kdab.GammaRay.PropertySyncer", m_propertySyncer); registerMessageHandlerInternal(m_nextAddress, m_propertySyncer, "handleMessage"); } Server::~Server() { } Server* Server::instance() { Q_ASSERT(s_instance); return static_cast(s_instance); } bool Server::isRemoteClient() const { return false; } QUrl Server::serverAddress() const { #ifdef Q_OS_ANDROID QUrl url(QString(QLatin1String("local://%1/+gammaray_socket")).arg(QDir::homePath())); #else QUrl url(ProbeSettings::value("ServerAddress", QLatin1String("tcp://0.0.0.0/")).toString().toUtf8().constData()); if (url.scheme().isEmpty()) url.setScheme("tcp"); if (url.port() <= 0) url.setPort(defaultPort()); #endif return url; } void Server::newConnection() { if (isConnected()) { cerr << Q_FUNC_INFO << " connected already, refusing incoming connection." << endl; m_serverDevice->nextPendingConnection()->close(); return; } m_broadcastTimer->stop(); setDevice(m_serverDevice->nextPendingConnection()); sendServerGreeting(); } void Server::sendServerGreeting() { // send greeting message for protocol version check { Message msg(endpointAddress(), Protocol::ServerVersion); msg.payload() << Protocol::version(); send(msg); } { Message msg(endpointAddress(), Protocol::ServerInfo); msg.payload() << label(); // TODO: expand with anything else needed here: Qt/GammaRay version, hostname, that kind of stuff send(msg); } { Message msg(endpointAddress(), Protocol::ObjectMapReply); msg.payload() << objectAddresses(); send(msg); } } void Server::messageReceived(const Message& msg) { if (msg.address() == endpointAddress()) { switch (msg.type()) { case Protocol::ObjectMonitored: case Protocol::ObjectUnmonitored: { Protocol::ObjectAddress addr; msg.payload() >> addr; Q_ASSERT(addr > Protocol::InvalidObjectAddress); m_propertySyncer->setObjectEnabled(addr, msg.type() == Protocol::ObjectMonitored); const QHash >::const_iterator it = m_monitorNotifiers.constFind(addr); if (it == m_monitorNotifiers.constEnd()) break; //cout << Q_FUNC_INFO << " un/monitor " << (int)addr << endl; QMetaObject::invokeMethod(it.value().first, it.value().second, Q_ARG(bool, msg.type() == Protocol::ObjectMonitored)); break; } } } else { dispatchMessage(msg); } } void Server::invokeObject(const QString &objectName, const char *method, const QVariantList &args) const { Endpoint::invokeObject(objectName, method, args); QObject* object = ObjectBroker::objectInternal(objectName); Q_ASSERT(object); // also invoke locally for in-process mode invokeObjectLocal(object, method, args); } Protocol::ObjectAddress Server::registerObject(const QString &name, QObject *object) { registerObjectInternal(name, ++m_nextAddress); Protocol::ObjectAddress address = Endpoint::registerObject(name, object); Q_ASSERT(m_nextAddress); if (isConnected()) { Message msg(endpointAddress(), Protocol::ObjectAdded); msg.payload() << name << m_nextAddress; send(msg); } const QMetaObject *meta = object->metaObject(); for(int i = 0; i < meta->methodCount(); ++i) { const QMetaMethod method = meta->method(i); if (method.methodType() == QMetaMethod::Signal) { m_signalMapper->connectToSignal(object, method); } } m_propertySyncer->addObject(address, object); return address; } void Server::forwardSignal(QObject* sender, int signalIndex, const QVector< QVariant >& args) { if (!isConnected()) return; Q_ASSERT(sender); Q_ASSERT(signalIndex >= 0); const QMetaMethod signal = sender->metaObject()->method(signalIndex); Q_ASSERT(signal.methodType() == QMetaMethod::Signal); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QByteArray name = signal.signature(); #else QByteArray name = signal.methodSignature(); #endif // get the name of the function to invoke, excluding the parens and function arguments. name = name.mid(0, name.indexOf('(')); QVariantList v; v.reserve(args.size()); foreach(const QVariant &arg, args) v.push_back(arg); Endpoint::invokeObject(sender->objectName(), name, v); } Protocol::ObjectAddress Server::registerObject(const QString& objectName, QObject* receiver, const char* messageHandlerName) { registerObjectInternal(objectName, ++m_nextAddress); Q_ASSERT(m_nextAddress); registerMessageHandlerInternal(m_nextAddress, receiver, messageHandlerName); if (isConnected()) { Message msg(endpointAddress(), Protocol::ObjectAdded); msg.payload() << objectName << m_nextAddress; send(msg); } return m_nextAddress; } void Server::registerMonitorNotifier(Protocol::ObjectAddress address, QObject* receiver, const char* monitorNotifier) { Q_ASSERT(address != Protocol::InvalidObjectAddress); Q_ASSERT(receiver); Q_ASSERT(monitorNotifier); m_monitorNotifiers.insert(address, qMakePair(receiver, monitorNotifier)); } void Server::handlerDestroyed(Protocol::ObjectAddress objectAddress, const QString& objectName) { unregisterObjectInternal(objectName); m_monitorNotifiers.remove(objectAddress); if (isConnected()) { Message msg(endpointAddress(), Protocol::ObjectRemoved); msg.payload() << objectName; send(msg); } } void Server::objectDestroyed(Protocol::ObjectAddress /*objectAddress*/, const QString &objectName, QObject *object) { Q_UNUSED(object); unregisterObjectInternal(objectName); if (isConnected()) { Message msg(endpointAddress(), Protocol::ObjectRemoved); msg.payload() << objectName; send(msg); } } void Server::broadcast() { QByteArray datagram; QDataStream stream(&datagram, QIODevice::WriteOnly); stream << Protocol::broadcastFormatVersion(); stream << Protocol::version(); stream << externalAddress(); stream << label(); // TODO integrate hostname m_serverDevice->broadcast(datagram); } QUrl Server::externalAddress() const { if (!m_serverDevice) return QUrl(); return m_serverDevice->externalAddress(); } gammaray-2.3.0/core/remote/server.h000066400000000000000000000100371255003167400172200ustar00rootroot00000000000000/* server.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SERVER_H #define GAMMARAY_SERVER_H #include "../gammaray_core_export.h" #include #include class QTcpServer; class QUdpSocket; class QTimer; namespace GammaRay { class MultiSignalMapper; class ServerDevice; /** Server side connection endpoint. */ class GAMMARAY_CORE_EXPORT Server : public Endpoint { Q_OBJECT public: explicit Server(QObject *parent = 0); ~Server(); /** * Register a server-side QObject to send/receive messages to/from the client side. */ Protocol::ObjectAddress registerObject(const QString &name, QObject *object) Q_DECL_OVERRIDE; /** Register a new object with name @p objectName as a destination for messages. * New messages to that object are passed to the slot @p messageHandlerName on @p receiver. */ Protocol::ObjectAddress registerObject(const QString &objectName, QObject* receiver, const char* messageHandlerName); /** * Register a callback slot @p monitorNotifier on object @p receiver that is called if the usage * of an object with address @p address changes on the client side. * * This is useful for example to disable expensive operations like sending large amounts of * data if nobody is interested anyway. */ void registerMonitorNotifier(Protocol::ObjectAddress address, QObject *receiver, const char* monitorNotifier); /** Singleton accessor. */ static Server* instance(); /** * Call @p method on the remote client and also directly on the local object identified by @p objectName. */ void invokeObject(const QString &objectName, const char *method, const QVariantList &args = QVariantList()) const Q_DECL_OVERRIDE; bool isRemoteClient() const Q_DECL_OVERRIDE; QUrl serverAddress() const Q_DECL_OVERRIDE; /** * Returns an address suitable to connect to this server. * In contrast to serverAddress(), which returns the listening address, which might not * be identical for all protocols (such as TCP). */ QUrl externalAddress() const; protected: void messageReceived(const Message& msg) Q_DECL_OVERRIDE; void handlerDestroyed(Protocol::ObjectAddress objectAddress, const QString& objectName) Q_DECL_OVERRIDE; void objectDestroyed(Protocol::ObjectAddress objectAddress, const QString &objectName, QObject *object) Q_DECL_OVERRIDE; private slots: void newConnection(); void broadcast(); /** * Forward the signal that triggered the call to this slot to the remote client if connected. */ void forwardSignal(QObject* sender, int signalIndex, const QVector &args); private: void sendServerGreeting(); private: ServerDevice *m_serverDevice; QHash > m_monitorNotifiers; Protocol::ObjectAddress m_nextAddress; QString m_label; QTimer* m_broadcastTimer; MultiSignalMapper* m_signalMapper; }; } #endif gammaray-2.3.0/core/remote/serverdevice.cpp000066400000000000000000000040471255003167400207370ustar00rootroot00000000000000/* serverdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "serverdevice.h" #include "tcpserverdevice.h" #include "localserverdevice.h" #include #include using namespace GammaRay; ServerDevice::ServerDevice(QObject* parent): QObject(parent) { } ServerDevice::~ServerDevice() { } void ServerDevice::setServerAddress(const QUrl& serverAddress) { m_address = serverAddress; } void ServerDevice::broadcast(const QByteArray& data) { Q_UNUSED(data); } ServerDevice* ServerDevice::create(const QUrl& serverAddress, QObject* parent) { ServerDevice *device = 0; if (serverAddress.scheme() == QLatin1String("tcp")) device = new TcpServerDevice(parent); else if (serverAddress.scheme() == QLatin1String("local")) device = new LocalServerDevice(parent); if (!device) { qWarning() << "Unsupported transport protocol:" << serverAddress.toString(); return 0; } device->setServerAddress(serverAddress); return device; } gammaray-2.3.0/core/remote/serverdevice.h000066400000000000000000000052331255003167400204020ustar00rootroot00000000000000/* serverdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SERVERDEVICE_H #define GAMMARAY_SERVERDEVICE_H #include #include class QIODevice; namespace GammaRay { /** Abstract base class for the actual transport implementation. */ class ServerDevice : public QObject { Q_OBJECT public: explicit ServerDevice(QObject *parent = 0); ~ServerDevice(); void setServerAddress(const QUrl &serverAddress); virtual bool listen() = 0; virtual QString errorString() const = 0; virtual QIODevice* nextPendingConnection() = 0; /** An externally useable address of this server. * This might be different from @p serverAddress as passed in the constructor. */ virtual QUrl externalAddress() const = 0; static ServerDevice* create(const QUrl &serverAddress, QObject *parent = 0); /** Broadcast the given message on an appropriate channel, if backend supports broadcasting. */ virtual void broadcast(const QByteArray &data); signals: void newConnection(); protected: QUrl m_address; }; template class ServerDeviceImpl : public ServerDevice { public: explicit inline ServerDeviceImpl(QObject *parent = 0) : ServerDevice(parent), m_server(0) { } ~ServerDeviceImpl() { } inline QString errorString() const { return m_server->errorString(); } inline QIODevice* nextPendingConnection() { Q_ASSERT(m_server->hasPendingConnections()); return m_server->nextPendingConnection(); } protected: ServerT* m_server; }; } #endif // GAMMARAY_SERVERDEVICE_H gammaray-2.3.0/core/remote/serverproxymodel.cpp000066400000000000000000000032301255003167400216730ustar00rootroot00000000000000/* serverproxymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "serverproxymodel.h" #include using namespace GammaRay; ServerProxyModel::ServerProxyModel(QObject *parent): QSortFilterProxyModel(parent) { } void ServerProxyModel::addRole(int role) { m_extraRoles.push_back(role); } QMap< int, QVariant > ServerProxyModel::itemData(const QModelIndex &index) const { const QModelIndex sourceIndex = mapToSource(index); auto d = sourceModel()->itemData(sourceIndex); foreach (int role, m_extraRoles) { d.insert(role, sourceIndex.data(role)); } return d; } gammaray-2.3.0/core/remote/serverproxymodel.h000066400000000000000000000032561255003167400213500ustar00rootroot00000000000000/* serverproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SERVERPROXYMODEL_H #define GAMMARAY_SERVERPROXYMODEL_H #include #include namespace GammaRay { /** Sort/filter proxy model for server-side use to pass through extra roles in itemData(). */ class ServerProxyModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ServerProxyModel(QObject *parent = 0); void addRole(int role); QMap itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; private: QVector m_extraRoles; }; } #endif // GAMMARAY_SERVERPROXYMODEL_H gammaray-2.3.0/core/remote/tcpserverdevice.cpp000066400000000000000000000054411255003167400214450ustar00rootroot00000000000000/* tcpserverdevice.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "tcpserverdevice.h" #include "server.h" #include #include #include using namespace GammaRay; TcpServerDevice::TcpServerDevice(QObject* parent): ServerDeviceImpl(parent), m_broadcastSocket(new QUdpSocket(this)) { m_server = new QTcpServer(this); connect(m_server, SIGNAL(newConnection()), this, SIGNAL(newConnection())); } TcpServerDevice::~TcpServerDevice() { } bool TcpServerDevice::listen() { const QHostAddress address(m_address.host()); // try the requested port first, and fall back to a random port otherwise if (m_server->listen(address, m_address.port())) return true; return m_server->listen(address, 0); } QUrl TcpServerDevice::externalAddress() const { QString myHost; foreach (const QHostAddress &addr, QNetworkInterface::allAddresses()) { if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6 || !addr.scopeId().isEmpty()) continue; myHost = addr.toString(); break; } QUrl url; url.setScheme(QLatin1String("tcp")); url.setHost(myHost); url.setPort(m_server->serverPort()); return url; } void TcpServerDevice::broadcast(const QByteArray &data) { const QHostAddress address = m_server->serverAddress(); // broadcast announcement only if we are actually listinging to remote connections #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) if (address.toString() == "127.0.0.1" || address.toString() == "::1") #else if (address.isLoopback()) #endif return; m_broadcastSocket->writeDatagram(data.data(), data.size(), QHostAddress::Broadcast, Server::broadcastPort()); } gammaray-2.3.0/core/remote/tcpserverdevice.h000066400000000000000000000032661255003167400211150ustar00rootroot00000000000000/* tcpserverdevice.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TCPSERVERDEVICE_H #define GAMMARAY_TCPSERVERDEVICE_H #include "serverdevice.h" #include #include class QUdpSocket; namespace GammaRay { class TcpServerDevice : public ServerDeviceImpl { Q_OBJECT public: explicit TcpServerDevice(QObject* parent = 0); ~TcpServerDevice(); bool listen() Q_DECL_OVERRIDE; QUrl externalAddress() const Q_DECL_OVERRIDE; void broadcast(const QByteArray &data) Q_DECL_OVERRIDE; private: QUdpSocket* m_broadcastSocket; }; } #endif // GAMMARAY_TCPSERVERDEVICE_H gammaray-2.3.0/core/signalspycallbackset.cpp000066400000000000000000000027571255003167400211660ustar00rootroot00000000000000/* signalspycallbackset.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalspycallbackset.h" using namespace GammaRay; SignalSpyCallbackSet::SignalSpyCallbackSet() : signalBeginCallback(0), signalEndCallback(0), slotBeginCallback(0), slotEndCallback(0) { } bool SignalSpyCallbackSet::isNull() const { return signalBeginCallback == 0 && signalEndCallback == 0 && slotBeginCallback == 0 && slotEndCallback == 0; } gammaray-2.3.0/core/signalspycallbackset.h000066400000000000000000000034111255003167400206170ustar00rootroot00000000000000/* signalspycallbackset.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALSPYCALLBACKSET_H #define GAMMARAY_SIGNALSPYCALLBACKSET_H #include "gammaray_core_export.h" class QObject; namespace GammaRay { /** @brief Callbacks for tracing signal emissions and slot invocation. * * @since 2.3 */ struct GAMMARAY_CORE_EXPORT SignalSpyCallbackSet { SignalSpyCallbackSet(); bool isNull() const; typedef void (*BeginCallback)(QObject *caller, int methodIndex, void **argv); typedef void (*EndCallback)(QObject *caller, int methodIndex); BeginCallback signalBeginCallback; EndCallback signalEndCallback; BeginCallback slotBeginCallback; EndCallback slotEndCallback; }; } #endif gammaray-2.3.0/core/singlecolumnobjectproxymodel.h000066400000000000000000000053541255003167400224360ustar00rootroot00000000000000/* singlecolumnobjectproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares the SingleColumnObjectProxyModel class. @brief Declares the SingleColumnObjectProxyModel class. @author Volker Krause \ */ #ifndef GAMMARAY_SINGLECOLUMNOBJECTPROXYMODEL_H #define GAMMARAY_SINGLECOLUMNOBJECTPROXYMODEL_H #include #include "util.h" #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) #include typedef QSortFilterProxyModel QIdentityProxyModel; #else #include #endif namespace GammaRay { /** * @brief A QIdentityProxyModel for generic Objects. */ class SingleColumnObjectProxyModel : public QIdentityProxyModel { public: /** * Constructor. * @param parent is the parent object for this instance. */ explicit SingleColumnObjectProxyModel(QObject *parent = 0) : QIdentityProxyModel(parent) { } /** * Returns the data for the specified model. * @param proxyIndex is a QModelIndex. * @param role is a Qt role. * * @return on success, a QVariant containing the data; * QVariant() if some anamoly occurs. */ QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const { if (proxyIndex.isValid() && role == Qt::DisplayRole && proxyIndex.column() == 0) { const QObject *obj = proxyIndex.data(ObjectModel::ObjectRole).value(); if (obj) { return Util::displayString(obj); } } return QIdentityProxyModel::data(proxyIndex, role); } }; } #endif // GAMMARAY_SINGLECOLUMNOBJECTPROXYMODEL_H gammaray-2.3.0/core/toolfactory.h000066400000000000000000000071421255003167400167670ustar00rootroot00000000000000/* toolfactory.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares the ToolFactory abstract base class. @brief Declares the ToolFactory abstract base class. @author Volker Krause \ */ #ifndef GAMMARAY_TOOLFACTORY_H #define GAMMARAY_TOOLFACTORY_H #include "probeinterface.h" #include #include #include namespace GammaRay { class ProbeInterface; /** * @brief An abstract interface for probe tools. * * The ToolFactory class is an abstract base class for creating probe tools * for GammaRay. Each tool must have a unique identifier. */ class ToolFactory { public: virtual inline ~ToolFactory() { } /** * Unique id of this tool * @return a QString containing the tool id. */ virtual QString id() const = 0; /** * Human readable name of this tool. * @return a QString containing the tool name. */ virtual QString name() const = 0; /** * Class names of types this tool can handle. * The tool will only be activated if an object of one of these types * is seen in the probed application. * @return a QStringList of class names of types this tool supports. */ virtual QStringList supportedTypes() const = 0; /** * Initialize the tool. * Implement this method to do non-GUI initialization, such as creating * object tracking models etc. * @param probe The probe interface allowing access to the object models. */ virtual void init(ProbeInterface *probe) = 0; /** * Allows to hide a plug-in from the UI. * This is useful for plug-ins that only provide support for additional * data types. * @since 2.1 */ virtual bool isHidden() const = 0; }; /** * @brief A templated generic ToolFactory for some data type and tool. */ template class StandardToolFactory : public ToolFactory { public: virtual inline QStringList supportedTypes() const { return QStringList(Type::staticMetaObject.className()); } virtual inline QString id() const { return Tool::staticMetaObject.className(); } virtual inline void init(ProbeInterface *probe) { new Tool(probe, probe->probe()); } inline bool isHidden() const { return false; } }; } Q_DECLARE_INTERFACE(GammaRay::ToolFactory, "com.kdab.GammaRay.ToolFactory/1.0") Q_DECLARE_METATYPE(GammaRay::ToolFactory *) #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define Q_PLUGIN_METADATA(x) #endif #endif gammaray-2.3.0/core/toolmodel.cpp000066400000000000000000000155621255003167400167600ustar00rootroot00000000000000/* toolmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "toolmodel.h" #include "toolfactory.h" #include "proxytoolfactory.h" #include "probe.h" #include "probesettings.h" #include "tools/connectioninspector/connectioninspector.h" #include "tools/localeinspector/localeinspector.h" #include "tools/metatypebrowser/metatypebrowser.h" #include "tools/modelinspector/modelinspector.h" #include "tools/objectinspector/objectinspector.h" #include "tools/resourcebrowser/resourcebrowser.h" #include "tools/textdocumentinspector/textdocumentinspector.h" #include "tools/messagehandler/messagehandler.h" #include "tools/metaobjectbrowser/metaobjectbrowser.h" #include "metaobjectrepository.h" #include "metaobject.h" #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include "tools/standardpaths/standardpaths.h" #include "tools/mimetypes/mimetypes.h" #endif #include #include #include #include #include #include #include using namespace GammaRay; ToolModel::ToolModel(QObject *parent): QAbstractListModel(parent) { // built-in tools addToolFactory(new ObjectInspectorFactory(this)); addToolFactory(new ModelInspectorFactory(this)); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) addToolFactory(new ConnectionInspectorFactory(this)); #endif addToolFactory(new ResourceBrowserFactory(this)); addToolFactory(new MetaObjectBrowserFactory(this)); addToolFactory(new MetaTypeBrowserFactory(this)); addToolFactory(new TextDocumentInspectorFactory(this)); addToolFactory(new MessageHandlerFactory(this)); addToolFactory(new LocaleInspectorFactory(this)); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) addToolFactory(new StandardPathsFactory(this)); addToolFactory(new MimeTypesFactory(this)); #endif m_pluginManager.reset(new ToolPluginManager(this)); Q_FOREACH (ToolFactory *factory, m_pluginManager->plugins()) { addToolFactory(factory); } } ToolModel::~ToolModel() { } QVariant ToolModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Probe"); default: return tr("N/A"); } } return QAbstractItemModel::headerData(section, orientation, role); } QVariant ToolModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } ToolFactory *toolIface = m_tools.at(index.row()); if (role == Qt::DisplayRole) { return toolIface->name(); } else if (role == ToolModelRole::ToolFactory) { return QVariant::fromValue(toolIface); } else if (role == ToolModelRole::ToolId) { return toolIface->id(); } else if (role == ToolModelRole::ToolEnabled) { return !m_inactiveTools.contains(toolIface); } return QVariant(); } int ToolModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_tools.size(); } Qt::ItemFlags ToolModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.isValid()) { ToolFactory *toolIface = m_tools.at(index.row()); if (m_inactiveTools.contains(toolIface)) { flags &= ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable); } } return flags; } QMap ToolModel::itemData(const QModelIndex& index) const { QMap map = QAbstractListModel::itemData(index); map.insert(ToolModelRole::ToolId, data(index, ToolModelRole::ToolId)); map.insert(ToolModelRole::ToolEnabled, data(index, ToolModelRole::ToolEnabled)); // the other custom roles are useless on the client anyway, since they contain raw pointers return map; } void ToolModel::objectAdded(QObject *obj) { Q_ASSERT(QThread::currentThread() == thread()); Q_ASSERT(Probe::instance()->isValidObject(obj)); // m_knownMetaObjects allows us to skip the expensive recursive search for matching tools if (!m_knownMetaObjects.contains(obj->metaObject())) { objectAdded(obj->metaObject()); m_knownMetaObjects.insert(obj->metaObject()); } } void ToolModel::objectAdded(const QMetaObject *mo) { Q_ASSERT(thread() == QThread::currentThread()); foreach (ToolFactory *factory, m_inactiveTools) { if (factory->supportedTypes().contains(mo->className())) { m_inactiveTools.remove(factory); factory->init(Probe::instance()); const int row = m_tools.indexOf(factory); emit dataChanged(index(row, 0), index(row, 0)); } } if (mo->superClass()) { objectAdded(mo->superClass()); } } QVector< ToolFactory* > ToolModel::plugins() const { return m_pluginManager->plugins(); } PluginLoadErrors ToolModel::pluginErrors() const { return m_pluginManager->errors(); } QModelIndex ToolModel::toolForObject(QObject* object) const { if (!object) return QModelIndex(); const QMetaObject *metaObject = object->metaObject(); while (metaObject) { for (int i = 0; i < m_tools.size(); i++) { const ToolFactory *factory = m_tools.at(i); if (factory && factory->supportedTypes().contains(metaObject->className())) { return index(i, 0); } } metaObject = metaObject->superClass(); } return QModelIndex(); } QModelIndex ToolModel::toolForObject(const void* object, const QString& typeName) const { if (!object) return QModelIndex(); const MetaObject *metaObject = MetaObjectRepository::instance()->metaObject(typeName); while (metaObject) { for (int i = 0; i < m_tools.size(); i++) { const ToolFactory *factory = m_tools.at(i); if (factory && factory->supportedTypes().contains(metaObject->className())) { return index(i, 0); } } metaObject = metaObject->superClass(); } return QModelIndex(); } void ToolModel::addToolFactory(ToolFactory* tool) { if (!tool->isHidden()) m_tools.push_back(tool); m_inactiveTools.insert(tool); } gammaray-2.3.0/core/toolmodel.h000066400000000000000000000063001255003167400164130ustar00rootroot00000000000000/* toolmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TOOLMODEL_H #define GAMMARAY_TOOLMODEL_H #include #include #include #include #include #include namespace GammaRay { class ToolFactory; class ProxyToolFactory; typedef PluginManager ToolPluginManager; /** * Manages the list of available probing tools. */ class ToolModel : public QAbstractListModel { Q_OBJECT public: explicit ToolModel(QObject *parent = 0); ~ToolModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; /** returns all tools provided by plugins for the ToolPluginModel. */ QVector plugins() const; /** returns all plugin load errors. */ PluginLoadErrors pluginErrors() const; /** returns the tool that is best suited to show information about \p object. */ QModelIndex toolForObject(QObject *object) const; /** returns the tool that is best suited to show information about \p object. */ QModelIndex toolForObject(const void *object, const QString &typeName) const; public slots: /** Check if we have to activate tools for this type */ void objectAdded(QObject *obj); private: /** * Check if we have to activate tools for this type * * NOTE: must be called from the GUI thread */ void objectAdded(const QMetaObject *mo); void addToolFactory(ToolFactory* tool); private: QVector m_tools; QSet m_inactiveTools; QSet m_knownMetaObjects; QPointer m_parentWidget; QScopedPointer m_pluginManager; }; } #endif // GAMMARAY_TOOLMODEL_H gammaray-2.3.0/core/toolpluginerrormodel.cpp000066400000000000000000000046301255003167400212430ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "toolpluginerrormodel.h" using namespace GammaRay; ToolPluginErrorModel::ToolPluginErrorModel(const PluginLoadErrors& errors, QObject* parent) : QAbstractTableModel(parent), m_errors(errors) { } ToolPluginErrorModel::~ToolPluginErrorModel() { } int ToolPluginErrorModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 3; } int ToolPluginErrorModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); return m_errors.size(); } QVariant ToolPluginErrorModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } const int row = index.row(); const int column = index.column(); if (role == Qt::DisplayRole) { switch (column) { case 0: return m_errors[row].pluginName(); case 1: return m_errors[row].pluginFile; case 2: return m_errors[row].errorString; } } return QVariant(); } QVariant ToolPluginErrorModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Plugin Name"); case 1: return tr("Plugin File"); case 2: return tr("Error Message"); } } return QAbstractTableModel::headerData(section, orientation, role); } gammaray-2.3.0/core/toolpluginerrormodel.h000066400000000000000000000036411255003167400207110ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TOOLPLUGINERRORMODEL_H #define GAMMARAY_TOOLPLUGINERRORMODEL_H #include #include namespace GammaRay { /** List of plugin loading errors on the target. */ class ToolPluginErrorModel : public QAbstractTableModel { Q_OBJECT public: explicit ToolPluginErrorModel(const PluginLoadErrors &errors, QObject *parent = 0); ~ToolPluginErrorModel(); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: PluginLoadErrors m_errors; }; } #endif // GAMMARAY_TOOLPLUGINERRORMODEL_H gammaray-2.3.0/core/toolpluginmodel.cpp000066400000000000000000000046321255003167400201730ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "toolpluginmodel.h" #include "toolfactory.h" using namespace GammaRay; ToolPluginModel::ToolPluginModel(const QVector &plugins, QObject* parent): QAbstractTableModel(parent), m_tools(plugins) { } ToolPluginModel::~ToolPluginModel() { } int ToolPluginModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 3; } int ToolPluginModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); return m_tools.size(); } QVariant ToolPluginModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } const int row = index.row(); const int column = index.column(); if (role == Qt::DisplayRole) { ToolFactory *factory = m_tools[row]; switch (column) { case 0: return factory->id(); case 1: return factory->name(); case 2: return factory->supportedTypes().join(", "); } } return QVariant(); } QVariant ToolPluginModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Id"); case 1: return tr("Name"); case 2: return tr("Supported types"); } } return QAbstractTableModel::headerData(section, orientation, role); } gammaray-2.3.0/core/toolpluginmodel.h000066400000000000000000000036471255003167400176450ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TOOLPLUGINMODEL_H #define GAMMARAY_TOOLPLUGINMODEL_H #include #include namespace GammaRay { class ToolFactory; /** Information about loaded plugins, for display in the about dialog. */ class ToolPluginModel : public QAbstractTableModel { Q_OBJECT public: explicit ToolPluginModel(const QVector &plugins, QObject *parent = 0); ~ToolPluginModel(); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QVector m_tools; }; } #endif // GAMMARAY_TOOLPLUGINMODEL_H gammaray-2.3.0/core/tools/000077500000000000000000000000001255003167400154055ustar00rootroot00000000000000gammaray-2.3.0/core/tools/connectioninspector/000077500000000000000000000000001255003167400214735ustar00rootroot00000000000000gammaray-2.3.0/core/tools/connectioninspector/connectioninspector.cpp000066400000000000000000000024651255003167400262740ustar00rootroot00000000000000/* connectioninspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectioninspector.h" using namespace GammaRay; ConnectionInspector::ConnectionInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) { Q_UNUSED(probe); } gammaray-2.3.0/core/tools/connectioninspector/connectioninspector.h000066400000000000000000000035241255003167400257360ustar00rootroot00000000000000/* connectioninspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONINSPECTOR_CONNECTIONINSPECTOR_H #define GAMMARAY_CONNECTIONINSPECTOR_CONNECTIONINSPECTOR_H #include "toolfactory.h" namespace GammaRay { class ConnectionInspector : public QObject { Q_OBJECT public: explicit ConnectionInspector(ProbeInterface *probe, QObject *parent = 0); }; class ConnectionInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit ConnectionInspectorFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Connections"); } }; } #endif // GAMMARAY_CONNECTIONINSPECTOR_H gammaray-2.3.0/core/tools/localeinspector/000077500000000000000000000000001255003167400205735ustar00rootroot00000000000000gammaray-2.3.0/core/tools/localeinspector/localeaccessormodel.cpp000066400000000000000000000057371255003167400253160ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localeaccessormodel.h" #include "localedataaccessor.h" #include #include using namespace GammaRay; LocaleAccessorModel::LocaleAccessorModel(LocaleDataAccessorRegistry *registry, QObject *parent) : QAbstractTableModel(parent), m_registry(registry) { } int LocaleAccessorModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } int area = m_registry->accessors().size(); return qSqrt(area); } int LocaleAccessorModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } int area = m_registry->accessors().size(); return qCeil((float)area / (int)qSqrt(area)); } Qt::ItemFlags LocaleAccessorModel::flags(const QModelIndex &index) const { return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable; } QVariant LocaleAccessorModel::data(const QModelIndex &index, int role) const { QVector acc = m_registry->accessors(); int offset = (index.row() * columnCount()) + index.column(); if (offset >= acc.size()) { return QVariant(); } LocaleDataAccessor *accessor = acc.at(offset); switch(role) { case Qt::DisplayRole: return accessor->accessorName(); case Qt::CheckStateRole: return m_registry->enabledAccessors().contains(accessor) ? Qt::Checked : Qt::Unchecked; case AccessorRole: return QVariant::fromValue(accessor); default: return QVariant(); } } bool LocaleAccessorModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::CheckStateRole) { return QAbstractItemModel::setData(index, value, role); } bool enabled = value.toInt() == Qt::Checked; LocaleDataAccessor *accessor = index.data(AccessorRole).value(); m_registry->setAccessorEnabled(accessor, enabled); emit dataChanged(index, index); return true; } gammaray-2.3.0/core/tools/localeinspector/localeaccessormodel.h000066400000000000000000000042601255003167400247510ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALEINSPECTOR_LOCALEACCESSORMODEL_H #define GAMMARAY_LOCALEINSPECTOR_LOCALEACCESSORMODEL_H #include "common/modelroles.h" #include #include namespace GammaRay { class LocaleDataAccessorRegistry; struct LocaleDataAccessor; class LocaleAccessorModel : public QAbstractTableModel { Q_OBJECT Q_ENUMS(CustomRoles) public: enum CustomRoles { AccessorRole = UserRole + 1 }; explicit LocaleAccessorModel(LocaleDataAccessorRegistry *registry, QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; private: QVector enabledAccessors; LocaleDataAccessorRegistry *m_registry; }; } #endif gammaray-2.3.0/core/tools/localeinspector/localedataaccessor.cpp000066400000000000000000000123271255003167400251200ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localedataaccessor.h" #include using namespace GammaRay; LocaleDataAccessorRegistry::LocaleDataAccessorRegistry(QObject *parent) : QObject(parent) { init(); } LocaleDataAccessorRegistry::~LocaleDataAccessorRegistry() { qDeleteAll(m_accessors); } QVector< LocaleDataAccessor * > LocaleDataAccessorRegistry::accessors() { return m_accessors; } QVector< LocaleDataAccessor * > LocaleDataAccessorRegistry::enabledAccessors() { return m_enabledAccessors; } void LocaleDataAccessorRegistry::registerAccessor(LocaleDataAccessor *accessor) { m_accessors.push_back(accessor); } void LocaleDataAccessorRegistry::setAccessorEnabled(LocaleDataAccessor *accessor, bool enabled) { QVector< LocaleDataAccessor * > &accessors = m_enabledAccessors; if (enabled && !accessors.contains(accessor)) { accessors.push_back(accessor); } else { int idx = accessors.indexOf(accessor); if (idx >= 0) { accessors.remove(idx); } } emit accessorsChanged(); } void LocaleDataAccessorRegistry::init() { LOCALE_SIMPLE_DEFAULT_ACCESSOR(Name, return locale.name(); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(Language, return QLocale::languageToString(locale.language()); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(Country, return QLocale::countryToString(locale.country()); ) #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) LOCALE_SIMPLE_ACCESSOR(Script, return QLocale::scriptToString(locale.script()); ) LOCALE_SIMPLE_ACCESSOR(Currency, return locale.currencySymbol(QLocale::CurrencySymbol) + QLatin1String(" (") + locale.currencySymbol(QLocale::CurrencyIsoCode) + QLatin1String(") - ") + locale.currencySymbol(QLocale::CurrencyDisplayName); ) #endif LOCALE_SIMPLE_ACCESSOR(TextDirection, return locale.textDirection() == Qt::LeftToRight ? "LTR" : "RTL"; ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(TimeFormatLong, return locale.timeFormat(QLocale::LongFormat); ) LOCALE_SIMPLE_ACCESSOR(TimeFormatShort, return locale.timeFormat(QLocale::ShortFormat); ) LOCALE_SIMPLE_ACCESSOR(TimeFormatNarrow, return locale.timeFormat(QLocale::NarrowFormat); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(DateFormatLong, return locale.dateFormat(QLocale::LongFormat); ) LOCALE_SIMPLE_ACCESSOR(DateFormatShort, return locale.dateFormat(QLocale::ShortFormat); ) LOCALE_SIMPLE_ACCESSOR(DateFormatNarrow, return locale.dateFormat(QLocale::NarrowFormat); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(DateTimeFormatLong, return locale.dateTimeFormat(QLocale::LongFormat); ) LOCALE_SIMPLE_ACCESSOR(DateTimeFormatShort, return locale.dateTimeFormat(QLocale::ShortFormat); ) LOCALE_SIMPLE_ACCESSOR(DateTimeFormatNarrow, return locale.dateTimeFormat(QLocale::NarrowFormat); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(MeasurementSystem, return locale.measurementSystem() == QLocale::ImperialSystem ? "Imperial" : "Metric"; ) LOCALE_SIMPLE_ACCESSOR(AmText, return locale.amText(); ) LOCALE_SIMPLE_ACCESSOR(PmText, return locale.pmText(); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(FloatFormat, return locale.toString(10000.1); ) #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) LOCALE_SIMPLE_ACCESSOR(NativeCountry, return locale.nativeCountryName(); ) LOCALE_SIMPLE_ACCESSOR(NativeLanguage, return locale.nativeLanguageName(); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(FirstDayOfWeek, return QLocale().dayName(locale.firstDayOfWeek()); ) LOCALE_SIMPLE_DEFAULT_ACCESSOR(WeekDays, const auto wds = locale.weekdays(); QStringList resultList; resultList.reserve(wds.size()); Q_FOREACH (const Qt::DayOfWeek &dayNumber, wds) { resultList << QLocale().dayName(dayNumber); } return QLocale().createSeparatedList(resultList); ) LOCALE_SIMPLE_ACCESSOR(BCP47, return locale.bcp47Name(); ) #endif LOCALE_SIMPLE_ACCESSOR(DecimalPoint, return locale.decimalPoint(); ) LOCALE_SIMPLE_ACCESSOR(GroupSeparator, return locale.groupSeparator(); ) LOCALE_SIMPLE_ACCESSOR(Exponential, return locale.exponential(); ) LOCALE_SIMPLE_ACCESSOR(Percent, return locale.percent(); ) LOCALE_SIMPLE_ACCESSOR(PositiveSign, return locale.positiveSign(); ) LOCALE_SIMPLE_ACCESSOR(NegativeSign, return locale.negativeSign(); ) } gammaray-2.3.0/core/tools/localeinspector/localedataaccessor.h000066400000000000000000000072141255003167400245640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation toolocale. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALEINSPECTOR_LOCALEDATAACCESSOR_H #define GAMMARAY_LOCALEINSPECTOR_LOCALEDATAACCESSOR_H #include #include #include #include #include namespace GammaRay { struct LocaleDataAccessor; class LocaleDataAccessorRegistry : public QObject { Q_OBJECT public: explicit LocaleDataAccessorRegistry(QObject *parent = 0); ~LocaleDataAccessorRegistry(); void registerAccessor(LocaleDataAccessor *accessor); void setAccessorEnabled(LocaleDataAccessor *accessor, bool enabled); QVector accessors(); QVector enabledAccessors(); Q_SIGNALS: void accessorsChanged(); private: void init(); private: QVector m_accessors; QVector m_enabledAccessors; }; struct LocaleDataAccessor { LocaleDataAccessor(LocaleDataAccessorRegistry *registry, bool defaultAccessor = false) { registry->registerAccessor(this); if (defaultAccessor) { registry->setAccessorEnabled(this, true); } } virtual ~LocaleDataAccessor() {} virtual QString accessorName() = 0; QVariant data(const QLocale &locale, int role) { if (role == Qt::DisplayRole) { return display(locale); } return QVariant(); } virtual QString display(const QLocale &) { return QString(); } }; #define LOCALE_DISPLAY_ACCESSOR(NAME) \ struct Locale##NAME##Accessor : LocaleDataAccessor \ { \ Locale##NAME##Accessor(LocaleDataAccessorRegistry *registry) : LocaleDataAccessor(registry) {} \ QString accessorName() { return #NAME; } \ QString display(const QLocale &locale) \ { \ #define LOCALE_DEFAULT_DISPLAY_ACCESSOR(NAME) \ struct Locale##NAME##Accessor : LocaleDataAccessor \ { \ Locale##NAME##Accessor(LocaleDataAccessorRegistry *registry) : LocaleDataAccessor(registry, true) {} \ \ QString accessorName() \ { \ return #NAME; \ } \ QString display(const QLocale &locale) \ { \ #define LOCALE_DISPLAY_ACCESSOR_END(NAME) \ return QString(); \ } \ }; new Locale##NAME##Accessor(this); #define LOCALE_SIMPLE_ACCESSOR(NAME, IMPLEMENTATION) \ LOCALE_DISPLAY_ACCESSOR(NAME) \ IMPLEMENTATION \ LOCALE_DISPLAY_ACCESSOR_END(NAME) #define LOCALE_SIMPLE_DEFAULT_ACCESSOR(NAME, IMPLEMENTATION) \ LOCALE_DEFAULT_DISPLAY_ACCESSOR(NAME) \ IMPLEMENTATION \ LOCALE_DISPLAY_ACCESSOR_END(NAME) } Q_DECLARE_METATYPE(GammaRay::LocaleDataAccessor *) #endif gammaray-2.3.0/core/tools/localeinspector/localeinspector.cpp000066400000000000000000000032741255003167400244730ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localeinspector.h" #include "localemodel.h" #include "localeaccessormodel.h" #include "localedataaccessor.h" using namespace GammaRay; LocaleInspector::LocaleInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) { LocaleDataAccessorRegistry *registry = new LocaleDataAccessorRegistry(this); LocaleModel *model = new LocaleModel(registry, this); probe->registerModel("com.kdab.GammaRay.LocaleModel", model); LocaleAccessorModel *accessorModel = new LocaleAccessorModel(registry, this); probe->registerModel("com.kdab.GammaRay.LocaleAccessorModel", accessorModel); } gammaray-2.3.0/core/tools/localeinspector/localeinspector.h000066400000000000000000000033641255003167400241400ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALEINSPECTOR_LOCALEINSPECTOR_H #define GAMMARAY_LOCALEINSPECTOR_LOCALEINSPECTOR_H #include "toolfactory.h" namespace GammaRay { class LocaleInspector : public QObject { Q_OBJECT public: explicit LocaleInspector(ProbeInterface *probe, QObject *parent = 0); }; class LocaleInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit LocaleInspectorFactory(QObject *parent) : QObject(parent) { } virtual inline QString name() const { return tr("Locales"); } }; } #endif // GAMMARAY_LOCALEINSPECTOR_H gammaray-2.3.0/core/tools/localeinspector/localemodel.cpp000066400000000000000000000061341255003167400235630ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localemodel.h" #include "localedataaccessor.h" #include #include using namespace GammaRay; LocaleModel::LocaleModel(LocaleDataAccessorRegistry *registry, QObject *parent) : QAbstractTableModel(parent), m_registry(registry) { init(); connect(registry, SIGNAL(accessorsChanged()), SLOT(reinit())); } int LocaleModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_localeData.size(); } QVariant LocaleModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_locales.size() || index.column() >= m_localeData.size()) { return QVariant(); } const QLocale l = m_locales.at(index.row()); return m_localeData.at(index.column())->data(l, role); } QVariant LocaleModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QAbstractItemModel::headerData(section, orientation, role); } if (orientation == Qt::Vertical) { return QAbstractItemModel::headerData(section, orientation, role); } LocaleDataAccessor *d = m_localeData.at(section); return d->accessorName(); } void LocaleModel::init() { m_localeData = m_registry->enabledAccessors(); #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) m_locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry).toVector(); #else m_locales.clear(); QLocale::Language l = QLocale::C; while (QLocale::languageToString(l) != QLatin1String("Unknown")) { QList countries = QLocale::countriesForLanguage(l); Q_FOREACH (const QLocale::Country &c, countries) { m_locales.append(QLocale(l, c)); } l = (QLocale::Language)((int)(l) + 1); } #endif } void LocaleModel::reinit() { beginResetModel(); init(); endResetModel(); } int LocaleModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_locales.size(); } gammaray-2.3.0/core/tools/localeinspector/localemodel.h000066400000000000000000000041411255003167400232240ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALEINSPECTOR_LOCALEMODEL_H #define GAMMARAY_LOCALEINSPECTOR_LOCALEMODEL_H #include #include #include namespace GammaRay { class LocaleDataAccessorRegistry; struct LocaleDataAccessor; class LocaleModel : public QAbstractTableModel { Q_OBJECT public: explicit LocaleModel(LocaleDataAccessorRegistry *registry, QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: void init(); private slots: void reinit(); private: QVector m_locales; QVector m_localeData; LocaleDataAccessorRegistry *m_registry; }; } #endif gammaray-2.3.0/core/tools/messagehandler/000077500000000000000000000000001255003167400203675ustar00rootroot00000000000000gammaray-2.3.0/core/tools/messagehandler/backtrace.h000066400000000000000000000026341255003167400224640ustar00rootroot00000000000000/* backtrace.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef GAMMARAY_MESSAGEHANDLER_BACKTRACE_H #define GAMMARAY_MESSAGEHANDLER_BACKTRACE_H #include typedef QStringList Backtrace; Backtrace getBacktrace(int levels = -1); #endif // BACKTRACE_H gammaray-2.3.0/core/tools/messagehandler/backtrace_dummy.cpp000066400000000000000000000024751255003167400242350ustar00rootroot00000000000000/* backtrace_dummy.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "backtrace.h" Backtrace getBacktrace(int levels) { Q_UNUSED(levels); return Backtrace(); } gammaray-2.3.0/core/tools/messagehandler/backtrace_unix.cpp000066400000000000000000000120451255003167400240570ustar00rootroot00000000000000/* backtrace_unix.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA NOTE: This file is heavily inspired/copied from kdebug.cpp in kdelibs/kdecore/io The original license is: This file is part of the KDE libraries Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) 2002 Holger Freyther (freyther@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //krazy:excludeall=cpp since lots of low-level stuff in here #include "backtrace.h" #ifdef IN_KDEVELOP_PARSER #define HAVE_BACKTRACE #define HAVE_BACKTRACE_DEMANGLE #endif //NOTE: we don't have check_function_exists, so lets just hardcode some OS'es #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__) #define HAVE_BACKTRACE (1) #endif ///TODO: what else is supported? what about mac? ///BEGIN kdebug.cpp #include #include #ifdef Q_OS_SOLARIS // For the purposes of KDebug Solaris has a GNU-libc-compatible // backtrace() function. This isn't detected by the CMake checks // normally (check_function_exists fails), but we know it's there. // For better results, we would use walk_context(), but that's // a little more code -- see also the crash handler in kcrash.cpp . #define HAVE_BACKTRACE (1) #endif #ifdef HAVE_BACKTRACE #include #ifdef __GNUC__ #define HAVE_BACKTRACE_DEMANGLE #include #endif #endif #ifdef HAVE_BACKTRACE static QString maybeDemangledName(char *name) { #ifdef HAVE_BACKTRACE_DEMANGLE const int len = strlen(name); QByteArray in = QByteArray::fromRawData(name, len); const int mangledNameStart = in.indexOf("(_"); if (mangledNameStart >= 0) { const int mangledNameEnd = in.indexOf('+', mangledNameStart + 2); if (mangledNameEnd >= 0) { int status; // if we forget about this line and the one that undoes its effect we don't change the // internal data of the QByteArray::fromRawData() ;) name[mangledNameEnd] = 0; char *demangled = abi::__cxa_demangle(name + mangledNameStart + 1, 0, 0, &status); name[mangledNameEnd] = '+'; if (demangled) { QString ret = QString::fromLatin1(name, mangledNameStart + 1) + QString::fromLatin1(demangled) + QString::fromLatin1(name + mangledNameEnd, len - mangledNameEnd); free(demangled); return ret; } } } #endif return QString::fromLatin1(name); } #endif QString kRealBacktrace(int levels) { QString s; #ifdef HAVE_BACKTRACE void *trace[256]; int n = backtrace(trace, 256); if (!n) { return s; } char **strings = backtrace_symbols(trace, n); if (levels != -1) { n = qMin(n, levels); } s = QLatin1String("[\n"); for (int i = 0; i < n; ++i) { s += QString::number(i) + QLatin1String(": ") + maybeDemangledName(strings[i]) + QLatin1Char('\n'); } s += QLatin1String("]\n"); if (strings) { free (strings); } #else Q_UNUSED(levels); #endif return s; } ///END kdebug.cpp Backtrace backtraceList(int levels) { QStringList s; #ifdef HAVE_BACKTRACE void *trace[256]; int n = backtrace(trace, 256); if (!n) { return s; } char **strings = backtrace_symbols(trace, n); if (levels != -1) { n = qMin(n, levels); } for (int i = 0; i < n; ++i) { s << maybeDemangledName(strings[i]); } if (strings) { free(strings); } #else Q_UNUSED(levels); #endif return s; } Backtrace getBacktrace(int levels) { return backtraceList(levels); } gammaray-2.3.0/core/tools/messagehandler/backtrace_win.cpp000066400000000000000000000045421255003167400236740ustar00rootroot00000000000000/* backtrace_win.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "backtrace.h" #include class StackWalkerToQStringList : public StackWalker { public: QStringList getStackWalkerBacktrace() { m_stackTrace.clear(); ShowCallstack(); return m_stackTrace; } protected: virtual void OnOutput(LPCSTR szText) { m_stackTrace << szText; } virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) { } virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) { } virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) { } private: QStringList m_stackTrace; }; static StackWalkerToQStringList *stackWalkerToQStringList = 0; Backtrace getBacktrace(int/*levels*/) { //FIXME: Perhaps take the levels into account if (!stackWalkerToQStringList) { stackWalkerToQStringList = new StackWalkerToQStringList(); } return stackWalkerToQStringList->getStackWalkerBacktrace(); } gammaray-2.3.0/core/tools/messagehandler/messagehandler.cpp000066400000000000000000000152701255003167400240620ustar00rootroot00000000000000/* messagehandler.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagehandler.h" #include "messagemodel.h" #include "backtrace.h" #include #include "common/objectbroker.h" #include "common/endpoint.h" #include #include #include #include static QTextStream cerr(stdout); using namespace GammaRay; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) typedef QtMsgHandler MessageHandlerCallback; static MessageHandlerCallback (*const installMessageHandler)(MessageHandlerCallback) = qInstallMsgHandler; #else typedef QtMessageHandler MessageHandlerCallback; static MessageHandlerCallback (*const installMessageHandler)(MessageHandlerCallback) = qInstallMessageHandler; #endif static MessageModel *s_model = 0; static MessageHandlerCallback s_handler = 0; static bool s_handlerDisabled = false; static QMutex s_mutex(QMutex::Recursive); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static void handleMessage(QtMsgType type, const char *rawMsg) #else static void handleMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) #endif { ///WARNING: do not trigger *any* kind of debug output here /// this would trigger an infinite loop and hence crash! #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) const QString msg = QString::fromLocal8Bit(rawMsg); #endif DebugMessage message; message.type = type; message.message = msg; message.time = QTime::currentTime(); if (type == QtCriticalMsg || type == QtFatalMsg || (type == QtWarningMsg && !ProbeGuard::insideProbe())) { message.backtrace = getBacktrace(50); // remove trailing internal functions // be a bit careful and first make sure that we find this function... // TODO: go even higher until qWarning/qFatal/qDebug/... ? int removeUntil = -1; for (int i = 0; i < message.backtrace.size(); ++i) { if (message.backtrace.at(i).contains(QLatin1String("handleMessage"))) { removeUntil = i; break; } } if (removeUntil != -1) { message.backtrace = message.backtrace.mid(removeUntil + 1); } } if (!message.backtrace.isEmpty() && (qgetenv("GAMMARAY_UNITTEST") == "1" || type == QtFatalMsg)) { if (type == QtFatalMsg) { cerr << "QFatal in " << qPrintable(qApp->applicationName()) << " (" << qPrintable(qApp->applicationFilePath()) << ')' << endl; } cerr << "START BACKTRACE:" << endl; int i = 0; foreach (const QString &frame, message.backtrace) { cerr << (++i) << "\t" << frame << endl; } cerr << "END BACKTRACE" << endl; } if (type == QtFatalMsg && qgetenv("GAMMARAY_GDB") != "1" && qgetenv("GAMMARAY_UNITTEST") != "1") { // Enforce handling on the GUI thread and block until we are done. QMetaObject::invokeMethod(static_cast(s_model)->parent(), "handleFatalMessage", qApp->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection, Q_ARG(GammaRay::DebugMessage, message)); } // reset msg handler so the app still works as usual // but make sure we don't let other threads bypass our // handler during that time QMutexLocker lock(&s_mutex); s_handlerDisabled = true; if (s_handler) { // try a direct call to the previous handler first, that avoids triggering the recursion detection in Qt5 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) s_handler(type, context, msg); #else s_handler(type, rawMsg); #endif } else { installMessageHandler(s_handler); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) qt_message_output(type, context, msg); #else qt_message_output(type, rawMsg); #endif installMessageHandler(handleMessage); } s_handlerDisabled = false; lock.unlock(); if (s_model) { // add directly from foreground thread, delay from background thread QMetaObject::invokeMethod(s_model, "addMessage", Qt::AutoConnection, Q_ARG(GammaRay::DebugMessage, message)); } } MessageHandler::MessageHandler(ProbeInterface *probe, QObject *parent) : MessageHandlerInterface(parent), m_messageModel(new MessageModel(this)) { Q_ASSERT(s_model == 0); s_model = m_messageModel; probe->registerModel("com.kdab.GammaRay.MessageModel", m_messageModel); // install handler directly, catches most cases, // i.e. user has no special handler or the handler // is created before the QApplication ensureHandlerInstalled(); // recheck when eventloop is entered, if the user // installs a handler after QApp but before .exec() QMetaObject::invokeMethod(this, "ensureHandlerInstalled", Qt::QueuedConnection); } MessageHandler::~MessageHandler() { QMutexLocker lock(&s_mutex); s_model = 0; MessageHandlerCallback oldHandler = installMessageHandler(s_handler); if (oldHandler != handleMessage) { // ups, the app installed it's own handler after ours... installMessageHandler(oldHandler); } s_handler = 0; } void MessageHandler::ensureHandlerInstalled() { QMutexLocker lock(&s_mutex); if (s_handlerDisabled) { return; } MessageHandlerCallback prevHandler = installMessageHandler(handleMessage); if (prevHandler != handleMessage) { s_handler = prevHandler; } } void MessageHandler::handleFatalMessage(const DebugMessage &message) { const QString app = qApp->applicationName().isEmpty() ? qApp->applicationFilePath() : qApp->applicationName(); emit fatalMessageReceived(app, message.message, message.time, message.backtrace); if (Endpoint::isConnected()) { Endpoint::instance()->waitForMessagesWritten(); } } MessageHandlerFactory::MessageHandlerFactory(QObject* parent): QObject(parent) { } gammaray-2.3.0/core/tools/messagehandler/messagehandler.h000066400000000000000000000041221255003167400235210ustar00rootroot00000000000000/* messagehandler.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEHANDLER_MESSAGEHANDLER_H #define GAMMARAY_MESSAGEHANDLER_MESSAGEHANDLER_H #include "toolfactory.h" #include "messagehandlerinterface.h" namespace GammaRay { struct DebugMessage; class MessageModel; namespace Ui { class MessageHandler; } class MessageHandler : public MessageHandlerInterface { Q_OBJECT Q_INTERFACES(GammaRay::MessageHandlerInterface) public: explicit MessageHandler(ProbeInterface *probe, QObject *parent = 0); ~MessageHandler(); private slots: void ensureHandlerInstalled(); void handleFatalMessage(const GammaRay::DebugMessage &message); private: MessageModel *m_messageModel; }; class MessageHandlerFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit MessageHandlerFactory(QObject *parent); virtual inline QString name() const { return tr("Messages"); } }; } #endif // MESSAGEHANDLER_H gammaray-2.3.0/core/tools/messagehandler/messagehandlerinterface.cpp000066400000000000000000000026641255003167400257460ustar00rootroot00000000000000/* messagehandlerinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagehandlerinterface.h" #include "common/objectbroker.h" using namespace GammaRay; MessageHandlerInterface::MessageHandlerInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } MessageHandlerInterface::~MessageHandlerInterface() { } gammaray-2.3.0/core/tools/messagehandler/messagehandlerinterface.h000066400000000000000000000034071255003167400254070ustar00rootroot00000000000000/* messagehandlerinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEHANDLER_MESSAGEHANDLERINTERFACE_H #define GAMMARAY_MESSAGEHANDLER_MESSAGEHANDLERINTERFACE_H #include class QTime; namespace GammaRay { class MessageHandlerInterface : public QObject { Q_OBJECT public: explicit MessageHandlerInterface(QObject *parent = 0); virtual ~MessageHandlerInterface(); signals: void fatalMessageReceived(const QString &app, const QString &message, const QTime &time, const QStringList &backtrace); }; } Q_DECLARE_INTERFACE(GammaRay::MessageHandlerInterface, "com.kdab.GammaRay.MessageHandler") #endif // GAMMARAY_MESSAGEHANDLERINTERFACE_H gammaray-2.3.0/core/tools/messagehandler/messagemodel.cpp000066400000000000000000000100741255003167400235420ustar00rootroot00000000000000/* messagemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagemodel.h" #include using namespace GammaRay; QString typeToString(QtMsgType type) { switch(type) { case QtDebugMsg: return QObject::tr("Debug"); case QtWarningMsg: return QObject::tr("Warning"); case QtCriticalMsg: return QObject::tr("Critical"); case QtFatalMsg: return QObject::tr("Fatal"); default: return QObject::tr("Unknown"); // never reached in theory } } MessageModel::MessageModel(QObject *parent) : QAbstractTableModel(parent) { qRegisterMetaType(); } MessageModel::~MessageModel() { } void MessageModel::addMessage(const DebugMessage &message) { ///WARNING: do not trigger *any* kind of debug output here /// this would trigger an infinite loop and hence crash! beginInsertRows(QModelIndex(), m_messages.count(), m_messages.count()); m_messages << message; endInsertRows(); } int MessageModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return COLUMN_COUNT; } int MessageModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_messages.count(); } QVariant MessageModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() > rowCount() || index.column() > columnCount()) { return QVariant(); } const DebugMessage &msg = m_messages.at(index.row()); if (role == Qt::DisplayRole) { if (index.column() == TypeColumn) { return typeToString(msg.type); } else if (index.column() == MessageColumn) { ///TODO: elide return msg.message; } else if (index.column() == TimeColumn) { return msg.time.toString(); } } else if (role == Qt::ToolTipRole) { if (!msg.backtrace.isEmpty()) { QString bt; int i = 0; foreach (const QString &frame, msg.backtrace) { bt += QString("#%1: %2\n").arg(i, 2).arg(frame); ++i; } return tr("
" "
Type:
%1
" "
Time:
%2
" "
Message:
%3
" "
Backtrace:
%4
" "
").arg(typeToString(msg.type), msg.time.toString(), msg.message, bt); } else { return tr("
" "
Type:
%1
" "
Time:
%2
" "
Message:
%3
" "
").arg(typeToString(msg.type), msg.time.toString(), msg.message); } } return QVariant(); } QVariant MessageModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if (section == TypeColumn) { return tr("Type"); } else if (section == MessageColumn) { return tr("Message"); } else if (section == TimeColumn) { return tr("Time"); } } return QVariant(); } gammaray-2.3.0/core/tools/messagehandler/messagemodel.h000066400000000000000000000045151255003167400232120ustar00rootroot00000000000000/* messagemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEHANDLER_MESSAGEMODEL_H #define GAMMARAY_MESSAGEHANDLER_MESSAGEMODEL_H #include "backtrace.h" #include #include #include namespace GammaRay { struct DebugMessage { QtMsgType type; QString message; QTime time; Backtrace backtrace; }; } Q_DECLARE_METATYPE(GammaRay::DebugMessage) Q_DECLARE_TYPEINFO(GammaRay::DebugMessage, Q_MOVABLE_TYPE); namespace GammaRay { class MessageModel : public QAbstractTableModel { Q_OBJECT public: explicit MessageModel(QObject *parent = 0); ~MessageModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; enum Columns { TypeColumn, TimeColumn, MessageColumn, COLUMN_COUNT }; public slots: void addMessage(const GammaRay::DebugMessage &message); private: QVector m_messages; }; } #endif // MESSAGEMODEL_H gammaray-2.3.0/core/tools/metaobjectbrowser/000077500000000000000000000000001255003167400211265ustar00rootroot00000000000000gammaray-2.3.0/core/tools/metaobjectbrowser/metaobjectbrowser.cpp000066400000000000000000000043661255003167400253640ustar00rootroot00000000000000/* metaobjectbrowser.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaobjectbrowser.h" #include "metaobjecttreemodel.h" #include "probe.h" #include "propertycontroller.h" #include #include #include using namespace GammaRay; MetaObjectBrowser::MetaObjectBrowser(ProbeInterface *probe, QObject *parent) : QObject(parent), m_propertyController(new PropertyController("com.kdab.GammaRay.MetaObjectBrowser", this)) { Q_UNUSED(probe); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(Probe::instance()->metaObjectModel()); connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(objectSelected(QItemSelection))); m_propertyController->setMetaObject(0); // init } void MetaObjectBrowser::objectSelected(const QItemSelection &selection) { QModelIndex index; if (selection.size() == 1) index = selection.first().topLeft(); if (index.isValid()) { const QMetaObject *metaObject = index.data(MetaObjectTreeModel::MetaObjectRole).value(); m_propertyController->setMetaObject(metaObject); } else { m_propertyController->setMetaObject(0); } } gammaray-2.3.0/core/tools/metaobjectbrowser/metaobjectbrowser.h000066400000000000000000000037431255003167400250270ustar00rootroot00000000000000/* metaobjectbrowser.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAOBJECTBROWSER_METATYPEBROWSER_H #define GAMMARAY_METAOBJECTBROWSER_METATYPEBROWSER_H #include "toolfactory.h" class QItemSelection; namespace GammaRay { class PropertyController; class MetaObjectBrowser : public QObject { Q_OBJECT public: explicit MetaObjectBrowser(ProbeInterface *probe, QObject *parent = 0); private Q_SLOTS: void objectSelected(const QItemSelection &selection); private: PropertyController *m_propertyController; }; class MetaObjectBrowserFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit MetaObjectBrowserFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Meta Objects"); } }; } #endif // GAMMARAY_METAOBJECTBROWSER_METATYPEBROWSER_H gammaray-2.3.0/core/tools/metatypebrowser/000077500000000000000000000000001255003167400206415ustar00rootroot00000000000000gammaray-2.3.0/core/tools/metatypebrowser/metatypebrowser.cpp000066400000000000000000000027021255003167400246020ustar00rootroot00000000000000/* metatypebrowser.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metatypebrowser.h" #include "metatypesmodel.h" #include "common/objectbroker.h" using namespace GammaRay; MetaTypeBrowser::MetaTypeBrowser(ProbeInterface *probe, QObject *parent) : QObject(parent) { MetaTypesModel *mtm = new MetaTypesModel(this); probe->registerModel("com.kdab.GammaRay.MetaTypeModel", mtm); } gammaray-2.3.0/core/tools/metatypebrowser/metatypebrowser.h000066400000000000000000000034041255003167400242470ustar00rootroot00000000000000/* metatypebrowser.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METATYPEBROWSER_METATYPEBROWSER_H #define GAMMARAY_METATYPEBROWSER_METATYPEBROWSER_H #include "toolfactory.h" namespace GammaRay { class MetaTypeBrowser : public QObject { Q_OBJECT public: explicit MetaTypeBrowser(ProbeInterface *probe, QObject *parent = 0); }; class MetaTypeBrowserFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit MetaTypeBrowserFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Meta Types"); } }; } #endif // GAMMARAY_METATYPEBROWSER_H gammaray-2.3.0/core/tools/metatypebrowser/metatypesmodel.cpp000066400000000000000000000072351255003167400244100ustar00rootroot00000000000000/* metatypesmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metatypesmodel.h" #include #include #include MetaTypesModel::MetaTypesModel(QObject *parent) : QAbstractTableModel(parent) { scanMetaTypes(); // TODO do we need to re-run this when new types are registered at runtime? } QVariant MetaTypesModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole || !index.isValid()) { return QVariant(); } int metaTypeId = m_metaTypes.at(index.row()); switch (index.column()) { case 0: { QString name(QMetaType::typeName(metaTypeId)); if (name.isEmpty()) { return tr("N/A"); } return name; } case 1: return metaTypeId; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) case 2: return QMetaType::sizeOf(metaTypeId); case 3: return (QMetaType::metaObjectForType(metaTypeId) != 0); case 4: { const QMetaType::TypeFlags flags = QMetaType::typeFlags(metaTypeId); QStringList l; #define F(x) if (flags & QMetaType:: x) l.push_back(#x) F(NeedsConstruction); F(NeedsDestruction); F(MovableType); F(PointerToQObject); F(IsEnumeration); F(SharedPointerToQObject); F(WeakPointerToQObject); F(TrackingPointerToQObject); F(WasDeclaredAsMetaType); #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) F(IsGadget); #endif #undef F return l.join(", "); } #endif } return QVariant(); } int MetaTypesModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_metaTypes.size(); } int MetaTypesModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return 2; #else return 5; #endif } QVariant MetaTypesModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { return QVariant(); } switch (section) { case 0: return tr("Type Name"); case 1: return tr("Meta Type Id"); case 2: return tr("Size"); case 3: return tr("Meta Object"); case 4: return tr("Type Flags"); } return QVariant(); } void MetaTypesModel::scanMetaTypes() { beginResetModel(); m_metaTypes.clear(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) for (int mtId = 0; QMetaType::isRegistered(mtId); ++mtId) { m_metaTypes.push_back(mtId); } #else for (int mtId = 0; mtId <= QMetaType::User || QMetaType::isRegistered(mtId); ++mtId) { if (QMetaType::isRegistered(mtId)) { m_metaTypes.push_back(mtId); } } #endif endResetModel(); } gammaray-2.3.0/core/tools/metatypebrowser/metatypesmodel.h000066400000000000000000000035571255003167400240600ustar00rootroot00000000000000/* metatypesmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METATYPEBROWSER_METATYPESMODEL_H #define GAMMARAY_METATYPEBROWSER_METATYPESMODEL_H #include #include class MetaTypesModel : public QAbstractTableModel { Q_OBJECT public: explicit MetaTypesModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; private: void scanMetaTypes(); QVector m_metaTypes; }; #endif gammaray-2.3.0/core/tools/mimetypes/000077500000000000000000000000001255003167400174215ustar00rootroot00000000000000gammaray-2.3.0/core/tools/mimetypes/mimetypes.cpp000066400000000000000000000026351255003167400221470ustar00rootroot00000000000000/* mimetypes.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mimetypes.h" #include "mimetypesmodel.h" using namespace GammaRay; MimeTypes::MimeTypes(ProbeInterface *probe, QObject *parent) : QObject(parent) { m_model = new MimeTypesModel(this); probe->registerModel("com.kdab.GammaRay.MimeTypeModel", m_model); } MimeTypes::~MimeTypes() { } gammaray-2.3.0/core/tools/mimetypes/mimetypes.h000066400000000000000000000034511255003167400216110ustar00rootroot00000000000000/* mimetypes.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MIMETYPES_MIMETYPES_H #define GAMMARAY_MIMETYPES_MIMETYPES_H #include "core/toolfactory.h" class QStandardItemModel; namespace GammaRay { class MimeTypes : public QObject { Q_OBJECT public: explicit MimeTypes(ProbeInterface *probe, QObject *parent = 0); ~MimeTypes(); private: QStandardItemModel *m_model; }; class MimeTypesFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit MimeTypesFactory(QObject *parent) : QObject(parent) { } virtual inline QString name() const { return tr("Mime Types"); } }; } #endif // GAMMARAY_MIMETYPES_H gammaray-2.3.0/core/tools/mimetypes/mimetypesmodel.cpp000066400000000000000000000133741255003167400231720ustar00rootroot00000000000000/* mimetypesmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mimetypesmodel.h" #include #include using namespace GammaRay; MimeTypesModel::MimeTypesModel(QObject* parent): QStandardItemModel(parent), m_modelFilled(false) { } MimeTypesModel::~MimeTypesModel() { } QVariant MimeTypesModel::data(const QModelIndex& index, int role) const { if (index.isValid() && role == Qt::DecorationRole && index.column() == 3) { QStandardItem *item = itemFromIndex(index); if (!item) return QVariant(); // on-demand lookup of icons, too slow to do that all in one go const QVariant v = item->data(Qt::DecorationRole); if (v.isNull()) { const QString iconName = item->data(IconNameRole).toString(); const QString genericIconName = item->data(GenericIconNameRole).toString(); if (iconName.isEmpty() && genericIconName.isEmpty()) return QVariant(); QIcon icon = QIcon::fromTheme(item->data(IconNameRole).toString()); if (icon.isNull()) icon = QIcon::fromTheme(item->data(GenericIconNameRole).toString()); const_cast(this)->blockSignals(true); item->setIcon(icon); item->setData(QVariant(), IconNameRole); // reset to avoid trying to look up an icon multiple times item->setData(QVariant(), GenericIconNameRole); const_cast(this)->blockSignals(false); return icon; } else { return v; } } return QStandardItemModel::data(index, role); } Qt::ItemFlags MimeTypesModel::flags(const QModelIndex& index) const { return QStandardItemModel::flags(index) & ~Qt::ItemIsEditable; } int MimeTypesModel::rowCount(const QModelIndex& parent) const { const_cast(this)->fillModel(); return QStandardItemModel::rowCount(parent); } QVector MimeTypesModel::itemsForType(const QString &mimeTypeName) { if (m_mimeTypeNodes.contains(mimeTypeName)) { return m_mimeTypeNodes.value(mimeTypeName); } makeItemsForType(mimeTypeName); return m_mimeTypeNodes.value(mimeTypeName); } void MimeTypesModel::makeItemsForType(const QString &mimeTypeName) { const QMimeType mt = m_db.mimeTypeForName(mimeTypeName); if (mt.parentMimeTypes().isEmpty()) { const QList row = makeRowForType(mt); appendRow(row); m_mimeTypeNodes[mt.name()].push_back(row.first()); } else { // parentMimeTypes contains duplicates and aliases const QSet parentMimeTypeNames = normalizedMimeTypeNames(mt.parentMimeTypes()); foreach (const QString &parentTypeName, parentMimeTypeNames) { foreach (QStandardItem *parentItem, itemsForType(parentTypeName)) { const QList row = makeRowForType(mt); parentItem->appendRow(row); m_mimeTypeNodes[mt.name()].push_back(row.first()); } } } } QSet< QString > MimeTypesModel::normalizedMimeTypeNames(const QStringList &typeNames) const { QSet res; foreach (const QString &typeName, typeNames) { const QMimeType mt = m_db.mimeTypeForName(typeName); res.insert(mt.name()); } return res; } QList MimeTypesModel::makeRowForType(const QMimeType &mt) { QList row; QStandardItem *item = new QStandardItem; item->setText(mt.name()); row.push_back(item); item = new QStandardItem; item->setText(mt.comment()); row.push_back(item); item = new QStandardItem; item->setText(mt.globPatterns().join(QLatin1String(", "))); row.push_back(item); item = new QStandardItem; item->setText(mt.iconName() + QLatin1String(" / ") + mt.genericIconName()); item->setData(mt.iconName(), IconNameRole); item->setData(mt.genericIconName(), GenericIconNameRole); row.push_back(item); item = new QStandardItem; QString s = mt.suffixes().join(QLatin1String(", ")); if (!mt.preferredSuffix().isEmpty() && mt.suffixes().size() > 1) { s += QLatin1String(" (") + mt.preferredSuffix() + QLatin1Char(')'); } item->setText(s); row.push_back(item); item = new QStandardItem; item->setText(mt.aliases().join(QLatin1String(", "))); row.push_back(item); return row; } void MimeTypesModel::fillModel() { if (m_modelFilled) return; m_modelFilled = true; setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Comment") << tr("Glob Patterns") << tr("Icons") << tr("Suffixes") << tr("Aliases")); foreach (const QMimeType &mt, m_db.allMimeTypes()) { if (!m_mimeTypeNodes.contains(mt.name())) { makeItemsForType(mt.name()); } } m_mimeTypeNodes.clear(); } gammaray-2.3.0/core/tools/mimetypes/mimetypesmodel.h000066400000000000000000000043561255003167400226370ustar00rootroot00000000000000/* mimetypesmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MIMETYPES_MIMETYPESMODEL_H #define GAMMARAY_MIMETYPES_MIMETYPESMODEL_H #include "common/modelroles.h" #include #include namespace GammaRay { class MimeTypesModel : public QStandardItemModel { Q_OBJECT public: enum Roles { IconNameRole = UserRole + 1, GenericIconNameRole }; explicit MimeTypesModel(QObject *parent = 0); ~MimeTypesModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; private: void fillModel(); QVector itemsForType(const QString &mimeTypeName); void makeItemsForType(const QString &mimeTypeName); static QList makeRowForType(const QMimeType &mt); QSet normalizedMimeTypeNames(const QStringList &typeNames) const; QHash > m_mimeTypeNodes; QMimeDatabase m_db; bool m_modelFilled; }; } #endif // GAMMARAY_MIMETYPESMODEL_H gammaray-2.3.0/core/tools/modelinspector/000077500000000000000000000000001255003167400204345ustar00rootroot00000000000000gammaray-2.3.0/core/tools/modelinspector/modelcellmodel.cpp000066400000000000000000000121611255003167400241220ustar00rootroot00000000000000/* modelcellmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelcellmodel.h" #include "core/varianthandler.h" #include using namespace GammaRay; ModelCellModel::ModelCellModel(QObject *parent) : QAbstractTableModel(parent) { } static bool sourceIsQQmlListModel(const QAbstractItemModel* model) { Q_ASSERT(model); while (auto proxy = qobject_cast(model)) model = proxy->sourceModel(); return model->inherits("QQmlListModel"); } void ModelCellModel::setModelIndex(const QModelIndex &index) { beginResetModel(); m_index = index; m_roles.clear(); if (index.isValid()) { // add built-in roles const auto hasDefaultRoles = !sourceIsQQmlListModel(index.model()); if (hasDefaultRoles) { #define R(x) qMakePair(x, QLatin1String(#x)) m_roles << R(Qt::DisplayRole) << R(Qt::DecorationRole) << R(Qt::EditRole) << R(Qt::ToolTipRole) << R(Qt::StatusTipRole) << R(Qt::WhatsThisRole) << R(Qt::FontRole) << R(Qt::TextAlignmentRole) << R(Qt::BackgroundRole) << R(Qt::ForegroundRole) << R(Qt::CheckStateRole) << R(Qt::AccessibleTextRole) << R(Qt::AccessibleDescriptionRole) << R(Qt::SizeHintRole) << R(Qt::InitialSortOrderRole) ; #undef R } // add custom roles QHash roleNames = index.model()->roleNames(); for (QHash::const_iterator it = roleNames.constBegin(); it != roleNames.constEnd(); ++it) { bool roleFound = false; for (int i = 0; i < m_roles.size(); ++i) { if (m_roles.at(i).first == it.key()) { roleFound = true; break; } } if (!roleFound) { m_roles.push_back(qMakePair(it.key(), QString::fromLatin1(it.value()))); } } } endResetModel(); } QVariant ModelCellModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } Q_ASSERT(index.row() < m_roles.size()); const QVariant value = m_index.data(m_roles.at(index.row()).first); if (role == Qt::DisplayRole) { switch(index.column()) { case 0: return m_roles.at(index.row()).second; case 1: return VariantHandler::displayString(value); case 2: return value.typeName(); } } else if (role == Qt::EditRole) { if (index.column() == 1) { return value; } } return QVariant(); } bool ModelCellModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && m_index.isValid() && (m_index.flags() & Qt::ItemIsEditable) && role == Qt::EditRole && index.column() == 1) { const Qt::ItemDataRole sourceRole = static_cast(m_roles.at(index.row()).first); QAbstractItemModel *sourceModel = const_cast(m_index.model()); return sourceModel->setData(m_index, value, sourceRole); } return QAbstractItemModel::setData(index, value, role); } Qt::ItemFlags ModelCellModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractTableModel::flags(index); if (index.isValid() && m_index.isValid() && index.column() == 1) { if (m_index.flags() & Qt::ItemIsEditable) { return flags | Qt::ItemIsEditable; } } return flags; } int ModelCellModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return 3; } int ModelCellModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !m_index.isValid()) { return 0; } return m_roles.size(); } QVariant ModelCellModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Role"); case 1: return tr("Value"); case 2: return tr("Type"); } } return QAbstractItemModel::headerData(section, orientation, role); } gammaray-2.3.0/core/tools/modelinspector/modelcellmodel.h000066400000000000000000000042051255003167400235670ustar00rootroot00000000000000/* modelcellmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTOR_MODELCELLMODEL_H #define GAMMARAY_MODELINSPECTOR_MODELCELLMODEL_H #include #include namespace GammaRay { class ModelCellModel : public QAbstractTableModel { Q_OBJECT public: explicit ModelCellModel(QObject *parent = 0); void setModelIndex(const QModelIndex &index); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QPersistentModelIndex m_index; QVector > m_roles; }; } #endif // GAMMARAY_MODELCELLMODEL_H gammaray-2.3.0/core/tools/modelinspector/modelinspector.cpp000066400000000000000000000121251255003167400241700ustar00rootroot00000000000000/* modelinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelinspector.h" #include "modelmodel.h" #include "modelcellmodel.h" #include "modeltester.h" #include "safetyfilterproxymodel.h" #include "probeinterface.h" #include "common/objectbroker.h" #include "remote/remotemodelserver.h" #include "remote/selectionmodelserver.h" #include using namespace GammaRay; ModelInspector::ModelInspector(ProbeInterface* probe, QObject *parent) : ModelInspectorInterface(parent), m_modelModel(0), m_modelContentServer(0), m_modelContentSelectionModel(0), m_safetyFilterProxyModel(0), m_modelTester(0) { m_modelModel = new ModelModel(this); connect(probe->probe(), SIGNAL(objectCreated(QObject*)), m_modelModel, SLOT(objectAdded(QObject*))); connect(probe->probe(), SIGNAL(objectDestroyed(QObject*)), m_modelModel, SLOT(objectRemoved(QObject*))); probe->registerModel("com.kdab.GammaRay.ModelModel", m_modelModel); m_modelSelectionModel = ObjectBroker::selectionModel(m_modelModel); connect(m_modelSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(modelSelected(QItemSelection))); connect(probe->probe(), SIGNAL(objectSelected(QObject*,QPoint)), SLOT(objectSelected(QObject*)) ); m_modelContentServer = new RemoteModelServer("com.kdab.GammaRay.ModelContent", this); m_cellModel = new ModelCellModel(this); probe->registerModel("com.kdab.GammaRay.ModelCellModel", m_cellModel); selectionChanged(QItemSelection()); m_modelTester = new ModelTester(this); connect(probe->probe(), SIGNAL(objectCreated(QObject*)), m_modelTester, SLOT(objectAdded(QObject*))); } QString ModelInspectorFactory::name() const { return tr("Models"); } void ModelInspector::modelSelected(const QItemSelection& selected) { if (m_modelContentSelectionModel && m_modelContentSelectionModel->model()) ObjectBroker::unregisterSelectionModel(m_modelContentSelectionModel); delete m_modelContentSelectionModel; m_modelContentSelectionModel = 0; QModelIndex index; if (selected.size() >= 1) index = selected.first().topLeft(); if (index.isValid()) { QObject *obj = index.data(ObjectModel::ObjectRole).value(); QAbstractItemModel *model = qobject_cast(obj); if (model->inherits("QQmlListModel")) { if (!m_safetyFilterProxyModel) m_safetyFilterProxyModel = new SafetyFilterProxyModel(this); m_safetyFilterProxyModel->setSourceModel(model); m_modelContentServer->setModel(m_safetyFilterProxyModel); } else { m_modelContentServer->setModel(model); } m_modelContentSelectionModel = new SelectionModelServer("com.kdab.GammaRay.ModelContent.selection", m_modelContentServer->model(), this); ObjectBroker::registerSelectionModel(m_modelContentSelectionModel); connect(m_modelContentSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged(QItemSelection))); } else { m_modelContentServer->setModel(0); } // clear the cell info box selectionChanged(QItemSelection()); } void ModelInspector::objectSelected(QObject* object) { QAbstractItemModel *selectedModel = qobject_cast(object); if (selectedModel) { const QModelIndexList indexList = m_modelModel->match(m_modelModel->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(selectedModel), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_modelSelectionModel->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } } void ModelInspector::selectionChanged(const QItemSelection& selected) { QModelIndex index; if (selected.size() >= 1) index = selected.first().topLeft(); m_cellModel->setModelIndex(index); emit cellSelected(index.row(), index.column(), QString::number(index.internalId()), Util::addressToString(index.internalPointer())); } gammaray-2.3.0/core/tools/modelinspector/modelinspector.h000066400000000000000000000047371255003167400236470ustar00rootroot00000000000000/* modelinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTOR_MODELINSPECTOR_H #define GAMMARAY_MODELINSPECTOR_MODELINSPECTOR_H #include "toolfactory.h" #include "common/modelinspectorinterface.h" class QItemSelection; class QItemSelectionModel; class SafetyFilterProxyModel; namespace GammaRay { class ModelModel; class ModelCellModel; class ModelTester; class RemoteModelServer; class ModelInspector : public ModelInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::ModelInspectorInterface) public: explicit ModelInspector(ProbeInterface *probe, QObject *parent = 0); private slots: void modelSelected(const QItemSelection &selected); void selectionChanged(const QItemSelection &selected); void objectSelected(QObject* object); private: ModelModel *m_modelModel; QItemSelectionModel *m_modelSelectionModel; RemoteModelServer *m_modelContentServer; QItemSelectionModel *m_modelContentSelectionModel; SafetyFilterProxyModel *m_safetyFilterProxyModel; ModelCellModel *m_cellModel; ModelTester *m_modelTester; }; class ModelInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit ModelInspectorFactory(QObject *parent) : QObject(parent) { } QString name() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_MODELINSPECTOR_H gammaray-2.3.0/core/tools/modelinspector/modelmodel.cpp000066400000000000000000000111171255003167400232620ustar00rootroot00000000000000/* modelmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelmodel.h" using namespace GammaRay; ModelModel::ModelModel(QObject *parent) : ObjectModelBase(parent) { } QVariant ModelModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QAbstractItemModel *model = static_cast(index.internalPointer()); if (!model) { return QVariant(); } return dataForObject(model, index, role); } int ModelModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { QAbstractItemModel *sourceModel = static_cast(parent.internalPointer()); Q_ASSERT(sourceModel); const QVector proxies = proxiesForModel(sourceModel); return proxies.size(); } return m_models.size(); } QModelIndex ModelModel::parent(const QModelIndex &child) const { QAbstractItemModel *model = static_cast(child.internalPointer()); Q_ASSERT(model); if (m_models.contains(model)) { return QModelIndex(); } QAbstractProxyModel *proxy = qobject_cast(model); Q_ASSERT(proxy); return indexForModel(proxy->sourceModel()); } QModelIndex ModelModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) { QAbstractItemModel *model = static_cast(parent.internalPointer()); const QVector proxies = proxiesForModel(model); if (proxies.size() <= row) { return QModelIndex(); } return createIndex(row, column, proxies.at(row)); } return createIndex(row, column, m_models.at(row)); } void ModelModel::objectAdded(QObject *obj) { QAbstractProxyModel *proxy = qobject_cast(obj); if (proxy) { beginResetModel(); // FIXME m_proxies.push_back(proxy); endResetModel(); return; } QAbstractItemModel *model = qobject_cast(obj); if (model) { beginInsertRows(QModelIndex(), m_models.size(), m_models.size()); m_models.push_back(model); endInsertRows(); } } void ModelModel::objectRemoved(QObject *obj) { int index = m_models.indexOf(static_cast(obj)); if (index >= 0 && index < m_models.size()) { beginRemoveRows(QModelIndex(), index, index); m_models.remove(index); endRemoveRows(); } for (QVector::iterator it = m_proxies.begin(); it != m_proxies.end(); ++it) { if (*it == obj) { beginResetModel(); // FIXME m_proxies.erase(it); endResetModel(); return; } } } QModelIndex ModelModel::indexForModel(QAbstractItemModel *model) const { if (!model) { return QModelIndex(); } QAbstractProxyModel *proxy = qobject_cast(model); if (!proxy) { Q_ASSERT(m_models.contains(model)); return index(m_models.indexOf(model), 0, QModelIndex()); } QAbstractItemModel *sourceModel = proxy->sourceModel(); const QModelIndex parentIndex = indexForModel(sourceModel); const QVector proxies = proxiesForModel(sourceModel); Q_ASSERT(proxies.contains(proxy)); return index(proxies.indexOf(proxy), 0, parentIndex); } QVector ModelModel::proxiesForModel(QAbstractItemModel* model) const { QVector proxies; if (!model) { return proxies; } foreach (QAbstractProxyModel *proxy, m_proxies) { if (proxy && proxy->sourceModel() == model) { proxies.push_back(proxy); } } return proxies; } gammaray-2.3.0/core/tools/modelinspector/modelmodel.h000066400000000000000000000043071255003167400227320ustar00rootroot00000000000000/* modelmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTOR_MODELMODEL_H #define GAMMARAY_MODELINSPECTOR_MODELMODEL_H #include "objectmodelbase.h" #include #include #include #include namespace GammaRay { class ModelModel : public ObjectModelBase { Q_OBJECT public: explicit ModelModel(QObject *parent); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; public slots: void objectAdded(QObject *obj); void objectRemoved(QObject *obj); private: QModelIndex indexForModel(QAbstractItemModel *model) const; QVector proxiesForModel(QAbstractItemModel *model) const; private: QVector m_models; QVector m_proxies; }; } #endif // MODELMODEL_H gammaray-2.3.0/core/tools/modelinspector/modeltester.cpp000066400000000000000000000074451255003167400235010ustar00rootroot00000000000000/* modeltester.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modeltester.h" #include <3rdparty/qt/modeltest.h> #include "util.h" #include #include #include using namespace GammaRay; namespace GammaRay { struct ModelTester::ModelTestResult { ModelTestResult() : modelTest(0) { } ~ModelTestResult() { delete modelTest; } ModelTest *modelTest; QHash failures; }; } ModelTester::ModelTester(QObject *parent) : QObject(parent) { } void ModelTester::objectAdded(QObject *obj) { QAbstractItemModel *model = qobject_cast(obj); if (model) { // TODO filter out our own models, way too slow otherwise // or even better allow to specify somehow to which models we want to attach connect(model, SIGNAL(destroyed(QObject*)), SLOT(modelDestroyed(QObject*))); ModelTestResult *result = new ModelTestResult; m_modelTestMap.insert(model, result); // needs to be available for the // initial calls to failure() already // FIXME too slow! // result->modelTest = new ModelTest(model, this); } } void ModelTester::modelDestroyed(QObject *model) { if (m_modelTestMap.contains(static_cast(model))) { delete m_modelTestMap.take(static_cast(model)); } } void ModelTester::failure(QAbstractItemModel *model, const char *file, int line, const char *message) { ModelTestResult *result = m_modelTestMap.value(model); Q_ASSERT(result || qgetenv("GAMMARAY_UNITTEST") == "1"); if (!result) { // one of our own models qt_assert(message, file, line); } ///TODO: track file if (!result->failures.contains(line)) { std::cout << qPrintable(Util::displayString(model)) << " " << line << " " << message << std::endl; result->failures.insert(line, QString::fromLatin1(message)); } } // inplace build of modeltest, with some slight modificatins: // - change QVERIFY to non-fatal reporting // - suppress qDebug etc, since those trigger qobject creating and thus // infinite loops when model-testing the object model //krazy:cond=includes #include // avoid interference with any include used by modeltest #define QT_QTTEST_MODULE_H #undef QVERIFY #undef QCOMPARE #define QVERIFY(x) (!(x) ? static_cast(static_cast(this)->parent())->failure(this->model, __FILE__, __LINE__, #x) : qt_noop()) #define QCOMPARE(x, y) ((x != y) ? static_cast(static_cast(this)->parent())->failure(this->model, __FILE__, __LINE__, #x) : qt_noop()) #undef qDebug #define qDebug() QNoDebug() #include <3rdparty/qt/modeltest.cpp> //krazy:endcond=includes gammaray-2.3.0/core/tools/modelinspector/modeltester.h000066400000000000000000000034221255003167400231350ustar00rootroot00000000000000/* modeltester.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTOR_MODELTESTER_H #define GAMMARAY_MODELINSPECTOR_MODELTESTER_H #include #include #include class QAbstractItemModel; class ModelTest; namespace GammaRay { class ModelTester : public QObject { Q_OBJECT public: explicit ModelTester(QObject *parent = 0); void failure(QAbstractItemModel *model, const char *file, int line, const char *message); public slots: void objectAdded(QObject *obj); private slots: void modelDestroyed(QObject *model); private: struct ModelTestResult; QHash m_modelTestMap; }; } #endif // GAMMARAY_MODELTESTER_H gammaray-2.3.0/core/tools/modelinspector/safetyfilterproxymodel.cpp000066400000000000000000000034121255003167400257640ustar00rootroot00000000000000/* safetyfilterproxymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "safetyfilterproxymodel.h" SafetyFilterProxyModel::SafetyFilterProxyModel(QObject* parent): QIdentityProxyModel(parent) { } SafetyFilterProxyModel::~SafetyFilterProxyModel() { } QVariant SafetyFilterProxyModel::data(const QModelIndex& proxyIndex, int role) const { if (sourceModel() && sourceModel()->inherits("QQmlListModel")) { // data on anything not in roleNames() crashes if (!sourceModel()->roleNames().contains(role)) { if (role == Qt::DisplayRole) return QLatin1String("CRASH GUARD"); return QVariant(); } } return QAbstractProxyModel::data(proxyIndex, role); } gammaray-2.3.0/core/tools/modelinspector/safetyfilterproxymodel.h000066400000000000000000000031731255003167400254350ustar00rootroot00000000000000/* safetyfilterproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef SAFETYFILTERPROXYMODEL_H #define SAFETYFILTERPROXYMODEL_H #include /** This model prevents data() calls known to crash specific source models, * such as QQmlListModel. */ class SafetyFilterProxyModel : public QIdentityProxyModel { Q_OBJECT public: explicit SafetyFilterProxyModel(QObject *parent = 0); ~SafetyFilterProxyModel(); QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; }; #endif // SAFETYFILTERPROXYMODEL_H gammaray-2.3.0/core/tools/objectinspector/000077500000000000000000000000001255003167400206025ustar00rootroot00000000000000gammaray-2.3.0/core/tools/objectinspector/abstractconnectionsmodel.cpp000066400000000000000000000133761255003167400264070ustar00rootroot00000000000000/* abstractconnectionsmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "abstractconnectionsmodel.h" #include "common/tools/objectinspector/connectionsmodelroles.h" #include "core/util.h" #include #include using namespace GammaRay; AbstractConnectionsModel::AbstractConnectionsModel(QObject *parent): QAbstractTableModel(parent) { } AbstractConnectionsModel::~AbstractConnectionsModel() { } int AbstractConnectionsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } int AbstractConnectionsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_connections.size(); } QVariant AbstractConnectionsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); const Connection &conn = m_connections.at(index.row()); if (role == Qt::DisplayRole && index.column() == 3) { switch (conn.type) { // see qobject_p.h case 0: if (!conn.endpoint || !m_object) return tr("Auto"); return tr("Auto (%1)").arg(conn.endpoint->thread() == m_object->thread() ? "Direct" : "Queued"); case 1: return tr("Direct"); case 2: return tr("Queued"); case 3: // Qt5 case 4: // Qt4 return tr("Blocking"); default: return tr("Unknown: %1").arg(conn.type); } } if (role == ConnectionsModelRoles::WarningFlagRole && index.column() == 0) { return isDuplicate(conn) || isDirectCrossThreadConnection(conn); } if (role == Qt::ToolTipRole) { QStringList tips; if (isDuplicate(conn)) tips << tr("Connections exists multiple times.\nThe connected slot is called multiple times when the signal is emitted."); if (isDirectCrossThreadConnection(conn)) tips << tr("Direct cross-thread connection.\nThe connected slot is called in the context of the emitting thread."); if (!tips.isEmpty()) return tips.join("\n\n"); } if (role == ConnectionsModelRoles::EndpointRole) { return QVariant::fromValue(conn.endpoint.data()); } if (role == ConnectionsModelRoles::ActionRole) { if (conn.endpoint && conn.endpoint != m_object) return ConnectionsModelActions::NavigateToEndpoint; return ConnectionsModelActions::NoAction; } return QVariant(); } QVariant AbstractConnectionsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section == 3 && orientation == Qt::Horizontal && role == Qt::DisplayRole) return tr("Type"); return QAbstractItemModel::headerData(section, orientation, role); } QString AbstractConnectionsModel::displayString(QObject *object, int methodIndex) { if (!object) return QObject::tr(""); if (methodIndex < 0) return QObject::tr(""); const QMetaMethod method = object->metaObject()->method(methodIndex); return Util::prettyMethodSignature(method); } QString AbstractConnectionsModel::displayString(QObject* object) { if (!object) return QObject::tr(""); return Util::displayString(object); } int AbstractConnectionsModel::signalIndexToMethodIndex(QObject* object, int signalIndex) { if (signalIndex < 0) return signalIndex; Q_ASSERT(object); return Util::signalIndexToMethodIndex(object->metaObject(), signalIndex); } QMap< int, QVariant > AbstractConnectionsModel::itemData(const QModelIndex& index) const { QMap d = QAbstractTableModel::itemData(index); d.insert(ConnectionsModelRoles::WarningFlagRole, data(index, ConnectionsModelRoles::WarningFlagRole)); d.insert(ConnectionsModelRoles::ActionRole, data(index, ConnectionsModelRoles::ActionRole)); return d; } bool AbstractConnectionsModel::isDuplicate(const Connection& conn) const { foreach (const Connection &c, m_connections) { if (&c == &conn) continue; if (c.endpoint == conn.endpoint && c.slotIndex >= 0 && c.slotIndex == conn.slotIndex && c.signalIndex >= 0 && c.signalIndex == conn.signalIndex) return true; } return false; } bool AbstractConnectionsModel::isDirectCrossThreadConnection(const Connection& conn) const { if (!conn.endpoint || !m_object || conn.endpoint->thread() == m_object->thread()) return false; return conn.type == 1; // direct } void AbstractConnectionsModel::clear() { if (m_connections.isEmpty()) return; beginRemoveRows(QModelIndex(), 0, m_connections.size() - 1); m_connections.clear(); endRemoveRows(); } void AbstractConnectionsModel::setConnections(const QVector& connections) { Q_ASSERT(m_connections.isEmpty()); if (connections.isEmpty()) return; beginInsertRows(QModelIndex(), 0, connections.size() - 1); m_connections = connections; endInsertRows(); } gammaray-2.3.0/core/tools/objectinspector/abstractconnectionsmodel.h000066400000000000000000000053461255003167400260520ustar00rootroot00000000000000/* abstractconnectionsmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_ABSTRACTCONNECTIONSMODEL_H #define GAMMARAY_OBJECTINSPECTOR_ABSTRACTCONNECTIONSMODEL_H #include #include #include namespace GammaRay { /** Common base class for the inbound and outbound connections models. */ class AbstractConnectionsModel : public QAbstractTableModel { Q_OBJECT public: explicit AbstractConnectionsModel(QObject *parent = 0); ~AbstractConnectionsModel(); virtual void setObject(QObject *object) = 0; int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap< int, QVariant > itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; protected: struct Connection { QPointer endpoint; int signalIndex; int slotIndex; int type; }; static QString displayString(QObject *object, int methodIndex); static QString displayString(QObject *object); static int signalIndexToMethodIndex(QObject *object, int signalIndex); void clear(); void setConnections(const QVector& connections); protected: QPointer m_object; QVector m_connections; private: bool isDuplicate(const Connection &conn) const; bool isDirectCrossThreadConnection(const Connection &conn) const; }; } #endif // GAMMARAY_ABSTRACTCONNECTIONSMODEL_H gammaray-2.3.0/core/tools/objectinspector/classinfoextension.cpp000066400000000000000000000036011255003167400252240ustar00rootroot00000000000000/* classinfoextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "classinfoextension.h" #include "connectionfilterproxymodel.h" #include "propertycontroller.h" #include "probe.h" #include "objectclassinfomodel.h" #include using namespace GammaRay; ClassInfoExtension::ClassInfoExtension(PropertyController* controller) : PropertyControllerExtension(controller->objectBaseName() + ".classInfo"), m_model(new ObjectClassInfoModel(controller)) { controller->registerModel(m_model, "classInfo"); } ClassInfoExtension::~ClassInfoExtension() { } bool ClassInfoExtension::setQObject(QObject* object) { m_model->setMetaObject(object ? object->metaObject() : 0); return true; } bool ClassInfoExtension::setMetaObject(const QMetaObject* metaObject) { m_model->setMetaObject(metaObject); return true; } gammaray-2.3.0/core/tools/objectinspector/classinfoextension.h000066400000000000000000000033311255003167400246710ustar00rootroot00000000000000/* classinfoextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_CLASSINFOEXTENSION_H #define GAMMARAY_OBJECTINSPECTOR_CLASSINFOEXTENSION_H #include "propertycontrollerextension.h" namespace GammaRay { class PropertyController; class ObjectClassInfoModel; class ClassInfoExtension : public PropertyControllerExtension { public: explicit ClassInfoExtension(PropertyController *controller); ~ClassInfoExtension(); bool setQObject(QObject *object) Q_DECL_OVERRIDE; bool setMetaObject(const QMetaObject *metaObject) Q_DECL_OVERRIDE; private: ObjectClassInfoModel *m_model; }; } #endif // CLASSINFOEXTENSION_H gammaray-2.3.0/core/tools/objectinspector/connectionsextension.cpp000066400000000000000000000063311255003167400255700ustar00rootroot00000000000000/* connectionsextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionsextension.h" #include "inboundconnectionsmodel.h" #include "outboundconnectionsmodel.h" #include #include #include #include using namespace GammaRay; ConnectionsExtension::ConnectionsExtension(PropertyController* controller): ConnectionsExtensionInterface(controller->objectBaseName() + ".connectionsExtension", controller), PropertyControllerExtension(controller->objectBaseName() + ".connections") { #ifndef USE_QT_CONNECTIONS_LIST m_inboundModel = new ConnectionFilterProxyModel(controller); m_outboundModel = new ConnectionFilterProxyModel(controller); m_inboundModel->setFilterOnReceiver(true); m_outboundModel->setFilterOnSender(true); m_inboundModel->setSourceModel(Probe::instance()->connectionModel()); m_outboundModel->setSourceModel(Probe::instance()->connectionModel()); #else m_inboundModel = new InboundConnectionsModel(controller); m_outboundModel = new OutboundConnectionsModel(controller); #endif controller->registerModel(m_inboundModel, "inboundConnections"); controller->registerModel(m_outboundModel, "outboundConnections"); } ConnectionsExtension::~ConnectionsExtension() { } bool ConnectionsExtension::setQObject(QObject* object) { #ifndef USE_QT_CONNECTIONS_LIST m_inboundModel->filterReceiver(object); m_outboundModel->filterSender(object); #else m_inboundModel->setObject(object); m_outboundModel->setObject(object); #endif return true; } void ConnectionsExtension::navigateToSender(int modelRow) { const QModelIndex index = m_inboundModel->index(modelRow, 0); QObject* sender = index.data(ConnectionsModelRoles::EndpointRole).value(); if (!sender) return; Probe::instance()->selectObject(sender); } void ConnectionsExtension::navigateToReceiver(int modelRow) { const QModelIndex index = m_outboundModel->index(modelRow, 0); QObject* receiver = index.data(ConnectionsModelRoles::EndpointRole).value(); if (!receiver) return; Probe::instance()->selectObject(receiver); } gammaray-2.3.0/core/tools/objectinspector/connectionsextension.h000066400000000000000000000045031255003167400252340ustar00rootroot00000000000000/* connectionsextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_CONNECTIONSEXTENSION_H #define GAMMARAY_OBJECTINSPECTOR_CONNECTIONSEXTENSION_H #include "common/tools/objectinspector/connectionsextensioninterface.h" #include "core/propertycontrollerextension.h" #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #define USE_QT_CONNECTIONS_LIST #endif namespace GammaRay { class ConnectionFilterProxyModel; class InboundConnectionsModel; class OutboundConnectionsModel; class ConnectionsExtension : public ConnectionsExtensionInterface, public PropertyControllerExtension { Q_OBJECT Q_INTERFACES(GammaRay::ConnectionsExtensionInterface) public: explicit ConnectionsExtension(PropertyController *controller); ~ConnectionsExtension(); bool setQObject(QObject *object) Q_DECL_OVERRIDE; public slots: void navigateToReceiver(int modelRow) Q_DECL_OVERRIDE; void navigateToSender(int modelRow) Q_DECL_OVERRIDE; private: #ifndef USE_QT_CONNECTIONS_LIST ConnectionFilterProxyModel *m_inboundModel; ConnectionFilterProxyModel *m_outboundModel; #else InboundConnectionsModel *m_inboundModel; OutboundConnectionsModel *m_outboundModel; #endif }; } #endif // GAMMARAY_CONNECTIONSEXTENSION_H gammaray-2.3.0/core/tools/objectinspector/enumsextension.cpp000066400000000000000000000035171255003167400244000ustar00rootroot00000000000000/* enumsextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "enumsextension.h" #include "connectionfilterproxymodel.h" #include "propertycontroller.h" #include "probe.h" #include #include using namespace GammaRay; EnumsExtension::EnumsExtension(PropertyController* controller) : PropertyControllerExtension(controller->objectBaseName() + ".enums"), m_model(new ObjectEnumModel(controller)) { controller->registerModel(m_model, "enums"); } EnumsExtension::~EnumsExtension() { } bool EnumsExtension::setQObject(QObject* object) { m_model->setMetaObject(object ? object->metaObject() : 0); return true; } bool EnumsExtension::setMetaObject(const QMetaObject* metaObject) { m_model->setMetaObject(metaObject); return true; } gammaray-2.3.0/core/tools/objectinspector/enumsextension.h000066400000000000000000000032631255003167400240430ustar00rootroot00000000000000/* enumsextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_ENUMSEXTENSION_H #define GAMMARAY_OBJECTINSPECTOR_ENUMSEXTENSION_H #include "propertycontrollerextension.h" namespace GammaRay { class PropertyController; class ObjectEnumModel; class EnumsExtension : public PropertyControllerExtension { public: explicit EnumsExtension(PropertyController *controller); ~EnumsExtension(); bool setQObject(QObject *object) Q_DECL_OVERRIDE; bool setMetaObject(const QMetaObject *metaObject) Q_DECL_OVERRIDE; private: ObjectEnumModel *m_model; }; } #endif // ENUMSEXTENSION_H gammaray-2.3.0/core/tools/objectinspector/inboundconnectionsmodel.cpp000066400000000000000000000102531255003167400262310ustar00rootroot00000000000000/* inboundconnectionsmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "inboundconnectionsmodel.h" #include "core/probe.h" #ifdef HAVE_PRIVATE_QT_HEADERS #include #endif using namespace GammaRay; InboundConnectionsModel::InboundConnectionsModel(QObject* parent): AbstractConnectionsModel(parent) { } InboundConnectionsModel::~InboundConnectionsModel() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) && defined(HAVE_PRIVATE_QT_HEADERS) static int signalIndexForConnection(QObjectPrivate::Connection *connection, QObject *sender) { QObjectPrivate *d = QObjectPrivate::get(sender); if (!d->connectionLists) return -1; // HACK: the declaration of d->connectionsLists is not accessible for us... const QVector *cl = reinterpret_cast*>(d->connectionLists); for (int signalIndex = 0; signalIndex < cl->count(); ++signalIndex) { const QObjectPrivate::Connection *c = cl->at(signalIndex).first; while (c) { if (c == connection) return signalIndex; c = c->nextConnectionList; continue; } } return -1; } #endif void InboundConnectionsModel::setObject(QObject* object) { clear(); m_object = object; if (!object) return; QVector connections; #ifdef HAVE_PRIVATE_QT_HEADERS QObjectPrivate *d = QObjectPrivate::get(object); if (d->senders) { for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { if (!s->sender || Probe::instance()->filterObject(s->sender)) continue; Connection conn; conn.endpoint = s->sender; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) conn.signalIndex = signalIndexToMethodIndex(s->sender, s->signal_index); if (s->isSlotObject) { conn.slotIndex = -1; } else { conn.slotIndex = s->method(); } #else conn.slotIndex = s->method(); conn.signalIndex = signalIndexToMethodIndex(s->sender, signalIndexForConnection(s, s->sender)); #endif conn.type = s->connectionType; connections.push_back(conn); } } #endif setConnections(connections); } QVariant InboundConnectionsModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || !m_object) return QVariant(); if (role == Qt::DisplayRole) { const Connection &conn = m_connections.at(index.row()); switch (index.column()) { case 0: return displayString(conn.endpoint); case 1: return displayString(conn.endpoint, conn.signalIndex); case 2: if (conn.slotIndex < 0) return tr(""); return displayString(m_object, conn.slotIndex); } } return AbstractConnectionsModel::data(index, role); } QVariant InboundConnectionsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Sender"); case 1: return tr("Signal"); case 2: return tr("Slot"); } } return AbstractConnectionsModel::headerData(section, orientation, role); } gammaray-2.3.0/core/tools/objectinspector/inboundconnectionsmodel.h000066400000000000000000000035071255003167400257020ustar00rootroot00000000000000/* inboundconnectionsmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_INBOUNDCONNECTIONSMODEL_H #define GAMMARAY_OBJECTINSPECTOR_INBOUNDCONNECTIONSMODEL_H #include "abstractconnectionsmodel.h" namespace GammaRay { /** List of inbound connections on a given QObject. */ class InboundConnectionsModel : public AbstractConnectionsModel { Q_OBJECT public: explicit InboundConnectionsModel(QObject *parent = 0); ~InboundConnectionsModel(); void setObject(QObject *object) Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_INBOUNDCONNECTIONSMODEL_H gammaray-2.3.0/core/tools/objectinspector/methodsextension.cpp000066400000000000000000000134311255003167400247100ustar00rootroot00000000000000/* methodsextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodsextension.h" #include "objectmethodmodel.h" #include "propertycontroller.h" #include "varianthandler.h" #include "methodargumentmodel.h" #include "multisignalmapper.h" #include "common/objectbroker.h" #include #include #include #include using namespace GammaRay; MethodsExtension::MethodsExtension(PropertyController* controller) : MethodsExtensionInterface(controller->objectBaseName() + ".methodsExtension", controller), PropertyControllerExtension(controller->objectBaseName() + ".methods"), m_model(new ObjectMethodModel(controller)), m_methodLogModel(new QStandardItemModel(this)), m_methodArgumentModel(new MethodArgumentModel(this)), m_signalMapper(0) { controller->registerModel(m_model, "methods"); controller->registerModel(m_methodLogModel, "methodLog"); controller->registerModel(m_methodArgumentModel, "methodArguments"); ObjectBroker::selectionModel(m_model); // trigger creation } MethodsExtension::~MethodsExtension() { } bool MethodsExtension::setQObject(QObject* object) { if (m_object == object) return true; m_object = object; m_model->setMetaObject(object ? object->metaObject() : 0); delete m_signalMapper; m_signalMapper = new MultiSignalMapper(this); connect(m_signalMapper, SIGNAL(signalEmitted(QObject*,int,QVector)), SLOT(signalEmitted(QObject*,int,QVector))); if (m_methodLogModel->rowCount() > 0) m_methodLogModel->clear(); setHasObject(true); return true; } bool MethodsExtension::setMetaObject(const QMetaObject* metaObject) { m_object = 0; m_model->setMetaObject(metaObject); setHasObject(false); return true; } void MethodsExtension::signalEmitted(QObject* sender, int signalIndex, const QVector& args) { Q_ASSERT(m_object == sender); QStringList prettyArgs; prettyArgs.reserve(args.size()); foreach (const QVariant &v, args) prettyArgs.push_back(VariantHandler::displayString(v)); m_methodLogModel->appendRow( new QStandardItem(tr("%1: Signal %2 emitted, arguments: %3"). arg(QTime::currentTime().toString("HH:mm:ss.zzz")). #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) arg(sender->metaObject()->method(signalIndex).signature()) #else arg(QString(sender->metaObject()->method(signalIndex).methodSignature())) #endif .arg(prettyArgs.join(", ")))); } void MethodsExtension::activateMethod() { QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(m_model); if (selectionModel->selectedRows().size() != 1) { return; } const QModelIndex index = selectionModel->selectedRows().at(0); const QMetaMethod method = index.data(ObjectMethodModelRole::MetaMethod).value(); m_methodArgumentModel->setMethod(method); } void MethodsExtension::connectToSignal() { QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(m_model); if (selectionModel->selectedRows().size() != 1) { return; } const QModelIndex index = selectionModel->selectedRows().at(0); const QMetaMethod method = index.data(ObjectMethodModelRole::MetaMethod).value(); if (method.methodType() == QMetaMethod::Signal) { m_signalMapper->connectToSignal(m_object, method); } } void MethodsExtension::invokeMethod(Qt::ConnectionType connectionType) { if (!m_object) { m_methodLogModel->appendRow( new QStandardItem( tr("%1: Invocation failed: Invalid object, probably got deleted in the meantime."). arg(QTime::currentTime().toString("HH:mm:ss.zzz")))); return; } QMetaMethod method; QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(m_model); if (selectionModel->selectedRows().size() == 1) { const QModelIndex index = selectionModel->selectedRows().at(0); method = index.data(ObjectMethodModelRole::MetaMethod).value(); } if (method.methodType() == QMetaMethod::Constructor) { m_methodLogModel->appendRow( new QStandardItem( tr("%1: Invocation failed: Can't invoke constructors."). arg(QTime::currentTime().toString("HH:mm:ss.zzz")))); return; } const QVector args = m_methodArgumentModel->arguments(); // TODO retrieve return value and add it to the log in case of success // TODO measure executation time and that to the log const bool result = method.invoke(m_object.data(), connectionType, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); if (!result) { m_methodLogModel->appendRow( new QStandardItem( tr("%1: Invocation failed.."). arg(QTime::currentTime().toString("HH:mm:ss.zzz")))); return; } m_methodArgumentModel->setMethod(QMetaMethod()); } gammaray-2.3.0/core/tools/objectinspector/methodsextension.h000066400000000000000000000046101255003167400243540ustar00rootroot00000000000000/* methodsextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_METHODSEXTENSION_H #define GAMMARAY_OBJECTINSPECTOR_METHODSEXTENSION_H #include "common/tools/objectinspector/methodsextensioninterface.h" #include "core/propertycontrollerextension.h" #include class QStandardItemModel; namespace GammaRay { class PropertyController; class ObjectMethodModel; class MethodArgumentModel; class MultiSignalMapper; class MethodsExtension : public MethodsExtensionInterface, public PropertyControllerExtension { Q_OBJECT Q_INTERFACES(GammaRay::MethodsExtensionInterface) public: explicit MethodsExtension(PropertyController *controller); ~MethodsExtension(); bool setQObject(QObject *object) Q_DECL_OVERRIDE; bool setMetaObject(const QMetaObject *metaObject) Q_DECL_OVERRIDE; public slots: void activateMethod() Q_DECL_OVERRIDE; void invokeMethod(Qt::ConnectionType type) Q_DECL_OVERRIDE; void connectToSignal() Q_DECL_OVERRIDE; private slots: void signalEmitted(QObject *sender, int signalIndex, const QVector &args); private: ObjectMethodModel *m_model; QStandardItemModel *m_methodLogModel; MethodArgumentModel *m_methodArgumentModel; MultiSignalMapper *m_signalMapper; QPointer m_object; }; } #endif // METHODSEXTENSION_H gammaray-2.3.0/core/tools/objectinspector/objectinspector.cpp000066400000000000000000000103521255003167400245040ustar00rootroot00000000000000/* objectinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectinspector.h" #include "propertycontroller.h" #include "probeinterface.h" #include "methodsextension.h" #include "classinfoextension.h" #include "enumsextension.h" #include "propertiesextension.h" #include "connectionsextension.h" #include #include #include #include using namespace GammaRay; ObjectInspector::ObjectInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) { registerPCExtensions(); m_propertyController = new PropertyController("com.kdab.GammaRay.ObjectInspector", this); m_selectionModel = ObjectBroker::selectionModel(ObjectBroker::model("com.kdab.GammaRay.ObjectTree")); connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(objectSelectionChanged(QItemSelection))); connect(probe->probe(), SIGNAL(objectSelected(QObject*,QPoint)), SLOT(objectSelected(QObject*))); // when we end up here the object model isn't populated yet QMetaObject::invokeMethod(this, "selectDefaultItem", Qt::QueuedConnection); } void ObjectInspector::selectDefaultItem() { // select the qApp object (if any) in the object treeView const QAbstractItemModel *viewModel = m_selectionModel->model(); const QModelIndexList matches = viewModel->match(viewModel->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(qApp), 1, Qt::MatchFlags(Qt::MatchExactly|Qt::MatchRecursive)); if (!matches.isEmpty()) { m_selectionModel->setCurrentIndex(matches.first(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } } void ObjectInspector::objectSelectionChanged(const QItemSelection& selection) { if (selection.isEmpty()) objectSelected(QModelIndex()); else objectSelected(selection.first().topLeft()); } void ObjectInspector::objectSelected(const QModelIndex &index) { if (index.isValid()) { QObject *obj = index.data(ObjectModel::ObjectRole).value(); m_propertyController->setObject(obj); } else { m_propertyController->setObject(0); } } void ObjectInspector::objectSelected(QObject *object) { const QAbstractItemModel *model = m_selectionModel->model(); const QModelIndexList indexList = model->match(model->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(object), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_selectionModel->select( index, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); // TODO: move this to the client side! //ui->objectTreeView->scrollTo(index); objectSelected(index); } void ObjectInspector::registerPCExtensions() { PropertyController::registerExtension(); PropertyController::registerExtension(); PropertyController::registerExtension(); PropertyController::registerExtension(); PropertyController::registerExtension(); } gammaray-2.3.0/core/tools/objectinspector/objectinspector.h000066400000000000000000000043131255003167400241510ustar00rootroot00000000000000/* objectinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_OBJECTINSPECTOR_H #define GAMMARAY_OBJECTINSPECTOR_OBJECTINSPECTOR_H #include "toolfactory.h" #include class QItemSelection; class QItemSelectionModel; class QModelIndex; namespace GammaRay { class PropertyController; class ObjectInspector : public QObject { Q_OBJECT public: explicit ObjectInspector(ProbeInterface *probe, QObject *parent = 0); private slots: void selectDefaultItem(); void objectSelected(const QModelIndex &index); void objectSelectionChanged(const QItemSelection &selection); void objectSelected(QObject *object); private: void registerPCExtensions(); PropertyController *m_propertyController; QItemSelectionModel *m_selectionModel; }; class ObjectInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit ObjectInspectorFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Objects"); } }; } #endif // GAMMARAY_OBJECTINSPECTOR_H gammaray-2.3.0/core/tools/objectinspector/outboundconnectionsmodel.cpp000066400000000000000000000072671255003167400264450ustar00rootroot00000000000000/* outboundconnectionmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "outboundconnectionsmodel.h" #include "core/probe.h" #ifdef HAVE_PRIVATE_QT_HEADERS #include #endif using namespace GammaRay; OutboundConnectionsModel::OutboundConnectionsModel(QObject* parent): AbstractConnectionsModel(parent) { } OutboundConnectionsModel::~OutboundConnectionsModel() { } void OutboundConnectionsModel::setObject(QObject* object) { clear(); m_object = object; if (!object) return; QVector connections; #ifdef HAVE_PRIVATE_QT_HEADERS QObjectPrivate *d = QObjectPrivate::get(object); if (d->connectionLists) { // HACK: the declaration of d->connectionsLists is not accessible for us... const QVector *cl = reinterpret_cast*>(d->connectionLists); for (int signalIndex = 0; signalIndex < cl->count(); ++signalIndex) { const QObjectPrivate::Connection *c = cl->at(signalIndex).first; while (c) { if (!c->receiver || Probe::instance()->filterObject(c->receiver)) { c = c->nextConnectionList; continue; } Connection conn; conn.endpoint = c->receiver; conn.signalIndex = signalIndexToMethodIndex(m_object, signalIndex); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) if (c->isSlotObject) conn.slotIndex = -1; else #endif conn.slotIndex = c->method(); conn.type = c->connectionType; c = c->nextConnectionList; connections.push_back(conn); } } } #endif setConnections(connections); } QVariant OutboundConnectionsModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || !m_object) return QVariant(); if (role == Qt::DisplayRole) { const Connection &conn = m_connections.at(index.row()); switch (index.column()) { case 0: return displayString(m_object, conn.signalIndex); case 1: return displayString(conn.endpoint); case 2: if (conn.slotIndex < 0) return tr(""); return displayString(conn.endpoint, conn.slotIndex); } } return AbstractConnectionsModel::data(index, role); } QVariant OutboundConnectionsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Signal"); case 1: return tr("Receiver"); case 2: return tr("Slot"); } } return AbstractConnectionsModel::headerData(section, orientation, role); } gammaray-2.3.0/core/tools/objectinspector/outboundconnectionsmodel.h000066400000000000000000000035161255003167400261030ustar00rootroot00000000000000/* outboundconnectionmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_OUTBOUNDCONNECTIONSMODEL_H #define GAMMARAY_OBJECTINSPECTOR_OUTBOUNDCONNECTIONSMODEL_H #include "abstractconnectionsmodel.h" namespace GammaRay { /** Lists outgoing connections from a given QObject. */ class OutboundConnectionsModel : public AbstractConnectionsModel { Q_OBJECT public: explicit OutboundConnectionsModel(QObject *parent = 0); ~OutboundConnectionsModel(); void setObject(QObject *object) Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_OUTBOUNDCONNECTIONMODEL_H gammaray-2.3.0/core/tools/objectinspector/propertiesextension.cpp000066400000000000000000000077201255003167400254450ustar00rootroot00000000000000/* propertiesextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertiesextension.h" #include "aggregatedpropertymodel.h" #include "metapropertymodel.h" #include "objectdynamicpropertymodel.h" #include "objectstaticpropertymodel.h" #include "propertycontroller.h" #include #include #include using namespace GammaRay; PropertiesExtension::PropertiesExtension(PropertyController *controller) : PropertiesExtensionInterface(controller->objectBaseName() + ".propertiesExtension", controller), PropertyControllerExtension(controller->objectBaseName() + ".properties"), m_staticPropertyModel(new ObjectStaticPropertyModel(this)), m_dynamicPropertyModel(new ObjectDynamicPropertyModel(this)), m_metaPropertyModel(new MetaPropertyModel(this)), m_aggregatedPropertyModel(new AggregatedPropertyModel(this)) { controller->registerModel(m_aggregatedPropertyModel, "properties"); m_aggregatedPropertyModel->addModel(m_staticPropertyModel); m_aggregatedPropertyModel->addModel(m_metaPropertyModel); m_aggregatedPropertyModel->addModel(m_dynamicPropertyModel); } PropertiesExtension::~PropertiesExtension() { } bool PropertiesExtension::setQObject(QObject *object) { if (m_object == object) return true; m_object = object; m_staticPropertyModel->setObject(object); m_dynamicPropertyModel->setObject(object); m_metaPropertyModel->setObject(object); setCanAddProperty(true); return true; } bool PropertiesExtension::setObject(void *object, const QString &typeName) { m_object = 0; m_staticPropertyModel->setObject(0); m_dynamicPropertyModel->setObject(0); m_metaPropertyModel->setObject(object, typeName); setCanAddProperty(false); return true; } bool PropertiesExtension::setMetaObject(const QMetaObject* metaObject) { m_object = 0; m_staticPropertyModel->setMetaObject(metaObject); m_dynamicPropertyModel->setObject(0); m_metaPropertyModel->setObject(0); setCanAddProperty(false); return true; } void PropertiesExtension::navigateToValue(int modelRow) { QModelIndex index = m_aggregatedPropertyModel->index(modelRow, 2); QVariant propertyValue = index.data(PropertyModel::ValueRole); if (propertyValue.canConvert()) { Probe::instance()->selectObject(propertyValue.value()); } else { Probe::instance()->selectObject(*reinterpret_cast(propertyValue.data()), index.data(Qt::DisplayRole).toString()); } } void PropertiesExtension::setProperty(const QString &name, const QVariant &value) { if (!m_object) { return; } m_object->setProperty(name.toUtf8(), value); } void PropertiesExtension::resetProperty(const QString &name) { if (!m_object || name.isEmpty()) { return; } const int index = m_object->metaObject()->indexOfProperty(name.toUtf8()); const QMetaProperty prop = m_object->metaObject()->property(index); prop.reset(m_object); } gammaray-2.3.0/core/tools/objectinspector/propertiesextension.h000066400000000000000000000047541255003167400251160ustar00rootroot00000000000000/* propertiesextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_PROPERTIESEXTENSION_H #define GAMMARAY_OBJECTINSPECTOR_PROPERTIESEXTENSION_H #include "common/tools/objectinspector/propertiesextensioninterface.h" #include "core/propertycontrollerextension.h" #include namespace GammaRay { class PropertyController; class ObjectDynamicPropertyModel; class ObjectStaticPropertyModel; class MetaPropertyModel; class AggregatedPropertyModel; class PropertiesExtension : public PropertiesExtensionInterface, public PropertyControllerExtension { Q_OBJECT Q_INTERFACES(GammaRay::PropertiesExtensionInterface) public: explicit PropertiesExtension(PropertyController *controller); ~PropertiesExtension(); void navigateToValue(int modelRow) Q_DECL_OVERRIDE; void setProperty(const QString &name, const QVariant &value) Q_DECL_OVERRIDE; void resetProperty(const QString &name) Q_DECL_OVERRIDE; bool setObject(void *object, const QString &typeName) Q_DECL_OVERRIDE; bool setQObject(QObject *object) Q_DECL_OVERRIDE; bool setMetaObject(const QMetaObject* metaObject) Q_DECL_OVERRIDE; private: ObjectStaticPropertyModel *m_staticPropertyModel; ObjectDynamicPropertyModel *m_dynamicPropertyModel; MetaPropertyModel *m_metaPropertyModel; AggregatedPropertyModel *m_aggregatedPropertyModel; QPointer m_object; }; } #endif // PROPERTIESEXTENSION_H gammaray-2.3.0/core/tools/resourcebrowser/000077500000000000000000000000001255003167400206405ustar00rootroot00000000000000gammaray-2.3.0/core/tools/resourcebrowser/resourcebrowser.cpp000066400000000000000000000061661255003167400246100ustar00rootroot00000000000000/* resourcebrowser.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "resourcebrowser.h" #include "resourcefiltermodel.h" #include "qt/resourcemodel.h" #include "common/objectbroker.h" #include #include #include using namespace GammaRay; ResourceBrowser::ResourceBrowser(ProbeInterface *probe, QObject *parent) : ResourceBrowserInterface(parent) { ResourceModel *resourceModel = new ResourceModel(this); ResourceFilterModel *proxy = new ResourceFilterModel(this); proxy->setSourceModel(resourceModel); probe->registerModel("com.kdab.GammaRay.ResourceModel", proxy); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(proxy); connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(currentChanged(QModelIndex))); } void ResourceBrowser::downloadResource(const QString &sourceFilePath, const QString &targetFilePath) { const QFileInfo fi(sourceFilePath); if (fi.isFile()) { static const QStringList l = QStringList() << "jpg" << "png" << "jpeg"; if (l.contains(fi.suffix())) { emit resourceDownloaded(targetFilePath, QPixmap(fi.absoluteFilePath())); } else { QFile f(fi.absoluteFilePath()); if (f.open(QFile::ReadOnly | QFile::Text)) { emit resourceDownloaded(targetFilePath, f.readAll()); } else { qWarning() << "Failed to open" << fi.absoluteFilePath(); } } } } void ResourceBrowser::currentChanged(const QModelIndex ¤t) { const QFileInfo fi(current.data(ResourceModel::FilePathRole).toString()); if (fi.isFile()) { static const QStringList l = QStringList() << "jpg" << "png" << "jpeg"; if (l.contains(fi.suffix())) { emit resourceSelected(QPixmap(fi.absoluteFilePath())); } else { QFile f(fi.absoluteFilePath()); if (f.open(QFile::ReadOnly | QFile::Text)) { emit resourceSelected(f.readAll()); } else { qWarning() << "Failed to open" << fi.absoluteFilePath(); emit resourceDeselected(); } } } else { emit resourceDeselected(); } } gammaray-2.3.0/core/tools/resourcebrowser/resourcebrowser.h000066400000000000000000000041111255003167400242410ustar00rootroot00000000000000/* resourcebrowser.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_RESOURCEBROWSER_RESOURCEBROWSER_H #define GAMMARAY_RESOURCEBROWSER_RESOURCEBROWSER_H #include "toolfactory.h" #include class QModelIndex; namespace GammaRay { class ResourceBrowser : public ResourceBrowserInterface { Q_OBJECT Q_INTERFACES(GammaRay::ResourceBrowserInterface) public: explicit ResourceBrowser(ProbeInterface *probe, QObject *parent = 0); public slots: void downloadResource(const QString &sourceFilePath, const QString &targetFilePath) Q_DECL_OVERRIDE; private slots: void currentChanged(const QModelIndex ¤t); }; class ResourceBrowserFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit ResourceBrowserFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Resources"); } }; } #endif // GAMMARAY_RESOURCEBROWSER_H gammaray-2.3.0/core/tools/resourcebrowser/resourcefiltermodel.cpp000066400000000000000000000035731255003167400254320ustar00rootroot00000000000000/* resourcefiltermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "resourcefiltermodel.h" #include "qt/resourcemodel.h" #include using namespace GammaRay; ResourceFilterModel::ResourceFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { } bool ResourceFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex index = sourceModel()->index(source_row, 0, source_parent); const QString path = index.data(ResourceModel::FilePathRole).toString(); if (path == ":/gammaray" || path.startsWith(":/gammaray/")) { return false; } return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } QMap ResourceFilterModel::itemData(const QModelIndex &index) const { return sourceModel()->itemData(mapToSource(index)); } gammaray-2.3.0/core/tools/resourcebrowser/resourcefiltermodel.h000066400000000000000000000032031255003167400250650ustar00rootroot00000000000000/* resourcefiltermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_RESOURCEBROWSER_RESOURCEFILTERMODEL_H #define GAMMARAY_RESOURCEBROWSER_RESOURCEFILTERMODEL_H #include namespace GammaRay { class ResourceFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ResourceFilterModel(QObject *parent = 0); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; }; } #endif // RESOURCEFILTERMODEL_H gammaray-2.3.0/core/tools/standardpaths/000077500000000000000000000000001255003167400202455ustar00rootroot00000000000000gammaray-2.3.0/core/tools/standardpaths/standardpaths.cpp000066400000000000000000000027221255003167400236140ustar00rootroot00000000000000/* standardpaths.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "standardpaths.h" #include "standardpathsmodel.h" using namespace GammaRay; StandardPaths::StandardPaths(ProbeInterface *probe, QObject *parent) : QObject(parent) { StandardPathsModel *model = new StandardPathsModel(this); probe->registerModel("com.kdab.GammaRay.StandardPathsModel", model); } StandardPaths::~StandardPaths() { } gammaray-2.3.0/core/tools/standardpaths/standardpaths.h000066400000000000000000000034251255003167400232620ustar00rootroot00000000000000/* standardpaths.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STANDARDPATHS_STANDARDPATHS_H #define GAMMARAY_STANDARDPATHS_STANDARDPATHS_H #include "core/toolfactory.h" namespace GammaRay { class StandardPaths : public QObject { Q_OBJECT public: explicit StandardPaths(ProbeInterface *probe, QObject *parent = 0); ~StandardPaths(); }; class StandardPathsFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit StandardPathsFactory(QObject *parent) : QObject(parent) { } virtual inline QString name() const { return tr("Standard Paths"); } }; } #endif // GAMMARAY_STANDARDPATHS_H gammaray-2.3.0/core/tools/standardpaths/standardpathsmodel.cpp000066400000000000000000000065131255003167400246370ustar00rootroot00000000000000/* standardpathsmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "standardpathsmodel.h" #include using namespace GammaRay; struct standard_path_t { QStandardPaths::StandardLocation location; const char *locationName; }; #define P(x) { QStandardPaths:: x, #x } static const standard_path_t standard_paths[] = { P(DesktopLocation), P(DocumentsLocation), P(FontsLocation), P(ApplicationsLocation), P(MusicLocation), P(MoviesLocation), P(PicturesLocation), P(TempLocation), P(HomeLocation), P(DataLocation), P(CacheLocation), P(GenericDataLocation), P(RuntimeLocation), P(ConfigLocation), P(DownloadLocation), P(GenericCacheLocation) }; #undef P static const int standard_path_count = sizeof(standard_paths) / sizeof(standard_path_t); StandardPathsModel::StandardPathsModel(QObject *parent) : QAbstractTableModel(parent) { } StandardPathsModel::~StandardPathsModel() { } QVariant StandardPathsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::TextAlignmentRole) { return static_cast(Qt::AlignLeft | Qt::AlignTop); } if (role == Qt::DisplayRole) { const QStandardPaths::StandardLocation loc = standard_paths[index.row()].location; switch (index.column()) { case 0: return QString::fromLatin1(standard_paths[index.row()].locationName); case 1: return QStandardPaths::displayName(loc); case 2: return QStandardPaths::standardLocations(loc).join(QLatin1String("\n")); case 3: return QStandardPaths::writableLocation(loc); } } return QVariant(); } int StandardPathsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } int StandardPathsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return standard_path_count; } QVariant StandardPathsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical || role != Qt::DisplayRole) { return QVariant(); } switch (section) { case 0: return tr("Type"); case 1: return tr("Display Name"); case 2: return tr("Standard Locations"); case 3: return tr("Writable Location"); } return QVariant(); } gammaray-2.3.0/core/tools/standardpaths/standardpathsmodel.h000066400000000000000000000034411255003167400243010ustar00rootroot00000000000000/* standardpathsmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STANDARDPATHS_STANDARDPATHSMODEL_H #define GAMMARAY_STANDARDPATHS_STANDARDPATHSMODEL_H #include namespace GammaRay { class StandardPathsModel : public QAbstractTableModel { Q_OBJECT public: explicit StandardPathsModel(QObject *parent = 0); ~StandardPathsModel(); QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_STANDARDPATHSMODEL_H gammaray-2.3.0/core/tools/textdocumentinspector/000077500000000000000000000000001255003167400220575ustar00rootroot00000000000000gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentformatmodel.cpp000066400000000000000000000057061255003167400275500ustar00rootroot00000000000000/* textdocumentformatmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "textdocumentformatmodel.h" #include "core/varianthandler.h" #include #include using namespace GammaRay; static QMetaEnum propertyEnum() { const int index = QTextFormat::staticMetaObject.indexOfEnumerator("Property"); Q_ASSERT(index >= 0); return QTextFormat::staticMetaObject.enumerator(index); } TextDocumentFormatModel::TextDocumentFormatModel(QObject *parent) : QAbstractTableModel(parent) { } void TextDocumentFormatModel::setFormat(const QTextFormat &format) { beginResetModel(); m_format = format; endResetModel(); } int TextDocumentFormatModel::rowCount(const QModelIndex &parent) const { if (!m_format.isValid() || parent.isValid()) { return 0; } return propertyEnum().keyCount(); } int TextDocumentFormatModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } QVariant TextDocumentFormatModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole && index.isValid()) { const int enumValue = propertyEnum().value(index.row()); switch (index.column()) { case 0: return QString::fromLatin1(propertyEnum().key(index.row())); case 1: return VariantHandler::displayString(m_format.property(enumValue)); case 2: return QString::fromLatin1(m_format.property(enumValue).typeName()); } } return QVariant(); } QVariant TextDocumentFormatModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Property"); case 1: return tr("Value"); case 2: return tr("Type"); } } return QAbstractItemModel::headerData(section, orientation, role); } gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentformatmodel.h000066400000000000000000000036741255003167400272170ustar00rootroot00000000000000/* textdocumentformatmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTFORMATMODEL_H #define GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTFORMATMODEL_H #include #include namespace GammaRay { class TextDocumentFormatModel : public QAbstractTableModel { Q_OBJECT public: explicit TextDocumentFormatModel(QObject *parent = 0); void setFormat(const QTextFormat &format); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QTextFormat m_format; }; } #endif gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentinspector.cpp000066400000000000000000000067201255003167400272420ustar00rootroot00000000000000/* textdocumentinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "textdocumentinspector.h" #include "textdocumentformatmodel.h" #include "textdocumentmodel.h" #include "objecttypefilterproxymodel.h" #include "probeinterface.h" #include "common/objectbroker.h" #include #include using namespace GammaRay; TextDocumentInspector::TextDocumentInspector(ProbeInterface *probe, QObject *parent): QObject(parent) { ObjectTypeFilterProxyModel *documentFilter = new ObjectTypeFilterProxyModel(this); documentFilter->setSourceModel(probe->objectListModel()); probe->registerModel("com.kdab.GammaRay.TextDocumentsModel", documentFilter); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(documentFilter); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(documentSelected(QItemSelection,QItemSelection))); m_textDocumentModel = new TextDocumentModel(this); probe->registerModel("com.kdab.GammaRay.TextDocumentModel", m_textDocumentModel); selectionModel = ObjectBroker::selectionModel(m_textDocumentModel); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(documentElementSelected(QItemSelection,QItemSelection))); m_textDocumentFormatModel = new TextDocumentFormatModel(this); probe->registerModel("com.kdab.GammaRay.TextDocumentFormatModel", m_textDocumentFormatModel); } void TextDocumentInspector::documentSelected(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); if (selected.isEmpty()) { m_textDocumentModel->setDocument(0); return; } const QModelIndex selectedRow = selected.first().topLeft(); QObject *selectedObj = selectedRow.data(ObjectModel::ObjectRole).value(); QTextDocument *doc = qobject_cast(selectedObj); m_textDocumentModel->setDocument(doc); } void TextDocumentInspector::documentElementSelected(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); if (selected.isEmpty()) { return; } const QModelIndex selectedRow = selected.first().topLeft(); const QTextFormat f = selectedRow.data(TextDocumentModel::FormatRole).value(); m_textDocumentFormatModel->setFormat(f); } gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentinspector.h000066400000000000000000000044221255003167400267040ustar00rootroot00000000000000/* textdocumentinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTINSPECTOR_H #define GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTINSPECTOR_H #include "toolfactory.h" #include #include class QItemSelection; namespace GammaRay { class TextDocumentModel; class TextDocumentFormatModel; class TextDocumentInspector : public QObject { Q_OBJECT public: explicit TextDocumentInspector(ProbeInterface *probe, QObject *parent = 0); private slots: void documentSelected(const QItemSelection &selected, const QItemSelection &deselected); void documentElementSelected(const QItemSelection &selected, const QItemSelection &deselected); private: TextDocumentModel *m_textDocumentModel; TextDocumentFormatModel *m_textDocumentFormatModel; }; class TextDocumentInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) public: explicit TextDocumentInspectorFactory(QObject *parent) : QObject(parent) { } inline QString name() const { return tr("Text Documents"); } }; } #endif // GAMMARAY_TEXTDOCUMENTINSPECTOR_H gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentmodel.cpp000066400000000000000000000130561255003167400263340ustar00rootroot00000000000000/* textdocumentmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "textdocumentmodel.h" #include #include #include #include #include using namespace GammaRay; static QString formatTypeToString(int type) { switch (type) { case QTextFormat::InvalidFormat: return "Invalid"; case QTextFormat::BlockFormat: return "Block"; case QTextFormat::CharFormat: return "Char"; case QTextFormat::ListFormat: return "List"; case QTextFormat::FrameFormat: return "Frame"; case QTextFormat::UserFormat: return "User"; } return QString("Unknown format: %1").arg(type); } TextDocumentModel::TextDocumentModel(QObject *parent) : QStandardItemModel(parent), m_document(0) { } void TextDocumentModel::setDocument(QTextDocument *doc) { if (m_document) { disconnect(m_document, SIGNAL(contentsChanged()), this, SLOT(documentChanged())); } m_document = doc; fillModel(); if (m_document) connect(m_document, SIGNAL(contentsChanged()), SLOT(documentChanged())); } void TextDocumentModel::documentChanged() { // TODO fillModel(); } void TextDocumentModel::fillModel() { clear(); if (!m_document) { return; } QStandardItem *item = new QStandardItem(tr("Root Frame")); const QTextFormat f = m_document->rootFrame()->frameFormat(); item->setData(QVariant::fromValue(f), FormatRole); item->setEditable(false); QStandardItemModel::appendRow(QList() << item << formatItem(m_document->rootFrame()->frameFormat())); fillFrame(m_document->rootFrame(), item); setHorizontalHeaderLabels(QStringList() << tr("Element") << tr("Format")); } void TextDocumentModel::fillFrame(QTextFrame *frame, QStandardItem *parent) { for (QTextFrame::iterator it = frame->begin(); it != frame->end(); ++it) { fillFrameIterator(it, parent); } } void TextDocumentModel::fillFrameIterator(const QTextFrame::iterator &it, QStandardItem *parent) { QStandardItem *item = new QStandardItem; if (QTextFrame *frame = it.currentFrame()) { const QRectF b = m_document->documentLayout()->frameBoundingRect(frame); QTextTable *table = qobject_cast(frame); if (table) { item->setText(tr("Table")); appendRow(parent, item, table->format(), b); fillTable(table, item); } else { item->setText(tr("Frame")); appendRow(parent, item, frame->frameFormat(), b); fillFrame(frame, item); } } const QTextBlock block = it.currentBlock(); if (block.isValid()) { item->setText(tr("Block: %1").arg(block.text())); const QRectF b = m_document->documentLayout()->blockBoundingRect(block); appendRow(parent, item, block.blockFormat(), b); fillBlock(block, item); } } void TextDocumentModel::fillTable(QTextTable *table, QStandardItem *parent) { for (int row = 0; row < table->rows(); ++row) { for (int col = 0; col < table->columns(); ++col) { QTextTableCell cell = table->cellAt(row, col); QStandardItem *item = new QStandardItem; item->setText(tr("Cell %1x%2").arg(row).arg(col)); appendRow(parent, item, cell.format()); for (QTextFrame::iterator it = cell.begin(); it != cell.end(); ++it) { fillFrameIterator(it, item); } } } } void TextDocumentModel::fillBlock(const QTextBlock &block, QStandardItem *parent) { for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { QStandardItem *item = new QStandardItem(tr("Fragment: %1").arg(it.fragment().text())); const QRectF b = m_document->documentLayout()->blockBoundingRect(block); appendRow(parent, item, it.fragment().charFormat(), b); } } QStandardItem *TextDocumentModel::formatItem(const QTextFormat &format) { QStandardItem *item = new QStandardItem; if (!format.isValid()) { item->setText(tr("no format")); } else if (format.isImageFormat()) { const QTextImageFormat imgformat = format.toImageFormat(); item->setText(tr("Image: %1").arg(imgformat.name())); } else { item->setText(formatTypeToString(format.type())); } item->setEditable(false); return item; } void TextDocumentModel::appendRow(QStandardItem *parent, QStandardItem *item, const QTextFormat &format, const QRectF &boundingBox) { item->setData(QVariant::fromValue(format), FormatRole); item->setData(boundingBox, BoundingBoxRole); item->setEditable(false); parent->appendRow(QList() << item << formatItem(format)); } gammaray-2.3.0/core/tools/textdocumentinspector/textdocumentmodel.h000066400000000000000000000044071255003167400260010ustar00rootroot00000000000000/* textdocumentmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTMODEL_H #define GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTMODEL_H #include "common/modelroles.h" #include #include class QTextTable; class QTextBlock; class QTextFrame; class QTextDocument; namespace GammaRay { class TextDocumentModel : public QStandardItemModel { Q_OBJECT public: explicit TextDocumentModel(QObject *parent = 0); enum Roles { FormatRole = UserRole, BoundingBoxRole }; void setDocument(QTextDocument *doc); private: void fillModel(); void fillFrame(QTextFrame *frame, QStandardItem *parent); void fillFrameIterator(const QTextFrame::iterator &it, QStandardItem *parent); void fillTable(QTextTable *table, QStandardItem *parent); void fillBlock(const QTextBlock &block, QStandardItem *parent); QStandardItem *formatItem(const QTextFormat &format); void appendRow(QStandardItem *parent, QStandardItem *item, const QTextFormat &format, const QRectF &boundingBox = QRectF()); private slots: void documentChanged(); private: QTextDocument *m_document; }; } #endif gammaray-2.3.0/core/util.cpp000066400000000000000000000240571255003167400157360ustar00rootroot00000000000000/* util.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "util.h" #include "common/metatypedeclarations.h" #include "varianthandler.h" #include #include #include #include #include #include #include #include #ifdef HAVE_PRIVATE_QT_HEADERS #include #include #endif #include using namespace GammaRay; using namespace std; namespace GammaRay { class ProtectedExposer : public QObject { public: using QObject::staticQtMetaObject; }; } QString Util::displayString(const QObject *object) { if (!object) { return "QObject(0x0)"; } if (object->objectName().isEmpty()) { return QString::fromLatin1("%1[this=%2]"). arg(object->metaObject()->className()). arg(addressToString(object)); } return object->objectName(); } QString Util::shortDisplayString(const QObject* object) { if (!object) return "0x0"; if (object->objectName().isEmpty()) return addressToString(object); return object->objectName(); } QString Util::addressToString(const void *p) { return (QLatin1String("0x") + QString::number(reinterpret_cast(p), 16)); } QString Util::enumToString(const QVariant &value, const char *typeName, const QObject *object) { QByteArray enumTypeName(typeName); if (enumTypeName.isEmpty()) { enumTypeName = value.typeName(); } // strip of class name and namespace const int pos = enumTypeName.lastIndexOf("::"); if (pos >= 0) { enumTypeName = enumTypeName.mid(pos + 2); } const QMetaObject *mo = &ProtectedExposer::staticQtMetaObject; int enumIndex = mo->indexOfEnumerator(enumTypeName); if (enumIndex < 0 && object) { mo = object->metaObject(); enumIndex = mo->indexOfEnumerator(enumTypeName); } if (enumIndex < 0) { return QString(); } const QMetaEnum me = mo->enumerator(enumIndex); if (!me.isValid()) { return QString(); } return me.valueToKeys(value.toInt()); } QString Util::prettyMethodSignature(const QMetaMethod& method) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return method.signature(); #else QString signature = method.typeName(); signature += ' ' + method.name() + '('; QStringList args; args.reserve(method.parameterCount()); const QList paramTypes = method.parameterTypes(); const QList paramNames = method.parameterNames(); for (int i = 0; i < method.parameterCount(); ++i) { QString arg = paramTypes.at(i); if (!paramNames.at(i).isEmpty()) arg += ' ' + paramNames.at(i); args.push_back(arg); } signature += args.join(", ") + ')'; return signature; #endif } bool Util::descendantOf(const QObject *ascendant, const QObject *obj) { QObject *parent = obj->parent(); if (!parent) { return false; } if (parent == ascendant) { return true; } return descendantOf(ascendant, parent); } namespace GammaRay { static QString stringifyProperty(const QObject *obj, const QString &propName) { const QVariant value = obj->property(propName.toLatin1()); const QMetaProperty mp = obj->metaObject()->property( obj->metaObject()->indexOfProperty(propName.toLatin1())); if (mp.isValid()) { const QString enumStr = Util::enumToString(value, mp.typeName(), obj); if (!enumStr.isEmpty()) { return enumStr; } } return VariantHandler::displayString(value); } struct IconCacheEntry { QVariant defaultIcon; // pair of property name and expected string value typedef QPair PropertyPair; // a list of property pairs typedef QVector PropertyMap; // pair of icon and property map, for which this icon is valid typedef QPair PropertyIcon; typedef QVector PropertyIcons; PropertyIcons propertyIcons; }; /// maps latin1 class name to list of icons valid for a given property map typedef QHash IconDatabase; static IconDatabase readIconData() { IconDatabase data; // we can't load icons due to their QPixmap dependency in a QCoreApplication if (!qApp->inherits("QGuiApplication") && !qApp->inherits("QApplication")) return data; const QString basePath = QLatin1String(":/gammaray/classes/"); QDir dir(basePath); const QStringList filterList = QStringList() << QLatin1String("*.png"); foreach (const QFileInfo &classEntry, dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { IconCacheEntry perClassData; dir.cd(classEntry.fileName()); const QStringList classIcons = dir.entryList(filterList, QDir::Files); dir.cdUp(); if (classIcons.isEmpty()) { cerr << "invalid class icon resource file: " << qPrintable(classEntry.absoluteFilePath()) << endl; continue; } foreach (const QString &iconName, classIcons) { const QIcon icon(classEntry.absoluteFilePath() + '/' + iconName); if (iconName == QLatin1String("default.png")) { perClassData.defaultIcon = icon; continue; } // special property-specific icons with file name format prop1=val;prop2=val.png QString propString(iconName); propString.chop(4); const QStringList props = propString.split(QLatin1String(";")); IconCacheEntry::PropertyMap propertyMap; foreach (const QString &prop, props) { const QStringList keyValue = prop.split(QLatin1Char('=')); if (keyValue.size() != 2) { continue; } propertyMap << qMakePair(keyValue.at(0), keyValue.at(1)); } Q_ASSERT(!propertyMap.isEmpty()); perClassData.propertyIcons << qMakePair(QVariant::fromValue(icon), propertyMap); } data[classEntry.fileName().toLatin1()] = perClassData; } return data; } static QVariant iconForObject(const QMetaObject *mo, const QObject *obj) { static const IconDatabase iconDataBase = readIconData(); // stupid Qt convention to use int for sizes... the static cast shuts down warnings about conversion from size_t to int. const QByteArray className = QByteArray::fromRawData(mo->className(), static_cast(strlen(mo->className()))); IconDatabase::const_iterator it = iconDataBase.constFind(className); if (it != iconDataBase.constEnd()) { foreach (const IconCacheEntry::PropertyIcon &propertyIcon, it->propertyIcons) { bool allMatch = true; Q_ASSERT(!propertyIcon.second.isEmpty()); foreach (const IconCacheEntry::PropertyPair &keyValue, propertyIcon.second) { if (stringifyProperty(obj, keyValue.first) != keyValue.second) { allMatch = false; break; } } if (allMatch) { return propertyIcon.first; } } return it->defaultIcon; } if (mo->superClass()) { return iconForObject(mo->superClass(), obj); } return QVariant(); } } QVariant Util::iconForObject(const QObject *obj) { if (obj) { return GammaRay::iconForObject(obj->metaObject(), obj); } return QVariant(); } QString Util::tooltipForObject(const QObject* object) { return QObject::tr("

Object name: %1\nType: %2\nParent: %3 (Address: %4)\nNumber of children: %5

"). arg(object->objectName().isEmpty() ? "<Not set>" : object->objectName()). arg(object->metaObject()->className()). arg(object->parent() ? object->parent()->metaObject()->className() : ""). arg(Util::addressToString(object->parent())). arg(object->children().size()); } void Util::drawTransparencyPattern(QPainter *painter, const QRect &rect, int squareSize) { QPixmap bgPattern(2 * squareSize, 2 * squareSize); bgPattern.fill(Qt::lightGray); QPainter bgPainter(&bgPattern); bgPainter.fillRect(squareSize, 0, squareSize, squareSize, Qt::gray); bgPainter.fillRect(0, squareSize, squareSize, squareSize, Qt::gray); QBrush bgBrush; bgBrush.setTexture(bgPattern); painter->fillRect(rect, bgBrush); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) && defined(HAVE_PRIVATE_QT_HEADERS) // from Qt4's qobject.cpp static void computeOffsets(const QMetaObject *mo, int *signalOffset, int *methodOffset) { *signalOffset = *methodOffset = 0; const QMetaObject *m = mo->superClass(); while (m) { const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m); *methodOffset += d->methodCount; *signalOffset += d->signalCount; m = m->superClass(); } } #endif int Util::signalIndexToMethodIndex(const QMetaObject* metaObject, int signalIndex) { #ifdef HAVE_PRIVATE_QT_HEADERS #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) return QMetaObjectPrivate::signal(metaObject, signalIndex).methodIndex(); #else if (signalIndex < 0) return signalIndex; Q_ASSERT(metaObject); int signalOffset, methodOffset; computeOffsets(metaObject, &signalOffset, &methodOffset); while (signalOffset > signalIndex) { metaObject = metaObject->superClass(); computeOffsets(metaObject, &signalOffset, &methodOffset); } const int offset = methodOffset - signalOffset; return metaObject->method(signalIndex + offset).methodIndex(); #endif #else Q_UNUSED(metaObject); Q_UNUSED(signalIndex); return -1; #endif } gammaray-2.3.0/core/util.h000066400000000000000000000134611255003167400154000ustar00rootroot00000000000000/* util.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** @file This file is part of the GammaRay Plugin API and declares various utility methods needed when writing a plugin. @brief Declares various utility methods needed when writing a GammaRay plugin. @author Volker Krause \ */ #ifndef GAMMARAY_UTIL_H #define GAMMARAY_UTIL_H #include "gammaray_core_export.h" #include #include class QRect; class QPainter; class QObject; namespace GammaRay { /** * @brief GammaRay utilities. */ namespace Util { /** * Returns a human readable string name of the specified QObject. * This does include the type name. * @param object is a pointer to a valid or null QObject. * * @return a QString containing the human readable display string. */ GAMMARAY_CORE_EXPORT QString displayString(const QObject *object); /** * Short display string for a QObject, either the object name or the address. * This does not include the type name. * @param object valid or 0 QObject */ GAMMARAY_CORE_EXPORT QString shortDisplayString(const QObject *object); /** * Returns a string version (as a hex number starting with "0x") of the * memory address @p p. * @param p is a pointer to an address in memory. * * @return a QString containing the human readable address string. */ GAMMARAY_CORE_EXPORT QString addressToString(const void *p); /** * Translates an enum or flag value into a human readable text. * @param value The numerical value. Type information from the QVariant * are used to find the corresponding QMetaEnum. * @param typeName Use this if the @p value has type int * (e.g. the case for QMetaProperty::read). * @param object Additional QObject to search for QMetaEnums. * * @return a QString containing the string version of the specified @p value. */ GAMMARAY_CORE_EXPORT QString enumToString(const QVariant &value, const char *typeName = 0, const QObject *object = 0); /** * Convenience wrapper for the above, in case the enum value is not available * in a QVariant already. */ template inline QString enumToString(T value, const char *typeName = 0, const QObject *object = 0) { return enumToString(QVariant::fromValue(value), typeName, object); } /** * Returns a display string for @p method. * This includes return types and argument names, if available. */ GAMMARAY_CORE_EXPORT QString prettyMethodSignature(const QMetaMethod &method); /** * Determines if the QObject @p obj is a descendant of the QObject @p ascendant. * @param ascendant is a pointer to a QObject. * @param object is a pointer to a QObject. * * @return true if @p obj is a descendant of @p ascendant; false otherwise. */ GAMMARAY_CORE_EXPORT bool descendantOf(const QObject *ascendant, const QObject *object); /** * Finds the parent QObject of the specified type T, if such exists. * @param object is a pointer to a QObject. * * @return zero on failure; else a pointer to a data type T. * */ template T *findParentOfType(QObject *object) { if (!object) { return 0; } if (qobject_cast(object)) { return qobject_cast(object); } return findParentOfType(object->parent()); } /** * Returns an icon for the given object. In normal operation a QIcon is * returned containing the icon most closely associated with the data type * pointed to by @p object * @param object is a pointer to a QObject. * * @return on failure QVariant() is returned; else a QIcon */ GAMMARAY_CORE_EXPORT QVariant iconForObject(const QObject *object); /** * Returns a suitable rich text tooltip string for @p object. * @param object a pointer to a valid or null QObject. */ GAMMARAY_CORE_EXPORT QString tooltipForObject(const QObject *object); /** * Draws a transparency pattern, i.e. the common checkerboard pattern into @p rect. * * @p size The size of the individual checkerboard squares. */ GAMMARAY_CORE_EXPORT void drawTransparencyPattern(QPainter *painter, const QRect &rect, int squareSize = 8); /** * Turns a signal index into a method index. * Signals indexes are used internally by QObject as an optimization and are * usually not exposed in public API. If you get them nevertheless, by using * internals of QObject this method turns them into method indexes that work * with public QMetaObject API. * * @param metaObject The meta object the signal belongs so * @since 2.2 */ GAMMARAY_CORE_EXPORT int signalIndexToMethodIndex(const QMetaObject* metaObject, int signalIndex); } } #endif // GAMMARAY_UTIL_H gammaray-2.3.0/core/varianthandler.cpp000066400000000000000000000344321255003167400177610ustar00rootroot00000000000000/* varianthandler.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "varianthandler.h" #include "util.h" #include "common/metatypedeclarations.h" #if QT_VERSION < QT_VERSION_CHECK(5, 0 , 0) #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; namespace GammaRay { struct VariantHandlerRepository { QHash*> stringConverters; QVector genericStringConverters; }; static QString displayMatrix4x4(const QMatrix4x4 &matrix) { QStringList rows; rows.reserve(4); for (int i = 0; i < 4; ++i) { QStringList cols; cols.reserve(4); for (int j = 0; j < 4; ++j) { cols.push_back(QString::number(matrix(i, j))); } rows.push_back(cols.join(" ")); } return '[' + rows.join(", ") + ']'; } static QString displayMatrix4x4(const QMatrix4x4 *matrix) { if (matrix) { return displayMatrix4x4(*matrix); } return ""; } template static QString displayVector(const T &vector) { QStringList v; for (int i = 0; i < Dim; ++i) v.push_back(QString::number(vector[i])); return '[' + v.join(", ") + ']'; } #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) static QString displayShaderType(const QOpenGLShader::ShaderType type) { QStringList types; #define ST(t) if (type & QOpenGLShader::t) types.push_back(#t); ST(Vertex) ST(Fragment) #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) ST(Geometry) ST(TessellationControl) ST(TessellationEvaluation) ST(Compute) #endif #undef ST if (types.isEmpty()) return ""; return types.join(" | "); } #endif } Q_GLOBAL_STATIC(VariantHandlerRepository, s_variantHandlerRepository) QString VariantHandler::displayString(const QVariant &value) { switch (value.type()) { #ifndef QT_NO_CURSOR case QVariant::Cursor: { const QCursor cursor = value.value(); return Util::enumToString(QVariant::fromValue(cursor.shape()), "Qt::CursorShape"); } #endif case QVariant::Icon: { const QIcon icon = value.value(); if (icon.isNull()) { return QObject::tr(""); } const auto sizes = icon.availableSizes(); QStringList l; l.reserve(sizes.size()); foreach (const QSize &size, sizes) { l.push_back(displayString(size)); } return l.join(QLatin1String(", ")); } case QVariant::Line: return QString::fromUtf8("%1, %2 → %3, %4"). arg(value.toLine().x1()).arg(value.toLine().y1()). arg(value.toLine().x2()).arg(value.toLine().y2()); case QVariant::LineF: return QString::fromUtf8("%1, %2 → %3, %4"). arg(value.toLineF().x1()).arg(value.toLineF().y1()). arg(value.toLineF().x2()).arg(value.toLineF().y2()); case QVariant::Locale: return value.toLocale().name(); case QVariant::Point: return QString::fromLatin1("%1, %2"). arg(value.toPoint().x()). arg(value.toPoint().y()); case QVariant::PointF: return QString::fromLatin1("%1, %2"). arg(value.toPointF().x()). arg(value.toPointF().y()); case QVariant::Rect: return QString::fromLatin1("%1, %2 %3 x %4"). arg(value.toRect().x()). arg(value.toRect().y()). arg(value.toRect().width()). arg(value.toRect().height()); case QVariant::RectF: return QString::fromLatin1("%1, %2 %3 x %4"). arg(value.toRectF().x()). arg(value.toRectF().y()). arg(value.toRectF().width()). arg(value.toRectF().height()); case QVariant::Region: { const QRegion region = value.value(); if (region.isEmpty()) { return QLatin1String(""); } if (region.rectCount() == 1) { return displayString(region.rects().at(0)); } else { return QString::fromLatin1("<%1 rects>").arg(region.rectCount()); } } case QVariant::Palette: { const QPalette pal = value.value(); if (pal == qApp->palette()) { return QLatin1String(""); } return QLatin1String(""); } case QVariant::Size: return QString::fromLatin1("%1 x %2"). arg(value.toSize().width()). arg(value.toSize().height()); case QVariant::SizeF: return QString::fromLatin1("%1 x %2"). arg(value.toSizeF().width()). arg(value.toSizeF().height()); case QVariant::StringList: return value.toStringList().join(", "); case QVariant::Transform: { const QTransform t = value.value(); return QString::fromLatin1("[%1 %2 %3, %4 %5 %6, %7 %8 %9]"). arg(t.m11()).arg(t.m12()).arg(t.m13()). arg(t.m21()).arg(t.m22()).arg(t.m23()). arg(t.m31()).arg(t.m32()).arg(t.m33()); } default: break; } // types with dynamic type ids if (value.type() == (QVariant::Type)qMetaTypeId()) { const QTextLength l = value.value(); QString typeStr; switch (l.type()) { case QTextLength::VariableLength: typeStr = QObject::tr("variable"); break; case QTextLength::FixedLength: typeStr = QObject::tr("fixed"); break; case QTextLength::PercentageLength: typeStr = QObject::tr("percentage"); break; } return QString::fromLatin1("%1 (%2)").arg(l.rawValue()).arg(typeStr); } if (value.userType() == qMetaTypeId()) { const QPainterPath path = value.value(); if (path.isEmpty()) { return QObject::tr(""); } return QObject::tr("<%1 elements>").arg(path.elementCount()); } if (value.userType() == qMetaTypeId()) { const QMargins margins = value.value(); return QObject::tr("left: %1, top: %2, right: %3, bottom: %4") .arg(margins.left()).arg(margins.top()) .arg(margins.right()).arg(margins.bottom()); } if (value.canConvert()) { return Util::displayString(value.value()); } if (value.userType() == qMetaTypeId()) { return displayMatrix4x4(value.value()); } if (value.userType() == qMetaTypeId()) { return displayMatrix4x4(value.value()); } #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (value.userType() == qMetaTypeId()) return displayVector<2>(value.value()); if (value.userType() == qMetaTypeId()) return displayVector<3>(value.value()); if (value.userType() == qMetaTypeId()) return displayVector<4>(value.value()); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) if (value.userType() == qMetaTypeId >()) { const QSet set = value.value >(); QStringList l; l.reserve(set.size()); foreach (const QByteArray &b, set) { l.push_back(QString::fromUtf8(b)); } return l.join(", "); } if (value.userType() == qMetaTypeId()) { const QSurfaceFormat format = value.value(); QString s; switch (format.renderableType()) { case QSurfaceFormat::DefaultRenderableType: s += "Default"; break; case QSurfaceFormat::OpenGL: s += "OpenGL"; break; case QSurfaceFormat::OpenGLES: s += "OpenGL ES"; break; case QSurfaceFormat::OpenVG: s += "OpenVG"; break; } s += " (" + QString::number(format.majorVersion()) + '.' + QString::number(format.minorVersion()); switch (format.profile()) { case QSurfaceFormat::CoreProfile: s += " core"; break; case QSurfaceFormat::CompatibilityProfile: s += " compat"; break; case QSurfaceFormat::NoProfile: break; } s += ')'; s += " RGBA: " + QString::number(format.redBufferSize()) + '/' + QString::number(format.greenBufferSize()) + '/' + QString::number(format.blueBufferSize()) + '/' + QString::number(format.alphaBufferSize()); s += " Depth: " + QString::number(format.depthBufferSize()); s += " Stencil: " + QString::number(format.stencilBufferSize()); s += " Buffer: "; switch (format.swapBehavior()) { case QSurfaceFormat::DefaultSwapBehavior: s += "default"; break; case QSurfaceFormat::SingleBuffer: s += "single"; break; case QSurfaceFormat::DoubleBuffer: s += "double"; break; case QSurfaceFormat::TripleBuffer: s += "triple"; break; default: s += "unknown"; } return s; } if (value.userType() == qMetaTypeId()) { const QSurface::SurfaceClass sc = value.value(); switch (sc) { case QSurface::Window: return QObject::tr("Window"); #if QT_VERSION > QT_VERSION_CHECK(5, 1, 0) case QSurface::Offscreen: return QObject::tr("Offscreen"); #endif default: return QObject::tr("Unknown Surface Class"); } } if (value.userType() == qMetaTypeId()) { const QSurface::SurfaceType type = value.value(); switch (type) { case QSurface::RasterSurface: return QObject::tr("Raster"); case QSurface::OpenGLSurface: return QObject::tr("OpenGL"); default: return QObject::tr("Unknown Surface Type"); } } if (value.userType() == qMetaTypeId()) return displayShaderType(value.value()); #endif // Qt5 // enums const QString enumStr = Util::enumToString(value); if (!enumStr.isEmpty()) { return enumStr; } // custom converters const QHash*>::const_iterator it = s_variantHandlerRepository()->stringConverters.constFind(value.userType()); if (it != s_variantHandlerRepository()->stringConverters.constEnd()) { return (*it.value())(value); } // recurse into sequences #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (value.canConvert()) { QStringList s; QSequentialIterable it = value.value(); s.reserve(it.size()); int emptyStrings = 0; foreach (const QVariant &v, it) { s.push_back(displayString(v)); if (s.last().isEmpty()) { ++emptyStrings; } } if (it.size() == 0) { return QObject::tr(""); } else if (it.size() == emptyStrings) { // we don't know the content either return QObject::tr("%1 entries").arg(emptyStrings); } else { return s.join(", "); } } #endif // generic converters QVector genStrConverters = s_variantHandlerRepository()->genericStringConverters; foreach (const GenericStringConverter &converter, genStrConverters) { bool ok = false; const QString s = converter(value, &ok); if (ok) { return s; } } return value.toString(); } QVariant VariantHandler::decoration(const QVariant &value) { switch (value.type()) { case QVariant::Brush: { const QBrush b = value.value(); if (b.style() != Qt::NoBrush) { QPixmap p(16, 16); p.fill(QColor(0, 0, 0, 0)); QPainter painter(&p); painter.setBrush(b); painter.drawRect(0, 0, p.width() - 1, p.height() - 1); return p; } break; } case QVariant::Color: { const QColor c = value.value(); if (c.isValid()) { QPixmap p(16, 16); QPainter painter(&p); painter.setBrush(QBrush(c)); painter.drawRect(0, 0, p.width() - 1, p.height() - 1); return p; } break; } #ifndef QT_NO_CURSOR case QVariant::Cursor: { const QCursor c = value.value(); if (!c.pixmap().isNull()) { return c.pixmap().scaled(16, 16, Qt::KeepAspectRatio, Qt::FastTransformation); } break; } #endif case QVariant::Icon: { return value; } case QVariant::Pen: { const QPen pen = value.value(); if (pen.style() != Qt::NoPen) { QPixmap p(16, 16); p.fill(QColor(0, 0, 0, 0)); QPainter painter(&p); painter.setPen(pen); painter.translate(0, 8 - pen.width() / 2); painter.drawLine(0, 0, p.width(), 0); return p; } break; } case QVariant::Pixmap: { const QPixmap p = value.value(); if(!p.isNull()) { return QVariant::fromValue(p.scaled(16, 16, Qt::KeepAspectRatio, Qt::FastTransformation)); } break; } default: break; } return QVariant(); } void VariantHandler::registerStringConverter(int type, Converter *converter) { s_variantHandlerRepository()->stringConverters.insert(type, converter); } void VariantHandler::registerGenericStringConverter( VariantHandler::GenericStringConverter converter) { s_variantHandlerRepository()->genericStringConverters.push_back(converter); } QVariant VariantHandler::serializableVariant(const QVariant& value) { if (value.userType() == qMetaTypeId()) { const QMatrix4x4 *m = value.value(); if (!m) return QVariant(); return QVariant::fromValue(QMatrix4x4(*m)); } return value; } gammaray-2.3.0/core/varianthandler.h000066400000000000000000000103221255003167400174160ustar00rootroot00000000000000/* varianthandler.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_VARIANTHANDLER_H #define GAMMARAY_VARIANTHANDLER_H #include "gammaray_core_export.h" #include namespace GammaRay { /** @brief Variant conversion functions, extendable by plugins. */ namespace VariantHandler { ///@cond internal template struct Converter { virtual RetT operator() (const QVariant &v) = 0; }; template struct ConverterImpl : public Converter { explicit inline ConverterImpl(FuncT converter) : f(converter) { } /*override*/ inline RetT operator() (const QVariant &v) { return f(v.value()); } FuncT f; }; ///@endcond /** * Returns a human readable string version of the QVariant value. * Converts to the variant type and prints the string value accordingly. * @param value is a QVariant. * * @return a QString containing the human readable string. */ GAMMARAY_CORE_EXPORT QString displayString(const QVariant &value); /** * Returns a human readable string version of the given value. * Thihs is a convenience overload of the QVariant-based version above. * * @return a QString containing the human readable string. */ template inline QString displayString(T value) { return displayString(QVariant::fromValue(value)); } /** * Returns a value representing @p value in a itemview decoration role. * @param value is a QVariant. * * @return a QVariant itemview decoration role. */ GAMMARAY_CORE_EXPORT QVariant decoration(const QVariant &value); /** * Register a string conversion functions for a variant type. * @internal */ GAMMARAY_CORE_EXPORT void registerStringConverter(int type, Converter *converter); /** * Register a string conversion function for a variant type. * @tparam T The type for which to use this converter function. */ template inline void registerStringConverter(FuncT f) { Converter *converter = new ConverterImpl(f); registerStringConverter(qMetaTypeId(), converter); } typedef QString(*GenericStringConverter)(const QVariant &value, bool *ok); /** * Register a generic string conversion function for various variant types. * This can be used when you have a converter that can dynamically check if * it can handle a given variant, and the types it can handle aren't known * at compile time (example: QQmlListProperty). * @param converter The converter function. It's second parameter is used to * indicate if the value could be handled. */ GAMMARAY_CORE_EXPORT void registerGenericStringConverter(GenericStringConverter converter); /** * Converts the given variant into an variant of a different type that can be transferred * to another process. * This is most prominently needed for pointer types, e.g. const QMatrix4x4* -> QMatrix4x4, * primarily for the fancy display delegate on the client side. */ GAMMARAY_CORE_EXPORT QVariant serializableVariant(const QVariant &value); } } #endif // GAMMARAY_VARIANTHANDLER_H gammaray-2.3.0/debian.changelog000066400000000000000000000053311255003167400164120ustar00rootroot00000000000000gammaray (2.3.0) final; urgency=low * 2.3.0 final release -- Allen Winter Fri, 10 Jul 2015 15:30:00 -0500 gammaray (2.2.1) final; urgency=low * 2.2.1 first 2.2 bugfix release -- Allen Winter Tue, 27 Jan 2015 18:30:00 -0500 gammaray (2.2.0) final; urgency=low * 2.2.0 final release -- Allen Winter Fri, 31 Oct 2014 09:30:00 -0500 gammaray (2.1.2) final; urgency=low * 2.1.2 second 2.1 bugfix release -- Allen Winter Thu, 23 Oct 2014 10:00:00 -0500 gammaray (2.1.1) final; urgency=low * 2.1.1 first 2.1 bugfix release -- Allen Winter Sat, 30 Aug 2014 12:00:00 -0500 gammaray (2.1.0) final; urgency=low * 2.1.0 final release -- Allen Winter Fri, 27 Jun 2014 09:30:00 -0500 gammaray (2.0.98) final; urgency=low * 2.1.0 rc1 release -- Allen Winter Thu, 26 Jun 2014 15:30:00 -0500 gammaray (2.0.2) final; urgency=low * 2.0.2 final release -- Allen Winter Fri, 18 Apr 2014 11:30:00 -0500 gammaray (2.0.1) final; urgency=low * 2.0.1 final release -- Allen Winter Fri, 28 Feb 2014 11:30:00 -0500 gammaray (2.0.0) final; urgency=low * 2.0.0 final release -- Allen Winter Fri, 17 Jan 2014 11:00:00 -0500 gammaray (1.9.96) final; urgency=low * 2.0.0 beta2 release -- Allen Winter Sat, 11 Jan 2014 11:00:00 -0500 gammaray (1.9.95) final; urgency=low * 2.0.0 beta1 release -- Allen Winter Fri, 20 Dec 2013 11:00:00 -0500 gammaray (1.3.2) final; urgency=low * 1.3.2 patch release -- Allen Winter Thu, 03 Oct 2013 11:00:00 -0500 gammaray (1.3.1) final; urgency=low * 1.3.1 patch release -- Allen Winter Tues, 30 Apr 2013 16:30:00 -0500 gammaray (1.3.0) final; urgency=low * 1.3.0 final release -- Allen Winter Sun, 27 Jan 2013 18:00:00 -0500 gammaray (1.2.2) patch; urgency=low * 1.2.2 patch release -- Allen Winter Fri, 21 Dec 2012 14:33:00 -0500 gammaray (1.2.1) patch; urgency=low * 1.2.1 patch release -- Allen Winter Thu, 16 Aug 2012 10:17:14 -0500 gammaray (1.2.0) final; urgency=low * 1.2.0 final release -- Allen Winter Thu, 05 Jul 2012 10:19:14 -0500 gammaray (1.1.99) beta2; urgency=low * 1.1.99 beta2 release -- Allen Winter Tue, 03 Jul 2012 14:10:14 +0000 gammaray (1.1.98) beta; urgency=low * 1.1.98 beta release -- Allen Winter Wed, 27 Jun 2012 14:10:14 +0000 gammaray-2.3.0/debian.control000066400000000000000000000013721255003167400161440ustar00rootroot00000000000000Source: gammaray Section: Miscellaneous Priority: optional Maintainer: Allen Winter Build-Depends: debhelper (>= 4.1.16), cdbs, cmake, libqt4-dev, libqtwebkit-dev, graphviz-dev Package: gammaray Architecture: any Depends: ${shlibs:Depends}, graphviz Description: A tool to poke around in a Qt-application GammaRay is a tool for examining the internals of a Qt application and to some extent also manipulate it. GammaRay uses injection methods to hook into an application at runtime and provide access to a wide variety of interesting information. It provides easy ways of navigating through the complex internal structures you find in some Qt frameworks, such as QGraphicsView, model/view, QTextDocument, state machines and more. gammaray-2.3.0/debian.rules000066400000000000000000000001511255003167400156100ustar00rootroot00000000000000#!/usr/bin/make -f include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/cmake.mk gammaray-2.3.0/docs/000077500000000000000000000000001255003167400142455ustar00rootroot00000000000000gammaray-2.3.0/docs/CMakeLists.txt000066400000000000000000000033251255003167400170100ustar00rootroot00000000000000# # man page # if(UNIX) find_program(POD2MAN_EXECUTABLE pod2man) gammaray_add_dummy_package(pod2man POD2MAN_EXECUTABLE) set_package_properties(pod2man PROPERTIES TYPE RECOMMENDED DESCRIPTION "Man page generator" PURPOSE "Generate GammaRay man pages." ) if(POD2MAN_EXECUTABLE AND NOT GAMMARAY_PROBE_ONLY_BUILD) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gammaray.1 COMMAND ${POD2MAN_EXECUTABLE} -c "KDAB Products" -r "\"${GAMMARAY_VERSION}\"" -s 1 ${CMAKE_CURRENT_SOURCE_DIR}/gammaray.pod ${CMAKE_CURRENT_BINARY_DIR}/gammaray.1 DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/gammaray.pod ) add_custom_target(man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gammaray.1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gammaray.1 DESTINATION ${MAN_INSTALL_DIR}) endif() endif() # # API docs # find_package(Doxygen) set_package_properties(Doxygen PROPERTIES TYPE OPTIONAL DESCRIPTION "API Documentation system" URL "http://www.doxygen.org" PURPOSE "Needed to build the API documention." ) if(DOXYGEN_FOUND) file(GLOB _dox_deps *.dox *.html) gammaray_all_installed_headers(_all_hdrs) list(APPEND _all_hdrs ${_dox_deps}) gammaray_join_list(DOXYGEN_INPUT " " ${_all_hdrs}) #apidox generation using doxygen configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ) add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/apidocs/html/index.html COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile DEPENDS ${_all_hdrs} ${_dox_deps} ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) add_custom_target(docs DEPENDS ${CMAKE_BINARY_DIR}/apidocs/html/index.html ) endif() gammaray-2.3.0/docs/Doxyfile.cmake000066400000000000000000000163141255003167400170370ustar00rootroot00000000000000#--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = GammaRay PROJECT_NUMBER = @GAMMARAY_VERSION@ OUTPUT_DIRECTORY = apidocs CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The \$name class" \ "The \$name widget" \ "The \$name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = YES HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = YES CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_MEMBERS_CTORS_1ST = YES SORT_BRIEF_DOCS = YES SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = NO GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST = YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "\$file:\$line: \$text" WARN_LOGFILE = doxygen.log #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = @DOXYGEN_INPUT@ FILE_PATTERNS = *.cpp \ *.cc \ *.cxx \ *.h \ *.hh \ *.hxx \ *.hpp \ *.dox RECURSIVE = YES EXCLUDE = @CMAKE_SOURCE_DIR@/common/gammaray_common_export.h \ @CMAKE_SOURCE_DIR@/core/gammaray_core_export.h \ @CMAKE_SOURCE_DIR@/ui/gammaray_ui_export.h EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */.svn/* \ */.git/* \ */cmake/* \ *.moc.* \ moc* \ *.all_cpp.* \ *unload.* \ */test/* \ */tests/* \ *_p.cpp \ *_export.h EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = @CMAKE_SOURCE_DIR@/docs INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # do NOT generate any formats other than html #--------------------------------------------------------------------------- SOURCE_BROWSER = NO GENERATE_HTML = YES GENERATE_LATEX = NO GENERATE_RTF = NO GENERATE_XML = NO GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO DISABLE_INDEX = YES #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = @CMAKE_SOURCE_DIR@/docs/footer.html HTML_STYLESHEET = GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = Q_DECL_IMPORT="" GAMMARAY_COMMON_EXPORT="" GAMMARAY_CORE_EXPORT="" GAMMARAY_UI_EXPORT="" EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = NO GROUP_GRAPHS = NO UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = YES SERVER_BASED_SEARCH = NO gammaray-2.3.0/docs/KDAB-CopyrightAssignmentForm.docx000066400000000000000000000200701255003167400224470ustar00rootroot00000000000000PK …•F _rels/.rels­’MKA †ďýCîÝl+ČÎö"Bo"ő„™ěîĐÎ3i­˙ŢA şPŠ ÇĽyóđŇmÎţ Nś‹‹AĂŞiAq0Ńş0jxŰ=/`Ó/şW>ÔJ™\*ŞŢ„˘aIŹĹLě©41q¨›!fORÇŔMÜtĄ¬˝Z›řz UĹmFóĐL·ýĚKs¦ŞI¸‡»M„†x”)ńÜĂű~wűŤň„‹0őđE Űá¦[[%3wiă ¬íÚĂɬ´!čx˘Śş‘BěÚQjFsZç°JťJ•‘T=š—păCČŻüÉÍÚŞ#±ůś!ü ńc±=ŢLŠ[θôđź/ň(ą  ]ř‡kkľ‚vÂöŠ<_#ŕ€PíE^Ř!MÉQřK_? ?PKÉŁnKĘPK …•Fword/_rels/document.xml.relsĹ“ŰJ1†ďű!÷n¶ő€”nWń˝đB©fgwăćDfVÚ·7Ĺj[hEˇŕĺL&ß˙˙03)—Ö°w¨˝+ř0Ë9§|Ą]Sđ×ůăŮ5/§É Ii[Ą? Ţ…±¨Z°3ŔĄ—ÚG+)•±AŞN6 Fy~%â.O÷lV<ÎŞ!góU€ß°}]k÷^őH+26@˙¬łÄáâ°üč”ňm"EŁ]·u`Ą6äÇ؇ŕ#Ýt•\dĘŰűĹ(*î|XEÝ´ÄnuăÖhöÜ®©_'_%‡K‚čäŃ(ç˙Ĺ;ęoY.N™ĄöŽćra`›ĺ»őÓn\žt5(ťŘîrn: ‰Ř»ąéPK—žë+ŞPK …•Fword/fontTable.xml­PANĂ0Ľó Ëwę´„˘¦â„z ĺ[gÓX˛×‘×$ô÷¸N+!ȡ ŢěťŮ™ŮY®?ť=6ž*9źR i_:Tň}÷r˙(G ¬'¬äY®WwˡlÔ]𙓺łjQĘ!y– ×Čř¦1ź˝ţpHq h!¦ ¸5ËŐ9ťJ—BďŚCÄ›w@™ [Ś'N¶’E!UŢgěń2 ™žÎDÝ^ć={‹'HŤfżL·G·÷vŇkqkݧD™¶š<‹ĂüO«WłÇË[ ¦É®`ă&ˇťź}«©dó[—đ=O{ş>ÎźŠ:?xőPKÁÇŮUPK …•Fword/styles.xmlĹTQOŰ0~߯ü^RšŞŠ€ş2D%Ôˇ{wťKcplËvHËŻß9q4a+ i}hâďěó}ß}ą“łM!˘G0–+™Ă1‰@2•rąNČÝíĹhB"ë¨L©P˛KÎNżśTSë¶l„祝V ÉťÓÓ8¶,‡‚ÚĄAb,S¦ —fWʤÚ(ÖbúBÄGăń׸ \’6Íáq/QÁ™QVe"VYĆÔ©đřá¸~+D› `űRPóPęćÓÔńÜmëbHT°éb-•ˇ+l±rŠ\SĹÎ!ŁĄpÖ/͵ ˰ŞJ:USjç ąâ+0^Éč φň™´o„€Z7łś&äîéŻ2şˇŇúłx@ĺÜE—\¦śÄţ2ű4÷W=R‘ŁăT®[Ě>ŽnľżNű”ŹćK­xŠ5ä|´Xúq`ďňŇ»«zĎ‹gŤ{ ŐćŔ»ÜVŁŚšş6Tçţú:´H˛ôµľ’Đ–฻´šVMŻ™­ř&Ž}=4CÝpNŤßmÇŕ¬7†Č{'PçŻÉ€ç&ź»hWmžĄűŢA—g!—đłôCťâ ń•NČ ť˙®ňGI]qëz„jpË€GŢîö@>ZĺśjoŠ^ˇ-ľŻîa$ăç ˲@ŻŮ7ŚíE~‡±˝Č›˙ąÝ{~Tž…La30Í<ú)i>ŮÜöÍžţPKčĘ’mÁŇ PK …•Fword/document.xmlí]ÝrŰF˛ľ?O1‡.»Š–,ŰÇ•Č+ĺP’•°Ö‘T˝[®­s1ÄDŔ 23 Ť\ĺ5NŐž»}“}“<É鞀”"9ŽiÚ‚Ő©ŠEŔÝ_÷7ÝóÓřËwďʂͅ±R«˝ÁÎÖ“*Ń©Tł˝Á›ÉńăoĚ:®R^h%öŤ°ďö˙ă/‹ÝT'u)”cĐ‚˛»zoPµk“\”Ü>.eb´Ő™{śčrWg™LDü3W˝Aî\µ»˝/ÚŇ•Pp,Ӧ侚Ův¸ä(Ţkűé“'/¶Ť(¸çµą¬lŰÚü}÷ź—E{ŢâCîşĐ&­ŚN„µ ˛÷-ąT]3;O>@`l§»˘ú;§†/VnyőAŽÂÁe‹öwMvʱʵç[övž\kď"ç•X¶6[ŻµďŤ®«¶µ2ůiKn.ë 5V˘SYH×xÁ—µó|˝§ş®łŹkí§LvÇ3Ą źŕĐçě/LuÚŕßĘ˙sfüź ׂ-vçĽŘś ÔĹ`Źü”´ż"sá7.*¸šµ…züýÝŽ‡·»¶Í‡^˛Řuű=°C]5FÎrÇF –™ňž{ …§şpAly»ý·şł"ý-ľÚřóŰ_ÚCOź‡7ýrhŻ˙f޵rř+·‰”{×r*Śç-v!ŚĚp(){Ë!Á­YÉ÷Gâ'ţ·š]peń@N˙Zçұ¤Je¸Y˘ mÚ'x‚˙ŤÂß«ňJŰżäŹOđ§©LáArůx|˛&>›Cbş˝ňEľ?|ú?ŃšÖ™Ľ—˙†6˝Ĺܦ·]+ŐWl|˙‘Ú$—–UŃÚX*lbËr˝`NłÚ ćrŁ1“2ĎëIÇë|ÉëŘĹnő’Ř' `0FĎ39XH ŠYľ>ř\Ë”qŐ°JĂ1ÔY˘UVűŽACHëµU/z© ˝PĐËAËt°ĆeÁŤ#Ńiť8;ńSÔhI”Jf ăENs1 µĬÖőRKÓvřˇO .KË| Ľč€ą?©ń+ä-OŮB‚Ѩ ‰V[[ ¬«çšČu‘"®‘}ç2­yÁ0-qđżÇ[^xÄş.Rđ &l% vѰy]ŔYüstf›P }Ĺ † `÷ŤÝs…&ŕ>ĺh ĽŞ ™„| $*…g™HŔd6Ď’>Ţ•đqSýŐŤ]0ź!ü§™śC'î-ň Ą7ş6,Éáp ą—. ÜZJ ¸ś; üŃ$$ßÍÄř%ČĽĘŘQ~nýĹV–I×ĎŘĺT%"Ä*±dš ˇÚ„H‡LfQA6÷JŽÝµ]íÂXV»:ř¨–^Ş»^ ĽlÄϵ4Îć€kščBLĽ>GBÚÔ)e‘<ůŢHÎSQ@v9 ©^ş\â@xÇç\Ýůô¨ ‹Č˝Č˝Ö1®‘pě»EYşiălP'¤ÖĐsCN }\ÂUĘWcśCĂŘ^dúčg8…°k+ž˝Ae8×\ ö­«SáíŘHčáŔę°c‡C ś‚ŕ¦a3áBčÓęp;ŞY şČTZŻ@Ż3P–ĺŤe}ÔŇľ| ÝB 9¨AGËY‘ŚŰC ĚXR·šWW­czg(rÁS&€~O?±—ŻU ÎőŰŻ˙gťńmµ¬ôŰŻ˙ĆÓbśîŤ—«fS&ů)9čçZX?Â1dĹ˨çĘŕ»N(yS SHuÉĚ®L÷fś>\$sE¨±rÂ(á^ĂU·ĺ5Tl]UÚ¸˙ľLů§XŻ<ÄöĘS|e`úĹrQTÄ&Ä&ë%\]úlţÚŔ‚˝:Ř’Ť‘Ť­™Ľ. ^ÄŚÍ'¨+ÉŃÄâ|WŐjë ’'g6¤íľö2j,ůe;LÚÍ۱ëĚꇹOІ3i]śě[™1ęg"ŹB(±häQF䲎9ŤŞJ€ß±§žp*ŘűÉŤňb^%¤ŞHŚ…Ť¨ ŻŘ½ź\Ľ:źôŇŻNF?ľb§Çěđôdr>>x39=0s/ý4qčŰłş(âĄŘb1‰¨ŚÄˇBO*CĎľC–r'|’ĐK-řĚ@bż˛KÄBIJ†%Ýş¤´—SV7§‘-¸ů÷żŠyĘ ĽyÄż„ ».@Ţ~ŽĚčwěŮćWĚnâŃ_|óŚ=Ýa?đ¤c˝´˛ý‹…HĹćăRbŢ/ĚĽź’„Ţ®®C{śYH|”_îV5¸’$¤>eU\Rá@ ÷ÇC}ĎîĚPßj”ô|ő˛Qš=Ň꯴}é×AăÔ›_ ›uPkZ¤âE\sĹŤÚ şĐ‚]™•ë皤Ë8ăGBJr.r]ŕR+c«řL´ň{ňĐ8‰{§ŕ”JŠÄ­8xîgA¤ş§‹“”v¸Ŕ Duhł<0TÂ0*Čgncn©źâľMaÂ;Ç“Ľ—úđ D˘Uú;3čá0ŻŤ?cúËjÔľĆáś\¦¬Su9ĹßśîĄ.– –űŇZúŔž0îK54Ű%XPT’ żÄ ®CúSpÔÝźţ‹ $‰5˛žýß~ýçďů˛;^·×†Ţ÷“[×w|fľQ‚{oš×~…+Í/Ĺ-÷˘Í /q•ßC®Éá¬VŇĎřąćŃ7»ůĄG%O˝ýv‹•{T-gXÚÔ ´I®u¦rĂţ"Ë«űc|hÚîxô'0âďýśÜőć8Ăf}:ásĎFłĚčňš–ÚĚŁK?Ęn»”Ëý3˝ÔC *Ę_}P°Q;ÂĄ3+«¦mŢnîlsz­şˇQČęÚ!ť\±¦«ů{ôĹißzéQˇdŤY }Wbu)pś×.×Fţć÷ 8]Ĺz×ÔŞ+ ‘¸ş§ű桋d]ÓŤ_‘á…fÝrż¦ĎŹAOëΉŠ>IĽ·Ň{űÝ~DŞŰ•äW\‹µfÚnŽŔPgzpě ÜÓůµ)˝t@ô+Ü0Ů(†Ľ!pcUđIż)q7ŻSWE^Ż­íJ{ôRJĽsĚ:QŃŕ=âB‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $‰/ŹÄ&öÎ.÷ęăĎ´u– éă ‰O·?čďţQWI„ Ž n ćZľ*…žţx6:yËđő#ţ}#ą0bÚtUk¬Kďň­EľĚ¨°®}oqź_Ž…u„_ĽĚ†zf üŠ~Ţžľ9_*'ľîę·_˙×v…ż†±rłTłžjˇißénÄ\bMY cŘĺ«PŻëŠĘEmŠ‚x–ISĆ72ľsnń˝Ú—qľąBMKK˝ô@/ç—ó/€-ĄÂşWŇ‚CúZ4ľLÖŐš5ďqÍţľýÉżä>Ővx).ĐíR!˛ës[}"ş2šĽ9÷/`;=>ľ:ďbóĚ„¤4\ ŽFĎT˝t˛9ÎÎÇ'“WG¬}÷Ü͢÷]ĘÉxňzUĽĎ"qÇ]áB‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚ $ B‚¸ĎHl´ÄŇSü™6l’!}ś!ÝZR «ą°Ă®şÍČZ9SXEŤfFřz ·Ľ/YRęŚĎŐ/#çZ‹Ąw¶Ř1hn¦uę‹‘Ŕ™5źÂŁ% I#,CfD"dĺ°‚É"—IÎĆŚ'—J/ ‘ÎÄŤW‹,lĘ&?RƶDÂáéÉä||đfrzĘBÄzY΀ieÂřQ7˙ţW1Oy!”eGÜńKĐD]«°˛aŔ*Ë-!ç ™“®ľh˲şÖĂ®¦”ŻżĺĎ´ˇʲ×#,ÍÝV&”«b‡97př4Ńş°ţÓą¨tüńBó /ݱT(łă‰±-qŢ”płF¤ľËźkí^^Ä3·GCfëéO"qxk_L{9_Rj* ˝Řb“÷Ö®ax·Űnöwm.Ă'ß Ăď «c.ß^WĚę}ZÁ6ŰG÷·ă(ľ«˙Uť…bűd!ŕPkޤ…»g`rđ¨^u ic# 2XĽ‡;O'áW™÷…9<ž­á6+ĎŠ0Pˇ-"çOEÎO·ţ€Ź8:Ţ+fŔaíViőXĽ—˛`˘-ů`1&+Ľ{Ç{(·Äű©¶z ±ÓUăp¸—.Ä#ü—áĎ|H<ůą–W: ěn*î0_С4ťÉx"VęeęÍ×jÝ„:>¤ÖKu)+Vjč˙)ö‚KşôSY°†VBç@·˝˘€N)ľ†rŢÔ—ëKݱCu,ĂÉ7*{Z9µË“‡ĚwHÚ!„E gBŹÉÔÓB&A% ř ýOT‰ő…S^Á´ ď)ű¨ ö®,vmNż7¨Ŕ„™‹Ż,+ôv9ţX€@o¸.×µcF7ĽgŻ(d)]L‘ĽĹşä9&Ô{\µµŻGO­×`<t4´‡P¶3ť)vqpíž\He.˝BđâëcĘżL 6×ĆöRMű19ąYP^¶>Ćż¨Ş€I1ĎZ¶ö|%ć1Â{%2Č]ĐÉů\Ŕł3äŔeěŕ‹ŐĐ"xŽČbmÚŤ÷´ňlÔGz(LUQéEŐč‡čŤ:ÔćĹ$ÄđÄ­(lR”JfŤżőÓKeäÜ”ÝÇĐwd:Ë€›‘tEYşń¤‹BňY¶™q©¬ó±˙‹ĆűúńpZâ€z© °í”—3ŰŐ!9ç´Q˘éŇT ­ügšÁ´:8"`h˘âŇ=!]ŔZ«^Ş'‰®•Ź]9›‚ŘcbI ĄŤż„Çľfőé¤AW)ůĄXVóďvzkśAŠŽ/›U#i#˝ŐđÎĽŔi÷&?ŻFŹjz©ŠN~ćÇWç‡?ŚN&Łńëńä-ÚÇńxrňę₟žł;ťOƇo^ŹÎŮŮ›ółÓ‹W4zC‘ĚzëpÄ&Ýe˙Ŕ„€ăđ˙˙EÝ‹"$î ›đ휺٠/É©ď‘)w‰M8őwşë3˙z¶0Ňáh9†Í…ŔQOK®~ ڏ+HlÂŐqi$í’G“­Űe Ý"$ BâËn ›úúmЏ+H|Ť@÷}ÔŐŤP´Ëđţ8!qWŘ̤AY¬üÜAŁkĂ/ĂŇmZĽ?¶EH„ÄgŕŰ㸠tą<Ô™´®Ýű»Ŕ–~ńiü&OŕdĆY"ťüE(¦łď–ďŹ „!ńhůďH»Ťŕ =IwŞŤ"˛˝G†EH„Äçs«™ü(ą,OSÜä@÷ĚČ B‚ř"Ä»JąCf5„ż,áŠ>f~ßxę+ÚÝjĽťîbSž\2§ű8íµÂSsĽ‰ $‰ĎÝĂŕÖg)2– ›YyDb/â‹ČiŤżßŁ#$ BÂņ?r¨ ®f˛6ÔaÁÁęXŢ#řŚ›Pr$TfUbqýddg'T<ůŹÇ¸­H\Ľ}SuŇ)ńÎáj° _5»@óYě vvľ}ňÂ[|~ńÍłoÚ~ÄŃő]OzöĎńS ËŻąŕ©05~qşZÉ´vÝ‘©vN—ËłÚĹńV'u9 Źš•Đ|*Ů!5hĎŚv­/lÂHGŇ_ĄĂËL¦ápŞ“ďŤLYĐ6›ńşpř…TâLş$GGńĎ‹PÇëůÓoźűbgçżv"­B·Q”´ń ńÓŞý˙PKÁ¤´Č3PK …•FdocProps/app.xmlť±NĂ0†wž"˛ş&NÓµ•ă „*Ń! ¶ČŘ—Ä(±-űRĄoŹ©tfüî?}úďŘa™Ćä >hkj˛Îr’€‘ViÓ×äµyN·$ (ŚŁ5P“ rŕwěä­ŹB &Ôd@t{J`!‹±‰Igý$0˘ď©í:-áÉĘy´ČóŠÂ‚`¨Ô]…ä׸?ăĄĘĘď~á­ą¸č㬱(ĆFOŔ×ĺ.żgôoŔśµŔŹúĂĂËŹ‘–Ů&«˛buÔf^Ú÷mŐVerłĐĆĆź ‘–›|ő8ëQĄŁ·6v^ô^¸!đ]Ĺč F¸ŢËżPKŞľş|ó…PK …•FdocProps/core.xml…’MoĂ †ďűw¤šP’6ő´I“ÚjÓn¸)Z hÓţű‘¬M»©ŇŽĆŻź×ŘÎGÝ$p^µ¦@,Ą(#ŰJ™ş@›ő?˘Äa*Ń´ tŹĺC.-—­7×ZpAO"Čx.mv!XN—;ЧQabrŰ:-B ]M¬_˘’Q:'‚¨D¤b;ŃYÉi÷®•$Đ€y˛Ânâ1ä˙6}K„F< púńÇčé+›ţâ¶ą“řŹÚăŽÚęAÂep9Ź®kr*P9uń˘>|#[şđ‹g°wÉý•8«řö1PK-^PK …•FčĐ#Ů= _rels/.relsPK …•FÉŁnKĘword/settings.xmlPK …•F—žë+Şword/_rels/document.xml.relsPK …•FÁÇŮUword/fontTable.xmlPK …•FčĘ’mÁŇ ŕword/styles.xmlPK …•FÁ¤´Č3Ţword/document.xmlPK …•FŞľş|ó…ŃdocProps/app.xmlPK …•F1ÍxT7LdocProps/core.xmlPK …•F-^x[Content_Types].xmlPK <ćgammaray-2.3.0/docs/Mainpage.dox000066400000000000000000000054051255003167400165060ustar00rootroot00000000000000/*! @mainpage GammaRay - Qt-application inspection and manipulation tool. @section about About GammaRay is a tool to poke around in a Qt-application and also to manipulate the application to some extent. GammaRay uses various DLL injection techniques to hook into an application at runtime and provide access to a lot of interesting information. @section plugins Plugins Starting with version 1.2, GammaRay provides the ability to write your own plugins. This documentation describes the API for doing just that. @section features Features GammaRay can: - Browse the QObject tree with live updates. - View, and to some extent, edit QObject static and dynamic properties. - View and call slots of a QObject (similar to qdbusviewer). - View other QObject elements such as signals, enums and class information introspectively. - List all QObject inbound and outbound signal/slot connections. - Provide live widget preview. Useful for finding layout issues). - View the content of any QAbstractItemModel (QAIM). Very useful when debugging a proxy model chain for example. - Browse the QAbstractProxyModel (QAPM) hierarchy. - Browse the QGraphicsView (QGV) item tree of any QGV scene. - Show a live preview of QGV items, including showing their coordinate system, transformation origin, rotate/zoom/pan, etc. - Act as a complete java script debugger, attachable to any QScriptEngine (including the usually not accessible one used by QML internally). - Perform HTML/CSS/DOM/JS introspection/editing/profiling on any QWebPage, thanks to QWebInspector. - Browse the QResource tree and its content. - Browse QStateMachines, along with their states and transitions. - Show all registered meta types. - Show all installed fonts. - Show all available codecs. - Browse all QTextDocuments, along with the ability to edit them and view their internal structures. - Show all QTimers and their statistics (number of wakeups, wakeup time, ...) @section license License The GammaRay Software is (C) 2010-2015 Klarälvdalens Datakonsult AB (KDAB), and is available under the terms of the GPL version 2 (or any later version, at your option). See LICENSE.GPL.txt for license details. Commercial use is also permitted as described in ReadMe-commercial.txt. @section about-KDAB About KDAB GammaRay is supported and maintained by Klarälvdalens Datakonsult AB (KDAB) KDAB, the Qt experts, provide consulting and mentoring for developing Qt applications from scratch and in porting from all popular and legacy frameworks to Qt. We continue to help develop parts of Qt and are one of the major contributors to the Qt Project. We can give advanced or standard trainings anywhere around the globe. Please visit http://www.kdab.com to meet the people who write code like this. @namespace GammaRay All GammaRay classes. */ gammaray-2.3.0/docs/footer.html000066400000000000000000000011571255003167400164350ustar00rootroot00000000000000
Klarälvdalens Datakonsult AB (KDAB)
"The Qt Experts"
http://www.kdab.com/
GammaRay
Qt-application inspection and manipulation tool
http://www.kdab.com/kdab-products/gammaray/
gammaray-2.3.0/docs/gammaray.pod000066400000000000000000000112311255003167400165450ustar00rootroot00000000000000=head1 NAME GammaRay - Qt-application inspection and manipulation tool. =head1 SYNOPSIS gammaray [--pid | | --connect [:] =head1 DESCRIPTION GammaRay inspects runtime internals of a Qt-application, such as: Object tree, properties, signal/slots, widgets, models, graphics views, javascript debugger, resources, state machines, meta types, fonts, codecs, text documents When run without any options, gammaray will present a list of running Qt-applications from which you can attach the selected injector. Else, you can attach to a running process by specifying its pid, or you can start a new Qt-application by specifying its name (and optional arguments). =head1 OPTIONS =over 4 =item B<--help> Print help message and exit. =item B<--version> Print version information and exit. =item B<-p, --pid > Attach to running Qt application with the specified pid. =item B<-i, --injector > Set the specified injection type. Supported injectors are: preload (Linux, Mac OS) gdb (Linux. requires gdb to be installed) style windll (Windows) =item B<--inprocess> Use the Gammaray 1.x in-process UI. This is not necessary in most cases, apart from using tools that do not work remotely. =item B<--inject-only> This will only inject the GammaRay probe into a process, but not start the GammaRay UI. This is useful for example when doing remote debugging on embedded devices. =item B<--listen
> Specify on which network address the GammaRay server should listen, default is 0.0.0.0 (ie. all of them). This can be used for example on Windows to avoid firewall warnings by setting the address to 127.0.0.1 if you don't need remote access. =item B<--no-listen> Disables the GammaRay server. This implies --inprocess as there is no other way to connect to the GammaRay probe in this case. =item B<--list-probes> List all installed probes. =item B<--probe > Explicitly specify which probe to use. You should use this if you have more than one probe installed (e.g. one for Qt4 and one for Qt5), until probe ABI auto-detection is implemented. =item B<--connect [:port]> Connect to a target with an already injected GammaRay probe. Useful for example for remote debugging. =back =head1 EXAMPLES =over 4 =item Run gammaray on the Qt-application C with command line arguments 'arg1' and 'arg2': % gammaray /path/to/qtfoo arg1 arg2 =item Invoke gammaray on the Qt-application running with pid 1234: % gammaray --pid 1234 =item Invoke gammaray on with injector gdb on Qt-application running with pid 1234: % gammaray --injector gdb --pid 1234 =back =head1 EXIT STATUS Exits with 0 under normal operation; otherwise, exists with a positive integer indicating a problem occurred while launching or attaching an injector. =head1 COPYRIGHT Copyright (C) 2010-2015 Klaralvdalens Datakonsult AB, a KDAB Group company, Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. StackWalker code Copyright (c) 2005-2009, Jochen Kalmbach, All rights reserved. =head1 AUTHORS Allen Winter Andreas Holzammer Anton Kreuzkamp David Faure Frank Osterfeld James Turner Jan Dalheimer Kevin Funk Laurent Montel Mathias Hasselmann Milian Wolff Patrick Spendrin Peter Kuemmel Rafael Roquetto Stephen Kelly Thomas McGuire Till Adam Tobias Koenig Volker Krause =cut gammaray-2.3.0/docs/kdab-gammaray-logo-16x16.png000066400000000000000000000016221255003167400211720ustar00rootroot00000000000000‰PNG  IHDRó˙asRGB®ÎébKGD˙˙˙ ˝§“ pHYs × ×B(›xtIMEŰ $3a†/IDAT8Ë]“_huÇ?ż˝»Ý»Ű˝ IĽ\s¦MJŢŞ5‚M°QZjE¬$|0V¨o ˘}«Ąµ †…*Ň@ű"ŠĐ¦ńˇôAŠmúG­pG·Iš?·ŮÝßîíř6)™Ď|™aŘôôôEǶwÜË#­ÉćeÔ=ďĎáááÇéččHm@;ź9wN€@^“{ńý>{ţĽŐjµŐuÝ˙D¤*"ŢĽëĘS##©‰ZĚ'ż\`áć5Ž\śăč•…őŃN€FŁ@0JĄ’ ` u Ş5®_řSߥű•śţq’îŢťë€F €Ö e÷»źA•vb›&/˝Ć‰ń7I›(÷ď"W*sěŤýŚOśä…wާ{pˇż¶ˇ€¬e’ďí&NLO}Ë[_|Í—ڱĺéj3g˙éWŹîCŮEDkcŁ•-rź}sâ+éŘ-ÇŻŻČÁź«Ň%źť˝$'« ˝ýž¤şz¤tLNť># ˘("P)B’onáĐ‹,V«|:ůßţKłłěŮ˙2NK+}»úYľUŰÜA*ĄpoŻ’µ˛č@cZ9ZĘí´níaÁu)>T&×ÖÎ_ss9vś‰©©»×Ľ«Ŕ÷|l3ÄH„Z“ÉYd#‡ŕůŮĽŤ‘ÉP˝=Ďĺą«,Ő=˘(ޤM‹BsD˘+›GĹ T:CX¶Ť2Rôő=ÁÜŤŽC¤ŁM€eeH’KwVĂL.G’40M?ŽČäóâ…ˇH*Ĺ•ż˙!…ÖÚX\ľł@Fär…bűŠ J5 ń*d µwôU•$  őčv.˙{S@=§}>)żÍĚŠ»´˘Ö‚€şďSŻ{$~‚5Hb°H (ˇ`ĄinrŘŃ»M†ž}FĄ{nĄso?ÍM6=[+lë®ĐÚ^Ú|;·VăŕGR©tQy¤“ÎÎNÚĘíŘŽC:Id(N’çm_őý¶Ĺĺz[ľPp Ă0CZZGÜš_ 㽆uĎ\ĎÜPëky‘3˙e·iŕpn%IEND®B`‚gammaray-2.3.0/docs/kdab-logo-16x16.png000066400000000000000000000014241255003167400173760ustar00rootroot00000000000000‰PNG  IHDRKÖűlŰIDAT8Ëť”MLSAÇgű^űh)M©…6|D%VP15špĐÄ‹$I8hâIÔ1žÔp0Q@šH &Ô BE)”VݶB‹…BiKëëÇŰ·ĎCAÁ`Úş·™Ěüć?3»‹A€ÔϢ/ě_ nĎŃäc ߌ~ť°Ĺ͔ǷvΚ¦Ľ Ťâ:µüyŇĺ29ýڦ¨Ô±yÚ=Ż·L!vҶýö'ŰH4JZş\oÍâě8]V´qI!"ľąÓő~Ŕާ ­·/Şł5ćS@°ţ±ÁĄ·L˘˝M×k˛ru<ůŁNT·t̬ö´…Ď®ťĎ/(B$ŮH8Jš sćďLäo¨;'RŢĐO!´1ěź*ĽAţţ+‹uÖ'—1Şś}ĎGŁíuVĚţäÎ%‘ÄAŢueAGuž8&Ö:Č1a.bćoÔ3rwbB¨ćd%@ĄÇǵô,Úűzdxn^®UdfHRŤŔĚB¤ůËŘg,׮޺R#ÍPŻW€¤Ćé\d[şgÍ–ů»W/H3ÔÝ#+=C ›ßöÖ* Vףö~N®-Đ•îŃ>3ńÖéńʦ3‡2+JuÉŘĂ»ë*TĂßćôVď'#&‘Ő]ĘH}YÉŃĂ… g!ˇéŠ# ę84Düó ‰Öh5@ĄÇŇzăÍŘ„ !ľkĚks‡1OvŞ%ŐĄšüJrÇşÇÜţ°\‚2eb1%ÚńĹɶő»gÝnűč ĹĹŚŚVćFuZ•"Âqv‡mÉe“ LË”ŞĽ"Ža}k›ÓÓŘôbÉ·˛W#ąW[ľżx·˘áÉ™—†Áˇ‘ĺ4+Î9u¶*7';dőý“í=c)[[qüűĹűŚ1Ă0rąś¦(„!„eY–eˇt™L*•ŠD"A0ơP˘(…Bż‰XT“ęâő IEND®B`‚gammaray-2.3.0/gammaray+sme+kde-qt5.spec000066400000000000000000000141621255003167400200210ustar00rootroot00000000000000Name: gammaray Version: 2.2.50+git20150705 Release: 1 Summary: An introspection tool for Qt applications Source: %{name}-%{version}.tar.bz2 Url: http://github.com/KDAB/GammaRay Group: Development/Tools License: GPL-2.0+ BuildRoot: %{_tmppath}/%{name}-%{version}-build Vendor: Klaralvdalens Datakonsult AB (KDAB) Packager: Klaralvdalens Datakonsult AB (KDAB) BuildRequires: cmake BuildRequires: libqt5-qtdeclarative-private-headers-devel libQt5Concurrent-devel libqt5-qttools-devel libqt5-qtsvg-devel libQt5PrintSupport-devel libqt5-qtscript-devel libQt5WebKitWidgets-devel # TODO: this seems only to be in the update repo? # libqt5-qtconnectivity-devel BuildRequires: kdstatemachineeditor-devel BuildRequires: kcoreaddons-devel %if %{defined suse_version} BuildRequires: update-desktop-files %endif %if %{defined fedora} BuildRequires: desktop-file-utils %endif %description GammaRay is a tool for examining the internals of a Qt application and to some extent also manipulate it. GammaRay uses injection methods to hook into an application at runtime and provide access to a wide variety of interesting information. It provides easy ways of navigating through the complex internal structures you find in some Qt frameworks, such as QGraphicsView, model/view, QTextDocument, state machines and more. Authors: -------- The GammaRay Team %package kf5-plugins Summary: GammaRay plug-ins to introspect KF5 applications Group: Development/Tools Requires: %{name} = %{version} %description kf5-plugins Plug-ins for the GammaRay introspection tool to debug KF5 applications, such as a KJob tracker. %package devel Summary: Development files for %{name} Group: Development/Libraries Requires: %{name} = %{version} %description devel The %{name}-devel package contains libraries and header files for developing GammaRay plug-ins. %prep %setup -q %build %if %{defined fedora} %cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %else %if "%{_lib}"=="lib64" cmake . -DLIB_SUFFIX=64 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %else cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %endif %endif %__make %{?_smp_mflags} %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %install %make_install %if %{defined suse_version} %suse_update_desktop_file GammaRay Development Qt Debugger %endif %clean %__rm -rf "%{buildroot}" %files %defattr(-,root,root) %{_prefix}/share/applications/GammaRay.desktop %dir %{_prefix}/share/appdata/ %{_prefix}/share/appdata/GammaRay.appdata.xml %{_prefix}/share/icons/hicolor %{_prefix}/share/doc/gammaray %{_mandir}/man1/gammaray.1.gz %{_bindir}/gammaray %dir %{_libdir}/gammaray/libexec/ %{_libdir}/gammaray/libexec/gammaray-client %{_libdir}/gammaray/libexec/gammaray-launcher %{_libdir}/libgammaray_common-*.so.* %{_libdir}/libgammaray_core-*.so.* %{_libdir}/libgammaray_ui-*.so.* %{_libdir}/libgammaray_client.so.* %dir %{_libdir}/gammaray/ %dir %{_libdir}/gammaray/*/ %dir %{_libdir}/gammaray/*/*/ %{_libdir}/gammaray/*/*/libgammaray_widget_export_actions.so %{_libdir}/gammaray/*/*/gammaray_probe.so %{_libdir}/gammaray/*/*/gammaray_inprocessui.so %{_libdir}/gammaray/*/*/gammaray_actioninspector* %{_libdir}/gammaray/*/*/gammaray_codecbrowser* %{_libdir}/gammaray/*/*/gammaray_fontbrowser* %{_libdir}/gammaray/*/*/gammaray_selectionmodelinspector* %{_libdir}/gammaray/*/*/gammaray_signalmonitor* %{_libdir}/gammaray/*/*/gammaray_statemachineviewer* %{_libdir}/gammaray/*/*/gammaray_timertop* %{_libdir}/gammaray/*/*/gammaray_widgetinspector* %{_libdir}/gammaray/*/*/gammaray_sceneinspector* %{_libdir}/gammaray/*/*/gammaray_styleinspector* %{_libdir}/gammaray/*/*/gammaray_scriptenginedebugger* %{_libdir}/gammaray/*/*/gammaray_webinspector* %{_libdir}/gammaray/*/*/gammaray_objectvisualizer* %{_libdir}/gammaray/*/*/gammaray_qmlsupport* %{_libdir}/gammaray/*/*/gammaray_quickinspector* %{_libdir}/gammaray/*/*/gammaray_translatorinspector* %{_libdir}/gammaray/*/*/styles/ %files kf5-plugins %defattr(-,root,root) %{_libdir}/gammaray/*/*/gammaray_kjobtracker* %files devel %defattr(-,root,root) %{_includedir}/gammaray %{_libdir}/libgammaray_common-*.so %{_libdir}/libgammaray_core-*.so %{_libdir}/libgammaray_ui-*.so %{_libdir}/libgammaray_client.so %{_libdir}/cmake/GammaRay/ %{_libdir}/qt5/mkspecs/modules/* %changelog * Tue Jan 27 2015 Allen Winter 2.2.1 2.2.1 final * Fri Oct 31 2014 Allen Winter 2.2.0 2.2.0 final * Thu Oct 23 2014 Allen Winter 2.1.2 2.1.2 final * Sat Aug 30 2014 Allen Winter 2.1.1 2.1.1 final * Fri Jun 27 2014 Allen Winter 2.1.0 2.1.0 final * Thu Jun 26 2014 Allen Winter 2.0.98 2.1.0 release candidate 1 * Fri Apr 18 2014 Allen Winter 2.0.2 2.0.2 final * Fri Feb 28 2014 Allen Winter 2.0.1 2.0.1 final * Fri Jan 17 2014 Allen Winter 2.0.0 2.0.0 final * Sat Jan 11 2014 Allen Winter 1.9.96 Second 2.0 beta release * Fri Dec 20 2013 Allen Winter 1.9.95 First 2.0 beta release * Thu Oct 03 2013 Allen Winter 1.3.2 Second 1.3 bugfix release * Tue Apr 30 2013 Allen Winter 1.3.1 First 1.3 bugfix release * Sun Jan 27 2013 Allen Winter 1.3.0 Update to latest release * Wed Jun 27 2012 Allen Winter 1.1.98 - Rename version to use all integers * Tue Jun 26 2012 Allen Winter 1.2beta - Update to beta release * Wed Jun 20 2012 Allen Winter 1.2prebeta - Update to prebeta release * Tue Jan 10 2012 Kevin Ottens 1.1.0 - Update to latest release * Sun Jan 8 2012 Kevin Ottens 1.0.98.20120108 - Grabbing a new snapshot * Wed Dec 21 2011 Kevin Ottens 1.0.1 - First packaging gammaray-2.3.0/gammaray-qt4.spec000066400000000000000000000124301255003167400164750ustar00rootroot00000000000000Name: gammaray-qt4 Version: 2.3.0 Release: 1 Summary: An introspection tool for Qt applications Source: gammaray-%{version}.tar.gz Url: http://github.com/KDAB/GammaRay Group: Development/Tools License: GPL-2.0+ BuildRoot: %{_tmppath}/%{name}-%{version}-build Vendor: Klaralvdalens Datakonsult AB (KDAB) Packager: Klaralvdalens Datakonsult AB (KDAB) # this package only contains the Qt4 probe, pull in the client from the Qt5 version Requires: gammaray = %{version} BuildRequires: cmake %if %{defined suse_version} BuildRequires: libqt4-devel libQtWebKit-devel libkde4-devel %endif %if %{defined fedora} BuildRequires: qt-devel qtwebkit-devel kdelibs-devel %endif %description GammaRay is a tool for examining the internals of a Qt application and to some extent also manipulate it. GammaRay uses injection methods to hook into an application at runtime and provide access to a wide variety of interesting information. It provides easy ways of navigating through the complex internal structures you find in some Qt frameworks, such as QGraphicsView, model/view, QTextDocument, state machines and more. This package only contains the Qt4 probe; pull in the client from gammaray-qt5 package. Authors: -------- The GammaRay Team %package kde4-plugins Summary: GammaRay plug-ins to introspect KDE4 applications Group: Development/Tools Requires: %{name} = %{version} %description kde4-plugins Plug-ins for the GammaRay introspection tool to debug KDE4 applications, such as a KJob tracker. %prep %setup -q %build %if %{defined fedora} %cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DGAMMARAY_PROBE_ONLY_BUILD=ON %else %if "%{_lib}"=="lib64" cmake . -DLIB_SUFFIX=64 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DGAMMARAY_PROBE_ONLY_BUILD=ON %else cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DGAMMARAY_PROBE_ONLY_BUILD=ON %endif %endif %__make %{?_smp_mflags} %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %install %make_install %clean %__rm -rf "%{buildroot}" %files %defattr(-,root,root) %{_libdir}/libgammaray_common-*.so.* %{_libdir}/libgammaray_core-*.so.* %{_libdir}/libgammaray_ui-*.so.* %dir %{_libdir}/gammaray/ %dir %{_libdir}/gammaray/*/ %dir %{_libdir}/gammaray/*/*/ %{_libdir}/gammaray/*/*/libgammaray_widget_export_actions.so %{_libdir}/gammaray/*/*/gammaray_probe.so %{_libdir}/gammaray/*/*/gammaray_inprocessui.so %{_libdir}/gammaray/*/*/gammaray_codecbrowser* %{_libdir}/gammaray/*/*/gammaray_fontbrowser* %{_libdir}/gammaray/*/*/gammaray_selectionmodelinspector* %{_libdir}/gammaray/*/*/gammaray_signalmonitor* %{_libdir}/gammaray/*/*/gammaray_statemachineviewer* %{_libdir}/gammaray/*/*/gammaray_timertop* %{_libdir}/gammaray/*/*/gammaray_actioninspector* %{_libdir}/gammaray/*/*/gammaray_widgetinspector* %{_libdir}/gammaray/*/*/gammaray_sceneinspector* %{_libdir}/gammaray/*/*/gammaray_styleinspector* %{_libdir}/gammaray/*/*/gammaray_scriptenginedebugger* %{_libdir}/gammaray/*/*/gammaray_webinspector* %{_libdir}/gammaray/*/*/gammaray_objectvisualizer* %{_libdir}/gammaray/*/*/styles/ %exclude %{_libdir}/cmake/GammaRay/* %exclude %{_libdir}/*.so %exclude %{_prefix}/mkspecs/modules/* %exclude %{_prefix}/share/icons/hicolor/* %files kde4-plugins %defattr(-,root,root) %{_libdir}/gammaray/*/*/gammaray_kjobtracker_plugin.so %{_libdir}/gammaray/*/*/gammaray_kjobtracker.desktop %{_libdir}/gammaray/*/*/gammaray_kjobtracker_ui_plugin.so %{_libdir}/gammaray/*/*/gammaray_kjobtracker_ui.desktop %changelog * Fri Jul 10 2015 Allen Winter 2.3.0 2.3.0 final * Tue Jan 27 2015 Allen Winter 2.2.1 2.2.1 final * Fri Oct 31 2014 Allen Winter 2.2.0 2.2.0 final * Thu Oct 23 2014 Allen Winter 2.1.2 2.1.2 final * Sat Aug 30 2014 Allen Winter 2.1.1 2.1.1 final * Fri Jun 27 2014 Allen Winter 2.1.0 2.1.0 final * Thu Jun 26 2014 Allen Winter 2.0.98 2.1.0 release candidate 1 * Fri Apr 18 2014 Allen Winter 2.0.2 2.0.2 final * Fri Feb 28 2014 Allen Winter 2.0.1 2.0.1 final * Fri Jan 17 2014 Allen Winter 2.0.0 2.0.0 final * Sat Jan 11 2014 Allen Winter 1.9.96 Second 2.0 beta release * Fri Dec 20 2013 Allen Winter 1.9.95 First 2.0 beta release * Thu Oct 03 2013 Allen Winter 1.3.2 Second 1.3 bugfix release * Tue Apr 30 2013 Allen Winter 1.3.1 First 1.3 bugfix release * Sun Jan 27 2013 Allen Winter 1.3.0 Update to latest release * Wed Jun 27 2012 Allen Winter 1.1.98 - Rename version to use all integers * Tue Jun 26 2012 Allen Winter 1.2beta - Update to beta release * Wed Jun 20 2012 Allen Winter 1.2prebeta - Update to prebeta release * Tue Jan 10 2012 Kevin Ottens 1.1.0 - Update to latest release * Sun Jan 8 2012 Kevin Ottens 1.0.98.20120108 - Grabbing a new snapshot * Wed Dec 21 2011 Kevin Ottens 1.0.1 - First packaging gammaray-2.3.0/gammaray.dsc000066400000000000000000000004431255003167400156070ustar00rootroot00000000000000Format: 1.0 Source: gammaray Version: 2.3.0 Binary: gammaray Maintainer: Allen Winter Architecture: any Build-Depends: debhelper (>= 4.1.16), cdbs, cmake, libqt4-dev, libqtwebkit-dev, graphviz-dev Files: 00000000000000000000000000000000 00000 gammaray-2.3.0.tar.gz gammaray-2.3.0/gammaray.spec000066400000000000000000000142571255003167400160000ustar00rootroot00000000000000Name: gammaray Version: 2.3.0 Release: 1 Summary: An introspection tool for Qt applications Source: %{name}-%{version}.tar.gz Url: http://github.com/KDAB/GammaRay Group: Development/Tools License: GPL-2.0+ BuildRoot: %{_tmppath}/%{name}-%{version}-build Vendor: Klaralvdalens Datakonsult AB (KDAB) Packager: Klaralvdalens Datakonsult AB (KDAB) BuildRequires: cmake BuildRequires: libqt5-qtdeclarative-private-headers-devel libQt5Concurrent-devel libqt5-qttools-devel libqt5-qtsvg-devel libQt5PrintSupport-devel libqt5-qtscript-devel libQt5WebKitWidgets-devel # TODO: this seems only to be in the update repo? # libqt5-qtconnectivity-devel BuildRequires: kdstatemachineeditor-devel BuildRequires: kcoreaddons-devel %if %{defined suse_version} BuildRequires: update-desktop-files %endif %if %{defined fedora} BuildRequires: desktop-file-utils %endif %description GammaRay is a tool for examining the internals of a Qt application and to some extent also manipulate it. GammaRay uses injection methods to hook into an application at runtime and provide access to a wide variety of interesting information. It provides easy ways of navigating through the complex internal structures you find in some Qt frameworks, such as QGraphicsView, model/view, QTextDocument, state machines and more. Authors: -------- The GammaRay Team %package kf5-plugins Summary: GammaRay plug-ins to introspect KF5 applications Group: Development/Tools Requires: %{name} = %{version} %description kf5-plugins Plug-ins for the GammaRay introspection tool to debug KF5 applications, such as a KJob tracker. %package devel Summary: Development files for %{name} Group: Development/Libraries Requires: %{name} = %{version} %description devel The %{name}-devel package contains libraries and header files for developing GammaRay plug-ins. %prep %setup -q %build %if %{defined fedora} %cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %else %if "%{_lib}"=="lib64" cmake . -DLIB_SUFFIX=64 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %else cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_USE_QT_SYS_PATHS=ON %endif %endif %__make %{?_smp_mflags} %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %install %make_install %if %{defined suse_version} %suse_update_desktop_file GammaRay Development Qt Debugger %endif %clean %__rm -rf "%{buildroot}" %files %defattr(-,root,root) %{_prefix}/share/applications/GammaRay.desktop %dir %{_prefix}/share/appdata/ %{_prefix}/share/appdata/GammaRay.appdata.xml %{_prefix}/share/icons/hicolor %{_prefix}/share/doc/gammaray %{_mandir}/man1/gammaray.1.gz %{_bindir}/gammaray %dir %{_libdir}/gammaray/libexec/ %{_libdir}/gammaray/libexec/gammaray-client %{_libdir}/gammaray/libexec/gammaray-launcher %{_libdir}/libgammaray_common-*.so.* %{_libdir}/libgammaray_core-*.so.* %{_libdir}/libgammaray_ui-*.so.* %{_libdir}/libgammaray_client.so.* %dir %{_libdir}/gammaray/ %dir %{_libdir}/gammaray/*/ %dir %{_libdir}/gammaray/*/*/ %{_libdir}/gammaray/*/*/libgammaray_widget_export_actions.so %{_libdir}/gammaray/*/*/gammaray_probe.so %{_libdir}/gammaray/*/*/gammaray_inprocessui.so %{_libdir}/gammaray/*/*/gammaray_actioninspector* %{_libdir}/gammaray/*/*/gammaray_codecbrowser* %{_libdir}/gammaray/*/*/gammaray_fontbrowser* %{_libdir}/gammaray/*/*/gammaray_selectionmodelinspector* %{_libdir}/gammaray/*/*/gammaray_signalmonitor* %{_libdir}/gammaray/*/*/gammaray_statemachineviewer* %{_libdir}/gammaray/*/*/gammaray_timertop* %{_libdir}/gammaray/*/*/gammaray_widgetinspector* %{_libdir}/gammaray/*/*/gammaray_sceneinspector* %{_libdir}/gammaray/*/*/gammaray_styleinspector* %{_libdir}/gammaray/*/*/gammaray_scriptenginedebugger* %{_libdir}/gammaray/*/*/gammaray_webinspector* %{_libdir}/gammaray/*/*/gammaray_objectvisualizer* %{_libdir}/gammaray/*/*/gammaray_qmlsupport* %{_libdir}/gammaray/*/*/gammaray_quickinspector* %{_libdir}/gammaray/*/*/gammaray_translatorinspector* %{_libdir}/gammaray/*/*/styles/ %files kf5-plugins %defattr(-,root,root) %{_libdir}/gammaray/*/*/gammaray_kjobtracker* %files devel %defattr(-,root,root) %{_includedir}/gammaray %{_libdir}/libgammaray_common-*.so %{_libdir}/libgammaray_core-*.so %{_libdir}/libgammaray_ui-*.so %{_libdir}/libgammaray_client.so %{_libdir}/cmake/GammaRay/ %{_libdir}/qt5/mkspecs/modules/* %changelog * Fri Jul 10 2015 Allen Winter 2.3.0 2.3.0 final * Tue Jan 27 2015 Allen Winter 2.2.1 2.2.1 final * Fri Oct 31 2014 Allen Winter 2.2.0 2.2.0 final * Thu Oct 23 2014 Allen Winter 2.1.2 2.1.2 final * Sat Aug 30 2014 Allen Winter 2.1.1 2.1.1 final * Fri Jun 27 2014 Allen Winter 2.1.0 2.1.0 final * Thu Jun 26 2014 Allen Winter 2.0.98 2.1.0 release candidate 1 * Fri Apr 18 2014 Allen Winter 2.0.2 2.0.2 final * Fri Feb 28 2014 Allen Winter 2.0.1 2.0.1 final * Fri Jan 17 2014 Allen Winter 2.0.0 2.0.0 final * Sat Jan 11 2014 Allen Winter 1.9.96 Second 2.0 beta release * Fri Dec 20 2013 Allen Winter 1.9.95 First 2.0 beta release * Thu Oct 03 2013 Allen Winter 1.3.2 Second 1.3 bugfix release * Tue Apr 30 2013 Allen Winter 1.3.1 First 1.3 bugfix release * Sun Jan 27 2013 Allen Winter 1.3.0 Update to latest release * Wed Jun 27 2012 Allen Winter 1.1.98 - Rename version to use all integers * Tue Jun 26 2012 Allen Winter 1.2beta - Update to beta release * Wed Jun 20 2012 Allen Winter 1.2prebeta - Update to prebeta release * Tue Jan 10 2012 Kevin Ottens 1.1.0 - Update to latest release * Sun Jan 8 2012 Kevin Ottens 1.0.98.20120108 - Grabbing a new snapshot * Wed Dec 21 2011 Kevin Ottens 1.0.1 - First packaging gammaray-2.3.0/hooking/000077500000000000000000000000001255003167400147535ustar00rootroot00000000000000gammaray-2.3.0/hooking/CMakeLists.txt000066400000000000000000000035711255003167400175210ustar00rootroot00000000000000set(gammaray_probe_srcs probecreator.cpp hooks.cpp ) if(UNIX AND Qt5Core_VERSION VERSION_LESS 5.4.0) list(APPEND gammaray_probe_srcs preload.cpp) endif() if(WIN32 OR APPLE) list(APPEND gammaray_probe_srcs abstractfunctionoverwriter.cpp functionoverwriterfactory.cpp unixfunctionoverwriter.cpp ) endif() if(WIN32) list(APPEND gammaray_probe_srcs entry_win.cpp winfunctionoverwriter.cpp ) endif() if(APPLE OR NOT Qt5Core_VERSION VERSION_LESS 5.4.0) list(APPEND gammaray_probe_srcs entry_unix.cpp) endif() # probe lib if(APPLE) # DYLD_INSERT_LIBRARIES only works with real shared libraries, not modules add_library(gammaray_probe SHARED ${gammaray_probe_srcs}) set_target_properties(gammaray_probe PROPERTIES INSTALL_RPATH "@loader_path/../../../Frameworks") else() add_library(gammaray_probe MODULE ${gammaray_probe_srcs}) endif() target_link_libraries(gammaray_probe gammaray_core ) if(NOT WIN32 AND NOT QNXNTO AND NOT ANDROID) target_link_libraries(gammaray_probe dl) endif() if(NOT ANDROID) set_target_properties(gammaray_probe PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${PROBE_PLUGIN_INSTALL_DIR}" ) set_target_properties(gammaray_probe PROPERTIES PREFIX "") endif() if(ANDROID) install(TARGETS gammaray_probe EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) ecm_generate_pri_file(BASE_NAME GammaRayProbe LIB_NAME gammaray_probe DEPS "core gui network GammaRayCommon GammaRayCore" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/..) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gammaray_probe-android-dependencies.xml DESTINATION ${LIB_INSTALL_DIR}) else() install(TARGETS gammaray_probe DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}) endif() gammaray-2.3.0/hooking/abstractfunctionoverwriter.cpp000066400000000000000000000141261255003167400231650ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "abstractfunctionoverwriter.h" #include #ifdef ARCH_X86 const long worstSizeForLongJump = 10; #elif defined(ARCH_64) const long worstSizeForLongJump = 14; #else # error "Unsupported hardware architecture!" #endif using namespace GammaRay; bool AbstractFunctionOverwriter::writeShortJump(void *target, void *const func) { quint8 *cur = (quint8 *) target; //E9 relative short jump is 5 bytes long bool ret = unprotectMemory(page_align(target), roundToNextPage(5)); if (!ret) { std::cerr << "Failed to unprotect memory: " << page_align(target) << std::endl; return false; } *cur = 0xE9; cur++; *reinterpret_cast(cur) = reinterpret_cast(func) - reinterpret_cast(cur + 4); ret = reprotectMemory(page_align(target), roundToNextPage(5)); if (!ret) { std::cerr << "Failed to reprotect memory: " << page_align(target) << std::endl; return false; } return true; } bool AbstractFunctionOverwriter::writeLongJump(void *target, void *const func) { quint8 *cur = (quint8 *) target; bool ret = unprotectMemory(page_align(target), roundToNextPage(worstSizeForLongJump)); if (!ret) { std::cerr << "Failed to unprotect memory: " << page_align(target) << std::endl; return false; } *cur = 0xff; *(++cur) = 0x25; #ifdef ARCH_X86 *reinterpret_cast(++cur) = reinterpret_cast(cur) + sizeof (quint32); cur += sizeof (quint32); *reinterpret_cast(cur) = reinterpret_cast(func); #elif defined(ARCH_64) *reinterpret_cast(++cur) = 0; cur += sizeof (quint32); *reinterpret_cast(cur) = reinterpret_cast(func); #else # error "Unsupported hardware architecture!" #endif ret = reprotectMemory(page_align(target), roundToNextPage(worstSizeForLongJump)); if (!ret) { std::cerr << "Failed to reprotect memory: " << page_align(target) << std::endl; return false; } return true; } void *AbstractFunctionOverwriter::getMemoryNearAddress(void *const addr, size_t size) { Q_ASSERT(blocksize() > size); #if defined(ARCH_64) intptr_t minAddr; intptr_t maxAddr; getAddressRange(minAddr, maxAddr); minAddr = std::max(minAddr, reinterpret_cast(addr) - 0x20000000); maxAddr = std::min(maxAddr, reinterpret_cast(addr) + 0x20000000); #endif for (QList::Iterator it = memoryPool.begin(); it != memoryPool.end(); ++it) { if (it->free >= size) { #if defined(ARCH_64) if (!((intptr_t)it->mem > minAddr && (intptr_t)it->mem < maxAddr)) { continue; } #endif quint8 *mem = (quint8 *)it->mem + (it->size - it->free); it->free -= size; return mem; } } void *mem = 0; #ifdef ARCH_X86 Q_UNUSED(addr); mem = reserveMemory(0, blocksize()); #elif defined(ARCH_64) intptr_t min = minAddr / blocksize(); intptr_t max = maxAddr / blocksize(); int rel = 0; for (int i = 0; i < (max - min + 1); ++i) { rel = -rel + (i & 1); void* query = reinterpret_cast(((min + max) / 2 + rel) * blocksize()); Q_ASSERT(!((size_t)query & (pagesize() - 1))); if (isMemoryFree(query, blocksize())) { mem = reserveMemory(query, blocksize()); if (mem != 0 && reinterpret_cast(mem) > minAddr && reinterpret_cast(mem) < maxAddr) { break; } } } #else #error "Unsupported hardware architecture!" #endif if (!mem) { std::cerr << "Error could not find memory close to: " << addr << std::endl; return 0; } if (!commitMemory(mem, blocksize())) { return 0; } MemorySegment memSegment; memSegment.mem = mem; memSegment.size = blocksize(); memSegment.free = blocksize() - size; memoryPool.append(memSegment); return mem; } void *AbstractFunctionOverwriter::createTrampoline(void *const func, void *const replacement) { void *mem = getMemoryNearAddress(func, worstSizeForLongJump); if (!mem) { return 0; } bool ret = writeLongJump(mem, replacement); if (!ret) { return 0; } return mem; } AbstractFunctionOverwriter::~AbstractFunctionOverwriter() { } bool AbstractFunctionOverwriter::overwriteFunction(const QString &orignalFunc, void * const replacementFunc) { void *func = qtCoreFunctionLookup(orignalFunc); if (!func) { std::cerr << "Failed to lookup: " << orignalFunc.toLatin1().data() << std::endl; return false; } void *mem = createTrampoline(func, replacementFunc); if (!mem) { return false; } bool ret = writeShortJump(func, mem); return ret; } void *AbstractFunctionOverwriter::page_align(void *addr) const { Q_ASSERT(addr != 0); return (void *)((size_t)addr & ~(pagesize() - 1)); } size_t AbstractFunctionOverwriter::roundToNextPage(size_t addr) const { Q_ASSERT(addr != 0); return (size_t)page_align((void*)(addr + (pagesize() - 1))); } size_t GammaRay::AbstractFunctionOverwriter::blocksize() { return roundToNextPage(std::max((worstSizeForLongJump * 4), pagesize())); } gammaray-2.3.0/hooking/abstractfunctionoverwriter.h000066400000000000000000000120261255003167400226270ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ABSTRACTFUNCTIONOVERWRITER_H #define GAMMARAY_ABSTRACTFUNCTIONOVERWRITER_H #include #include #include #define __STDC_LIMIT_MACROS #if defined(HAVE_STDINT_H) #include #endif #if defined(_M_X64) || defined(__amd64) || defined(__x86_64) #define ARCH_64 #elif defined(_M_IX86) || defined(__i386__) #define ARCH_X86 #endif namespace GammaRay { class AbstractFunctionOverwriter { public: virtual ~AbstractFunctionOverwriter(); /** * Overwrites a given Qt Core 4 function with a replacement function. * @param orignalFunc original Qt Core 4 function * @param replacementFunc replacement function */ bool overwriteFunction(const QString &orignalFunc, void * const replacementFunc); protected: /** * Unprotects a memory region so that the memory can get written * @param mem start address of the memory that should be unprotected * @param size size of the memory region */ virtual bool unprotectMemory(void *mem, size_t size) = 0; /** * Restore the protection of the memory region that has been * unproteced before with unprotectMemory * @param mem start address of the memory that should be protected * @param size size of the memory region */ virtual bool reprotectMemory(void *mem, size_t size) = 0; /** * Writes a short jump at a given target to jump to a function. * NOTE: A short jump takes 5 bytes, so make sure these 5 bytes * can be written. * @param target position where the jump should be written to * @param size size of the memory region */ virtual bool writeShortJump(void *target, void * const func); /** * Writes a long jump at a given target to jump to a function. * NOTE: A short jump takes 10 bytes for x86 and 14 bytes for x64, * so make sure these 5 bytes can be written. * @param target position where the jump should be written to * @param size size of the memory region */ virtual bool writeLongJump(void *target, void * const func); /** * Get memory close to a target address. * @param addr position that should the memory be close to * @param size size of the memory region */ virtual void *getMemoryNearAddress(void * const addr, size_t size); /** * Creates a tranpoline function close to another function. * @param func function that the tranpoline should be close to * @param replacement function that the trampoline should point to */ virtual void *createTrampoline(void * const func, void * const replacement); /** * Get address range in which the program resists. * @param min min address * @param max max address */ virtual bool getAddressRange(intptr_t &min, intptr_t &max) = 0; /** * Check if the memory region is not already taken. * @param mem start address * @param size size of the memory region */ virtual bool isMemoryFree(void * const mem, size_t size) = 0; /** * Allocate memory at the griven position * @param mem start address * @param size size of the memory region */ virtual void *reserveMemory(void *mem, size_t size) = 0; /** * Commit memory at the griven position * @param mem start address * @param size size of the memory region */ virtual bool commitMemory(void *mem, size_t size) = 0; /** * Lookup function address of a given Qt Core 4 function. * @param function function name */ virtual void *qtCoreFunctionLookup(const QString &function) = 0; virtual long pagesize() const = 0; virtual size_t blocksize(); private: void *page_align(void *addr) const; size_t roundToNextPage(size_t addr) const; struct MemorySegment { void *mem; size_t size; size_t free; }; QList memoryPool; }; } #endif // ABSTRACTFUNCTIONOVERWRITER_H gammaray-2.3.0/hooking/entry_unix.cpp000066400000000000000000000026051255003167400176660ustar00rootroot00000000000000/* entry_unix.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "hooks.h" using namespace GammaRay; // we need a way to execute some code upon load, so let's abuse // static initialization class HitMeBabyOneMoreTime { public: HitMeBabyOneMoreTime() { Hooks::installHooks(); } }; static HitMeBabyOneMoreTime britney; gammaray-2.3.0/hooking/entry_win.cpp000066400000000000000000000032411255003167400174750ustar00rootroot00000000000000/* entry_win.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "hooks.h" #include #include using namespace GammaRay; extern "C" BOOL WINAPI DllMain(HINSTANCE/*hInstance*/, DWORD dwReason, LPVOID/*lpvReserved*/) { switch(dwReason) { case DLL_THREAD_ATTACH: { Hooks::installHooks(); if (!Probe::isInitialized()) { gammaray_probe_inject(); } break; } case DLL_PROCESS_DETACH: { //Unloading does not work, because we overwrite existing code exit(-1); break; } }; return TRUE; //krazy:exclude=captruefalse } gammaray-2.3.0/hooking/functionoverwriterfactory.cpp000066400000000000000000000031351255003167400230270ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "functionoverwriterfactory.h" #ifdef Q_OS_WIN #include "winfunctionoverwriter.h" #else #include "unixfunctionoverwriter.h" #endif using namespace GammaRay; AbstractFunctionOverwriter *FunctionOverwriterFactory::createFunctionOverwriter() { static AbstractFunctionOverwriter *overwriter = 0; #ifdef Q_OS_WIN if (!overwriter) { overwriter = new WinFunctionOverwriter(); } #else if (!overwriter) { overwriter = new UnixFunctionOverwriter(); } #endif return overwriter; } gammaray-2.3.0/hooking/functionoverwriterfactory.h000066400000000000000000000027261255003167400225010ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FUNCTIONOVERWRITERFACTORY_H #define GAMMARAY_FUNCTIONOVERWRITERFACTORY_H #include "abstractfunctionoverwriter.h" namespace GammaRay { class FunctionOverwriterFactory { public: static AbstractFunctionOverwriter *createFunctionOverwriter(); private: FunctionOverwriterFactory() { } }; } #endif // FUNCTIONOVERWRITERFACTORY_H gammaray-2.3.0/hooking/gammaray_probe-android-dependencies.xml000066400000000000000000000002021255003167400245160ustar00rootroot00000000000000 gammaray-2.3.0/hooking/hooks.cpp000066400000000000000000000116651255003167400166130ustar00rootroot00000000000000/* hooks.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //krazy:excludeall=cpp due to low-level stuff in here #include #include "hooks.h" #include "functionoverwriterfactory.h" #include "probecreator.h" #include #include #ifdef GAMMARAY_USE_QHOOKS #include #endif #include #include #ifdef Q_OS_MAC #include #include #include #include #endif #define IF_DEBUG(x) using namespace GammaRay; // previously installed Qt hooks, for daisy-chaining static void(*gammaray_next_startup_hook)() = 0; static void(*gammaray_next_addObject)(QObject*) = 0; static void(*gammaray_next_removeObject)(QObject*) = 0; extern "C" Q_DECL_EXPORT void gammaray_startup_hook() { Probe::startupHookReceived(); new ProbeCreator(ProbeCreator::CreateOnly); if (gammaray_next_startup_hook) gammaray_next_startup_hook(); } extern "C" Q_DECL_EXPORT void gammaray_addObject(QObject *obj) { Probe::objectAdded(obj, true); if (gammaray_next_addObject) gammaray_next_addObject(obj); } extern "C" Q_DECL_EXPORT void gammaray_removeObject(QObject *obj) { Probe::objectRemoved(obj); if (gammaray_next_removeObject) gammaray_next_removeObject(obj); } const char* gammaray_flagLocation(const char* method) { SignalSlotsLocationStore::flagLocation(method); return method; } #ifdef GAMMARAY_USE_QHOOKS static void installQHooks() { Q_ASSERT(qtHookData[QHooks::HookDataVersion] >= 1); Q_ASSERT(qtHookData[QHooks::HookDataSize] >= 6); gammaray_next_addObject = reinterpret_cast(qtHookData[QHooks::AddQObject]); gammaray_next_removeObject = reinterpret_cast(qtHookData[QHooks::RemoveQObject]); gammaray_next_startup_hook = reinterpret_cast(qtHookData[QHooks::Startup]); qtHookData[QHooks::AddQObject] = reinterpret_cast(&gammaray_addObject); qtHookData[QHooks::RemoveQObject] = reinterpret_cast(&gammaray_removeObject); qtHookData[QHooks::Startup] = reinterpret_cast(&gammaray_startup_hook); } #endif #ifdef GAMMARAY_USE_FUNCTION_OVERWRITE static bool functionsOverwritten = false; static void overwriteQtFunctions() { functionsOverwritten = true; AbstractFunctionOverwriter *overwriter = FunctionOverwriterFactory::createFunctionOverwriter(); overwriter->overwriteFunction(QLatin1String("qt_startup_hook"), (void*)gammaray_startup_hook); overwriter->overwriteFunction(QLatin1String("qt_addObject"), (void*)gammaray_addObject); overwriter->overwriteFunction(QLatin1String("qt_removeObject"), (void*)gammaray_removeObject); #if defined(Q_OS_WIN) #ifdef ARCH_64 #ifdef __MINGW32__ overwriter->overwriteFunction( QLatin1String("_Z13qFlagLocationPKc"), (void*)gammaray_flagLocation); #else overwriter->overwriteFunction( QLatin1String("?qFlagLocation@@YAPEBDPEBD@Z"), (void*)gammaray_flagLocation); #endif #else # ifdef __MINGW32__ overwriter->overwriteFunction( QLatin1String("_Z13qFlagLocationPKc"), (void*)gammaray_flagLocation); # else overwriter->overwriteFunction( QLatin1String("?qFlagLocation@@YAPBDPBD@Z"), (void*)gammaray_flagLocation); # endif #endif #endif } #endif bool Hooks::hooksInstalled() { #ifdef GAMMARAY_USE_QHOOKS return qtHookData[QHooks::AddQObject] == reinterpret_cast(&gammaray_addObject); #elif defined(GAMMARAY_USE_FUNCTION_OVERWRITE) return functionsOverwritten; #else return false; #endif } void Hooks::installHooks() { if (hooksInstalled()) return; #ifdef GAMMARAY_USE_QHOOKS installQHooks(); #elif defined(GAMMARAY_USE_FUNCTION_OVERWRITE) overwriteQtFunctions(); #endif } extern "C" Q_DECL_EXPORT void gammaray_probe_inject() { if (!qApp) { return; } printf("gammaray_probe_inject()\n"); // make it possible to re-attach new ProbeCreator(ProbeCreator::CreateAndFindExisting); } gammaray-2.3.0/hooking/hooks.h000066400000000000000000000040561255003167400162540ustar00rootroot00000000000000/* hooks.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_HOOKS_H #define GAMMARAY_HOOKS_H #include class QObject; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) #define GAMMARAY_USE_QHOOKS #endif #if (defined(Q_OS_WIN) || defined(Q_OS_MAC)) && !defined(GAMMARAY_USE_QHOOKS) #define GAMMARAY_USE_FUNCTION_OVERWRITE #endif extern "C" { extern Q_DECL_EXPORT void gammaray_startup_hook(); extern Q_DECL_EXPORT void gammaray_addObject(QObject* obj); extern Q_DECL_EXPORT void gammaray_removeObject(QObject* obj); /** Entry point for runtime attaching. */ extern Q_DECL_EXPORT void gammaray_probe_inject(); } extern Q_DECL_EXPORT const char *gammaray_flagLocation(const char *method); namespace GammaRay { namespace Hooks { /** Returns @c true if we have installed the hooks. * This is useful to avoid loops from preloaded hooks for example. */ bool hooksInstalled(); /** Install hooks, either by function overwriting or using qhooks. */ void installHooks(); } } #endif gammaray-2.3.0/hooking/preload.cpp000066400000000000000000000051461255003167400171130ustar00rootroot00000000000000/* preload.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "hooks.h" #include using namespace GammaRay; extern "C" Q_DECL_EXPORT void qt_startup_hook() { gammaray_startup_hook(); #if !defined Q_OS_MAC if (!Hooks::hooksInstalled()) { static void(*next_qt_startup_hook)() = (void (*)()) dlsym(RTLD_NEXT, "qt_startup_hook"); next_qt_startup_hook(); } #endif } extern "C" Q_DECL_EXPORT void qt_addObject(QObject *obj) { gammaray_addObject(obj); #if !defined Q_OS_MAC if (!Hooks::hooksInstalled()) { static void (*next_qt_addObject)(QObject *obj) = (void (*)(QObject *obj)) dlsym(RTLD_NEXT, "qt_addObject"); next_qt_addObject(obj); } #endif } extern "C" Q_DECL_EXPORT void qt_removeObject(QObject *obj) { gammaray_removeObject(obj); #if !defined Q_OS_WIN && !defined Q_OS_MAC if (!Hooks::hooksInstalled()) { static void (*next_qt_removeObject)(QObject *obj) = (void (*)(QObject *obj)) dlsym(RTLD_NEXT, "qt_removeObject"); next_qt_removeObject(obj); } #endif } #ifndef GAMMARAY_UNKNOWN_CXX_MANGLED_NAMES Q_DECL_EXPORT const char *qFlagLocation(const char *method) { gammaray_flagLocation(method); static const char *(*next_qFlagLocation)(const char *method) = (const char * (*)(const char *method)) dlsym(RTLD_NEXT, "_Z13qFlagLocationPKc"); Q_ASSERT_X(next_qFlagLocation, "", "Recompile with GAMMARAY_UNKNOWN_CXX_MANGLED_NAMES enabled, " "your compiler uses an unsupported C++ name mangling scheme"); return next_qFlagLocation(method); } #endif gammaray-2.3.0/hooking/probecreator.cpp000066400000000000000000000051001255003167400201420ustar00rootroot00000000000000/* probecreator.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probecreator.h" #include #include #include #include #include #include #include #define IF_DEBUG(x) using namespace GammaRay; using namespace std; ProbeCreator::ProbeCreator(Type type) : m_type(type) { //push object into the main thread, as windows creates a //different thread where this runs in moveToThread(QCoreApplication::instance()->thread()); // delay to foreground thread QMetaObject::invokeMethod(this, "createProbe", Qt::QueuedConnection); // don't propagate the probe to child processes if (qgetenv("GAMMARAY_UNSET_PRELOAD") == "1") { qputenv("LD_PRELOAD", ""); } if (qgetenv("GAMMARAY_UNSET_DYLD") == "1") { qputenv("DYLD_INSERT_LIBRARIES", ""); qputenv("DYLD_FORCE_FLAT_NAMESPACE", ""); } // HACK the webinspector plugin does this as well, but if the web view is created // too early the env var from there isn't going to reach the web process qputenv("QTWEBKIT_INSPECTOR_SERVER", "0.0.0.0:" + QByteArray::number(Endpoint::defaultPort() + 1)); } void ProbeCreator::createProbe() { // make sure we are in the ui thread Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!qApp || Probe::isInitialized()) { // never create it twice deleteLater(); return; } Probe::createProbe(m_type == GammaRay::ProbeCreator::CreateAndFindExisting); Q_ASSERT(Probe::isInitialized()); deleteLater(); } gammaray-2.3.0/hooking/probecreator.h000066400000000000000000000030701255003167400176130ustar00rootroot00000000000000/* probecreator.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBECREATOR_H #define GAMMARAY_PROBECREATOR_H #include namespace GammaRay { /** * Creates Probe instance in main thread and deletes self afterwards. */ class ProbeCreator : public QObject { Q_OBJECT public: enum Type { CreateOnly, CreateAndFindExisting }; explicit ProbeCreator(Type t); private slots: void createProbe(); private: Type m_type; }; } #endif // GAMMARAY_PROBECREATOR_H gammaray-2.3.0/hooking/unixfunctionoverwriter.cpp000066400000000000000000000064741255003167400223540ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "unixfunctionoverwriter.h" #if !defined(Q_OS_WIN) #include #include #include #include #include #include #include using namespace std; using namespace GammaRay; UnixFunctionOverwriter::UnixFunctionOverwriter() { m_pagesize = sysconf(_SC_PAGESIZE); } bool UnixFunctionOverwriter::unprotectMemory(void *mem, size_t size) { Q_ASSERT(!((size_t)mem & (pagesize() - 1))); Q_ASSERT(!((size_t)size & (pagesize() - 1))); const bool writable = (mprotect(mem, size, PROT_READ|PROT_WRITE|PROT_EXEC) == 0); Q_ASSERT(writable); return writable; } bool UnixFunctionOverwriter::reprotectMemory(void *mem, size_t size) { Q_ASSERT(!((size_t)mem & (pagesize() - 1))); Q_ASSERT(!((size_t)size & (pagesize() - 1))); const bool readOnly = (mprotect(mem, size, PROT_READ|PROT_EXEC) == 0); Q_ASSERT(readOnly); return readOnly; } bool UnixFunctionOverwriter::getAddressRange(intptr_t &min, intptr_t &max) { min = INTPTR_MIN; max = INTPTR_MAX; return true; } bool UnixFunctionOverwriter::isMemoryFree(void * const mem, size_t size) { Q_ASSERT(!((size_t)mem & (pagesize() - 1))); Q_ASSERT(!((size_t)size & (pagesize() - 1))); Q_UNUSED(mem); Q_UNUSED(size); //under unix there is no easy way to find out if a region is free or not return true; } void *UnixFunctionOverwriter::reserveMemory(void *mem, size_t size) { Q_ASSERT(!((size_t)mem & (pagesize() - 1))); Q_ASSERT(!((size_t)size & (pagesize() - 1))); // reserve a memory region with a hint and hope that it is close to the other address void *retmem = mmap(mem, size, PROT_READ|PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); if (retmem == MAP_FAILED) { return 0; } return retmem; } bool UnixFunctionOverwriter::commitMemory(void *mem, size_t size) { Q_ASSERT(!((size_t)mem & (pagesize() - 1))); Q_ASSERT(!((size_t)size & (pagesize() - 1))); Q_UNUSED(mem); Q_UNUSED(size); //under unix we don't have a commit return true; } void *UnixFunctionOverwriter::qtCoreFunctionLookup(const QString &function) { return dlsym(RTLD_NEXT, function.toLatin1()); } long GammaRay::UnixFunctionOverwriter::pagesize() const { return m_pagesize; } #endif // Q_OS_WIN gammaray-2.3.0/hooking/unixfunctionoverwriter.h000066400000000000000000000037561255003167400220210ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_UNIXFUNCTIONOVERWRITER_H #define GAMMARAY_UNIXFUNCTIONOVERWRITER_H #include #if !defined(Q_OS_WIN) #include "abstractfunctionoverwriter.h" namespace GammaRay { class UnixFunctionOverwriter : public AbstractFunctionOverwriter { protected: virtual bool unprotectMemory(void *mem, size_t size); virtual bool reprotectMemory(void *mem, size_t size); virtual bool getAddressRange(intptr_t &min, intptr_t &max); virtual bool isMemoryFree(void * const mem, size_t size); virtual void *reserveMemory(void *mem, size_t size); virtual bool commitMemory(void *mem, size_t size); virtual void *qtCoreFunctionLookup(const QString &function); virtual long pagesize() const; private: UnixFunctionOverwriter(); long m_pagesize; friend class FunctionOverwriterFactory; }; } #endif // !Q_OS_WIN #endif // UNIXFUNCTIONOVERWRITER_H gammaray-2.3.0/hooking/winfunctionoverwriter.cpp000066400000000000000000000064361255003167400221640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //krazy:excludeall=null since the WinAPI likes to use NULL #include "winfunctionoverwriter.h" #include using namespace std; using namespace GammaRay; WinFunctionOverwriter::WinFunctionOverwriter():oldProtect(0) { } bool WinFunctionOverwriter::unprotectMemory(void *mem, size_t size) { BOOL ret = VirtualProtect(mem, size, PAGE_EXECUTE_READWRITE, &oldProtect); return ret; } bool WinFunctionOverwriter::reprotectMemory(void *mem, size_t size) { BOOL ret = VirtualProtect(mem, size, oldProtect, &oldProtect); return ret; } bool WinFunctionOverwriter::getAddressRange(intptr_t &min, intptr_t &max) { SYSTEM_INFO si; GetSystemInfo(&si); min = reinterpret_cast(si.lpMinimumApplicationAddress); max = reinterpret_cast(si.lpMaximumApplicationAddress); return true; } bool WinFunctionOverwriter::isMemoryFree(void * const mem, size_t size) { Q_UNUSED(size); MEMORY_BASIC_INFORMATION mi; ZeroMemory(&mi, sizeof(MEMORY_BASIC_INFORMATION)); VirtualQuery(mem, &mi, sizeof(mi)); if (mi.State != MEM_FREE) { return false; } return true; } void *WinFunctionOverwriter::reserveMemory(void *mem, size_t size) { void *retmem = 0; retmem = VirtualAlloc(mem, size, MEM_RESERVE, PAGE_EXECUTE_READ); return retmem; } bool WinFunctionOverwriter::commitMemory(void *mem, size_t size) { void *retmem = 0; retmem = VirtualAlloc(mem, size, MEM_COMMIT, PAGE_EXECUTE_READ); return retmem != 0; } void *WinFunctionOverwriter::qtCoreFunctionLookup(const QString &function) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static HMODULE qtCoreDllHandle = GetModuleHandle(L"QtCore4"); if (qtCoreDllHandle == NULL) { qtCoreDllHandle = GetModuleHandle(L"QtCored4"); } #else static HMODULE qtCoreDllHandle = GetModuleHandle(L"Qt5Core"); if (qtCoreDllHandle == NULL) { qtCoreDllHandle = GetModuleHandle(L"Qt5Cored"); } #endif if (qtCoreDllHandle == NULL) { cerr << "no handle for QtCore found!" << endl; return 0; } FARPROC qtfuncaddr = GetProcAddress(qtCoreDllHandle, function.toLatin1()); return (void*)qtfuncaddr; } long WinFunctionOverwriter::pagesize() const { SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; } gammaray-2.3.0/hooking/winfunctionoverwriter.h000066400000000000000000000037211255003167400216230ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WINFUNCTIONOVERWRITER_H #define GAMMARAY_WINFUNCTIONOVERWRITER_H #include #include "abstractfunctionoverwriter.h" #include namespace GammaRay { class WinFunctionOverwriter : public AbstractFunctionOverwriter { protected: virtual bool unprotectMemory(void *mem, size_t size); virtual bool reprotectMemory(void *mem, size_t size); virtual bool getAddressRange(intptr_t &min, intptr_t &max); virtual bool isMemoryFree(void * const mem, size_t size); virtual void *reserveMemory(void *mem, size_t size); virtual bool commitMemory(void *mem, size_t size); virtual void *qtCoreFunctionLookup(const QString &function); virtual long pagesize() const; private: WinFunctionOverwriter(); DWORD oldProtect; friend class FunctionOverwriterFactory; }; } #endif // WINFUNCTIONOVERWRITER_H gammaray-2.3.0/inprocessui/000077500000000000000000000000001255003167400156605ustar00rootroot00000000000000gammaray-2.3.0/inprocessui/CMakeLists.txt000066400000000000000000000005421255003167400204210ustar00rootroot00000000000000add_library(gammaray_inprocessui MODULE main.cpp) target_link_libraries(gammaray_inprocessui gammaray_core gammaray_ui_internal) set_target_properties(gammaray_inprocessui PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${PROBE_PLUGIN_INSTALL_DIR}" ) install(TARGETS gammaray_inprocessui DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}) gammaray-2.3.0/inprocessui/main.cpp000066400000000000000000000027201255003167400173110ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include extern "C" { void Q_DECL_EXPORT gammaray_create_inprocess_mainwindow() { GammaRay::MainWindow *window = new GammaRay::MainWindow; window->setAttribute(Qt::WA_DeleteOnClose); GammaRay::Probe::instance()->setWindow(window); GammaRay::Probe::instance()->setParent(window); window->show(); } } gammaray-2.3.0/launcher/000077500000000000000000000000001255003167400151165ustar00rootroot00000000000000gammaray-2.3.0/launcher/CMakeLists.txt000066400000000000000000000030071255003167400176560ustar00rootroot00000000000000add_subdirectory(injector) if(NOT GAMMARAY_PROBE_ONLY_BUILD) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) # shared launcher code set(gammaray_launcher_shared_srcs injector/abstractinjector.cpp injector/processinjector.cpp injector/injectorfactory.cpp injector/styleinjector.cpp injector/windllinjector.cpp injector/interactiveprocess.cpp probefinder.cpp launchoptions.cpp clientlauncher.cpp launcherfinder.cpp launcher.cpp ) if(NOT WIN32) list(APPEND gammaray_launcher_shared_srcs injector/debuggerinjector.cpp injector/gdbinjector.cpp injector/lldbinjector.cpp injector/preloadcheck.cpp injector/preloadinjector.cpp ) endif() add_library(gammaray_launcher_shared STATIC ${gammaray_launcher_shared_srcs}) target_link_libraries(gammaray_launcher_shared ${QT_QTCORE_LIBRARIES} gammaray_common_internal) if(HAVE_QT_WIDGETS) target_link_libraries(gammaray_launcher_shared ${QT_QTGUI_LIBRARIES}) endif() if(UNIX AND NOT APPLE AND NOT QNXNTO) target_link_libraries(gammaray_launcher_shared dl) # for preload check endif() # command line launcher set(gammaray_runner_srcs main.cpp ) add_executable(gammaray ${gammaray_runner_srcs}) target_link_libraries(gammaray gammaray_launcher_shared) if(QNXNTO) target_link_libraries(gammaray cpp) endif() gammaray_embed_info_plist(gammaray ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in) install(TARGETS gammaray ${INSTALL_TARGETS_DEFAULT_ARGS}) # UI launcher if(HAVE_QT_CONCURRENT AND GAMMARAY_BUILD_UI) add_subdirectory(ui) endif() endif() gammaray-2.3.0/launcher/Info.plist.in000066400000000000000000000007141255003167400174750ustar00rootroot00000000000000 CFBundleIdentifier com.kdab.GammaRay.injector CFBundleInfoDictionaryVersion 6.0 CFBundleName gammaray CFBundleVersion @GAMMARAY_VERSION_STRING@ CFBundleShortVersion @GAMMARAY_VERSION@ LSUIElement 1 gammaray-2.3.0/launcher/clientlauncher.cpp000066400000000000000000000040651255003167400206270ustar00rootroot00000000000000/* clientlauncher.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "clientlauncher.h" #include "launcherfinder.h" #include using namespace GammaRay; ClientLauncher::ClientLauncher() { m_process.setProcessChannelMode(QProcess::ForwardedChannels); } ClientLauncher::~ClientLauncher() { } QString ClientLauncher::clientPath() { return LauncherFinder::findLauncher(LauncherFinder::Client); } QStringList ClientLauncher::makeArgs(const QUrl &url) { QStringList args; args.push_back(url.toString()); return args; } bool ClientLauncher::launch(const QUrl &url) { m_process.start(clientPath(), makeArgs(url)); return m_process.waitForStarted(); } void ClientLauncher::launchDetached(const QUrl &url) { QProcess::startDetached(clientPath(), makeArgs(url)); } void ClientLauncher::terminate() { if (m_process.state() == QProcess::Running) m_process.terminate(); } void ClientLauncher::waitForFinished() { if (m_process.state() == QProcess::Running) m_process.waitForFinished(-1); } gammaray-2.3.0/launcher/clientlauncher.h000066400000000000000000000032461255003167400202740ustar00rootroot00000000000000/* clientlauncher.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENTLAUNCHER_H #define GAMMARAY_CLIENTLAUNCHER_H #include class QUrl; namespace GammaRay { /** Launching/monitoring of the GammaRay client for out-of-process use. */ class ClientLauncher { public: ClientLauncher(); ~ClientLauncher(); bool launch(const QUrl &url); void terminate(); void waitForFinished(); static void launchDetached(const QUrl &url); private: static QString clientPath(); static QStringList makeArgs(const QUrl &url); private: QProcess m_process; }; } #endif // GAMMARAY_CLIENTLAUNCHER_H gammaray-2.3.0/launcher/injector/000077500000000000000000000000001255003167400167335ustar00rootroot00000000000000gammaray-2.3.0/launcher/injector/CMakeLists.txt000066400000000000000000000010571255003167400214760ustar00rootroot00000000000000if(Qt5Widgets_FOUND OR QT_QTGUI_FOUND) set(gammaray_injector_style_srcs injectorstyleplugin.cpp) add_library(gammaray_injector_style MODULE ${gammaray_injector_style_srcs}) target_link_libraries(gammaray_injector_style ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ) set_target_properties(gammaray_injector_style PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${PROBE_PLUGIN_INSTALL_DIR}/styles ) install( TARGETS gammaray_injector_style DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}/styles ) endif() gammaray-2.3.0/launcher/injector/abstractinjector.cpp000066400000000000000000000036211255003167400230020ustar00rootroot00000000000000/* abstractinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "abstractinjector.h" #include #include using namespace GammaRay; AbstractInjector::~AbstractInjector() { } bool AbstractInjector::launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) { Q_UNUSED(programAndArgs); Q_UNUSED(probeDll); Q_UNUSED(probeFunc); qWarning() << "Injection on launch not supported by this injector."; return false; } bool AbstractInjector::attach(int pid, const QString &probeDll, const QString &probeFunc) { Q_UNUSED(pid); Q_UNUSED(probeDll); Q_UNUSED(probeFunc); qWarning() << "Attaching to a running process is not supported by this injector."; return false; } bool AbstractInjector::selfTest() { return true; } gammaray-2.3.0/launcher/injector/abstractinjector.h000066400000000000000000000057031255003167400224520ustar00rootroot00000000000000/* abstractinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ABSTRACTINJECTOR_H #define GAMMARAY_ABSTRACTINJECTOR_H #include #include class QString; class QStringList; namespace GammaRay { class AbstractInjector { public: typedef QSharedPointer Ptr; virtual ~AbstractInjector(); /** * Injector Name */ virtual QString name() const = 0; /** * Launch the application @p program and inject @p probeDll and call @p probeFunc on it. * * @return True if the launch succeeded, false otherwise. */ virtual bool launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc); /** * Attach to the running application with process id @p pid * and inject @p probeDll and call @p probeFunc on it. * * @return True if attaching succeeded, false otherwise. */ virtual bool attach(int pid, const QString &probeDll, const QString &probeFunc); /** * Return the exit code from the application launch or attach. */ virtual int exitCode() = 0; /** * Return the QProcess::ExitStatus from the application launch or attach. */ virtual QProcess::ExitStatus exitStatus() = 0; /** * Return the QProcess::ProcessError from the application launch or attach. */ virtual QProcess::ProcessError processError() = 0; /** * @return Descriptional error message when launch/attach/self-test failed. */ virtual QString errorString() = 0; /** * Perform tests to ensure the injector is operational, such as testing if * all necessary runtime dependencies are available. * @return @c true on success, @c false otherwise. * @note Make sure to set errorString() when returning @c false. */ virtual bool selfTest(); }; } #endif // ABSTRACTINJECTOR_H gammaray-2.3.0/launcher/injector/debuggerinjector.cpp000066400000000000000000000102271255003167400227630ustar00rootroot00000000000000/* debuggerinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "debuggerinjector.h" #include #include #include #include using namespace GammaRay; DebuggerInjector::DebuggerInjector() : mExitCode(-1), mProcessError(QProcess::UnknownError), mExitStatus(QProcess::NormalExit), mManualError(false) { } DebuggerInjector::~DebuggerInjector() { } QString DebuggerInjector::errorString() { return mErrorString; } int DebuggerInjector::exitCode() { return mExitCode; } QProcess::ExitStatus DebuggerInjector::exitStatus() { return mExitStatus; } QProcess::ProcessError DebuggerInjector::processError() { return mProcessError; } void DebuggerInjector::readyReadStandardOutput() { } void DebuggerInjector::readyReadStandardError() { const QString error = m_process->readAllStandardError(); std::cerr << qPrintable(error) << std::endl; } bool DebuggerInjector::startDebugger(const QStringList& args) { m_process.reset(new QProcess); connect(m_process.data(), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError())); connect(m_process.data(), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput())); m_process->setProcessChannelMode(QProcess::SeparateChannels); m_process->start(debuggerExecutable(), args); bool status = m_process->waitForStarted(-1); mExitCode = m_process->exitCode(); mExitStatus = m_process->exitStatus(); if (!mManualError) { mProcessError = m_process->error(); mErrorString = m_process->errorString(); } return status; } bool DebuggerInjector::selfTest() { if (startDebugger(QStringList() << QLatin1String("--version"))) { return m_process->waitForFinished(-1); } return false; } void DebuggerInjector::waitForMain() { addFunctionBreakpoint("main"); execCmd("run"); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) loadSymbols("QtCore"); #else loadSymbols("Qt5Core"); #endif addMethodBreakpoint("QCoreApplication::exec"); execCmd("continue"); } int DebuggerInjector::injectAndDetach(const QString &probeDll, const QString &probeFunc) { Q_ASSERT(m_process); loadSymbols("dl"); execCmd(QString::fromLatin1("call (void) dlopen(\"%1\", %2)"). arg(probeDll).arg(RTLD_NOW).toUtf8()); loadSymbols(probeDll.toUtf8()); execCmd(QString::fromLatin1("call (void) %1()").arg(probeFunc).toUtf8()); if (qgetenv("GAMMARAY_UNITTEST") != "1") { execCmd("detach"); execCmd("quit"); } else { // delete all breakpoints before we continue, so we don't hit another one and abort there execCmd("delete"); execCmd("continue"); // if we hit a crash or anything, print backtrace and quit execCmd("backtrace", false); execCmd("quit", false); } m_process->waitForFinished(-1); mExitCode = m_process->exitCode(); mExitStatus = m_process->exitStatus(); if (!mManualError) { mProcessError = m_process->error(); mErrorString = m_process->errorString(); } return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit; } void DebuggerInjector::loadSymbols(const QByteArray& library) { Q_UNUSED(library); } gammaray-2.3.0/launcher/injector/debuggerinjector.h000066400000000000000000000060121255003167400224250ustar00rootroot00000000000000/* debuggerinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_DEBUGGERINJECTOR_H #define GAMMARAY_DEBUGGERINJECTOR_H #include "injector/abstractinjector.h" #include #include namespace GammaRay { /** Base class for debugger-based injectors. */ class DebuggerInjector : public QObject, public AbstractInjector { Q_OBJECT public: DebuggerInjector(); ~DebuggerInjector(); bool selfTest() Q_DECL_OVERRIDE; QString errorString() Q_DECL_OVERRIDE; int exitCode() Q_DECL_OVERRIDE; QProcess::ExitStatus exitStatus() Q_DECL_OVERRIDE; QProcess::ProcessError processError() Q_DECL_OVERRIDE; protected: virtual QString debuggerExecutable() const = 0; /** Execute a raw command on the debugger. */ virtual void execCmd(const QByteArray &cmd, bool waitForWritten = true) = 0; /** Break in the function @p function, specify name without parenthesis. */ virtual void addFunctionBreakpoint(const QByteArray &function) = 0; /** Break in the method @p method, specify name without parenthesis. */ virtual void addMethodBreakpoint(const QByteArray &method) = 0; /** Load symbols for the given shared library. */ virtual void loadSymbols(const QByteArray &library); /** Start the debugger with the given command line arguments. */ bool startDebugger(const QStringList &args); /** Add a breakpoint in common entry points and wait until they are hit. */ void waitForMain(); /** Given an interrupted process, this injects the probe and continues the process. */ int injectAndDetach(const QString &probeDll, const QString &probeFunc); protected slots: virtual void readyReadStandardError(); virtual void readyReadStandardOutput(); protected: QScopedPointer m_process; int mExitCode; QProcess::ProcessError mProcessError; QProcess::ExitStatus mExitStatus; QString mErrorString; bool mManualError; }; } #endif // GAMMARAY_DEBUGGERINJECTOR_H gammaray-2.3.0/launcher/injector/gdbinjector.cpp000066400000000000000000000077131255003167400217410ustar00rootroot00000000000000/* gdbinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "gdbinjector.h" #include #include #include #include using namespace GammaRay; static QTextStream cout(stdout); static QTextStream cerr(stderr); GdbInjector::GdbInjector() { } QString GdbInjector::debuggerExecutable() const { return QLatin1String("gdb"); } bool GdbInjector::launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) { QStringList gdbArgs; gdbArgs.push_back(QLatin1String("--args")); gdbArgs.append(programAndArgs); if (!startDebugger(gdbArgs)) { return -1; } execCmd("set confirm off"); waitForMain(); return injectAndDetach(probeDll, probeFunc); } bool GdbInjector::attach(int pid, const QString &probeDll, const QString &probeFunc) { Q_ASSERT(pid > 0); if (!startDebugger(QStringList() << QLatin1String("-pid") << QString::number(pid))) { return false; } return injectAndDetach(probeDll, probeFunc); } void GdbInjector::execCmd(const QByteArray &cmd, bool waitForWritten) { m_process->write(cmd + '\n'); if (waitForWritten) { m_process->waitForBytesWritten(-1); } } void GdbInjector::readyReadStandardError() { const QString error = m_process->readAllStandardError(); cerr << error << flush; if (error.startsWith(QLatin1String("Function \"main\" not defined."))) { mManualError = true; mErrorString = tr("The debuggee application is missing debug symbols which are required\n" "for GammaRay's GDB injector. Please recompile the debuggee.\n\n" "GDB error was: %1").arg(error); } else if (error.startsWith(QLatin1String("Can't find member of namespace, class, struct, or union named \"QCoreApplication::exec\""))) { mManualError = true; mErrorString = tr("Your QtCore library is missing debug symbols which are required\n" "for GammaRay's GDB injector. Please install the required debug symbols.\n\n" "GDB error was: %1").arg(error); } if (mManualError) { m_process->kill(); disconnect(m_process.data(), SIGNAL(readyReadStandardError()), this, 0); disconnect(m_process.data(), SIGNAL(readyReadStandardOutput()), this, 0); mProcessError = QProcess::FailedToStart; return; } } void GdbInjector::readyReadStandardOutput() { if (qgetenv("GAMMARAY_UNITTEST") == "1") { cout << m_process->readAllStandardOutput() << flush; } } void GdbInjector::addFunctionBreakpoint(const QByteArray& function) { execCmd("break " + function); } void GdbInjector::addMethodBreakpoint(const QByteArray& method) { #ifdef Q_OS_MAC execCmd("break " + method + "()"); #else execCmd("break " + method); #endif } void GdbInjector::loadSymbols(const QByteArray& library) { #ifndef Q_OS_MAC execCmd("sha " + library); #else Q_UNUSED(library); #endif } gammaray-2.3.0/launcher/injector/gdbinjector.h000066400000000000000000000041671255003167400214060ustar00rootroot00000000000000/* gdbinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_GDBINJECTOR_H #define GAMMARAY_GDBINJECTOR_H #include "injector/debuggerinjector.h" namespace GammaRay { class GdbInjector : public DebuggerInjector { Q_OBJECT public: GdbInjector(); QString name() const { return QString("gdb"); } bool launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) Q_DECL_OVERRIDE; bool attach(int pid, const QString &probeDll, const QString &probeFunc) Q_DECL_OVERRIDE; protected: QString debuggerExecutable() const Q_DECL_OVERRIDE; void execCmd(const QByteArray &cmd, bool waitForWritten = true) Q_DECL_OVERRIDE; void addFunctionBreakpoint(const QByteArray& function) Q_DECL_OVERRIDE; void addMethodBreakpoint(const QByteArray& method) Q_DECL_OVERRIDE; void loadSymbols(const QByteArray& library) Q_DECL_OVERRIDE; private slots: void readyReadStandardError() Q_DECL_OVERRIDE; void readyReadStandardOutput() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_GDBINJECTOR_H gammaray-2.3.0/launcher/injector/injectorfactory.cpp000066400000000000000000000066101255003167400226470ustar00rootroot00000000000000/* injectorfactory.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "injectorfactory.h" #include "gdbinjector.h" #include "lldbinjector.h" #include "preloadinjector.h" #include "styleinjector.h" #include "windllinjector.h" #include #include namespace GammaRay { namespace InjectorFactory { AbstractInjector::Ptr createInjector(const QString &name) { #ifndef Q_OS_WIN if (name == QLatin1String("gdb")) { return AbstractInjector::Ptr(new GdbInjector); } if (name == QLatin1String("lldb")) { return AbstractInjector::Ptr(new LldbInjector); } #endif if (name == QLatin1String("style")) { return AbstractInjector::Ptr(new StyleInjector); } #ifndef Q_OS_WIN if (name == QLatin1String("preload")) { return AbstractInjector::Ptr(new PreloadInjector); } #else if (name == QLatin1String("windll")) { return AbstractInjector::Ptr(new WinDllInjector); } #endif return AbstractInjector::Ptr(0); } #if !defined(Q_OS_WIN) static AbstractInjector::Ptr findFirstWorkingInjector(const QStringList &types) { foreach (const QString &type, types) { AbstractInjector::Ptr injector = createInjector(type); if (injector->selfTest()) return injector; } return AbstractInjector::Ptr(0); } #endif AbstractInjector::Ptr defaultInjectorForLaunch(const ProbeABI &abi) { #if defined(Q_OS_MAC) if (abi.majorQtVersion() >= 5 && abi.minorQtVersion() >= 4) return createInjector(QLatin1String("preload")); return findFirstWorkingInjector(QStringList() << QLatin1String("lldb") << QLatin1String("gdb")); #elif defined(Q_OS_UNIX) Q_UNUSED(abi); return createInjector(QLatin1String("preload")); #else Q_UNUSED(abi); return createInjector(QLatin1String("windll")); #endif } AbstractInjector::Ptr defaultInjectorForAttach() { #if defined(Q_OS_MAC) return findFirstWorkingInjector(QStringList() << QLatin1String("lldb") << QLatin1String("gdb")); #elif !defined(Q_OS_WIN) return findFirstWorkingInjector(QStringList() << QLatin1String("gdb") << QLatin1String("lldb")); #else return createInjector(QLatin1String("windll")); #endif } QStringList availableInjectors() { QStringList types; #ifndef Q_OS_WIN types << QLatin1String("preload") << QLatin1String("gdb") << QLatin1String("lldb"); #else types << QLatin1String("windll"); #endif types << QLatin1String("style"); return types; } } } gammaray-2.3.0/launcher/injector/injectorfactory.h000066400000000000000000000031571255003167400223170ustar00rootroot00000000000000/* injectorfactory.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_INJECTORFACTORY_H #define GAMMARAY_INJECTORFACTORY_H #include "abstractinjector.h" namespace GammaRay { class ProbeABI; namespace InjectorFactory { AbstractInjector::Ptr createInjector(const QString &name); AbstractInjector::Ptr defaultInjectorForLaunch(const ProbeABI &abi); AbstractInjector::Ptr defaultInjectorForAttach(); /** * Returns the list of available injector types. */ QStringList availableInjectors(); } } #endif // GAMMARAY_INJECTORFACTORY_H gammaray-2.3.0/launcher/injector/injectorstyle.json000066400000000000000000000000441255003167400225220ustar00rootroot00000000000000{ "Keys": [ "gammaray-injector" ] } gammaray-2.3.0/launcher/injector/injectorstyleplugin.cpp000066400000000000000000000061561255003167400235640ustar00rootroot00000000000000/* injectorstyleplugin.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "injectorstyleplugin.h" #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #else #include //krazy:exclude=camelcase #include #endif #include #include #include #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) typedef void *QFunctionPointer; #endif using namespace GammaRay; QStyle *InjectorStylePlugin::create(const QString &) { inject(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static QGuiPlatformPlugin defaultGuiPlatform; return QStyleFactory::create(defaultGuiPlatform.styleName()); #else const QStringList styleNameList = QGuiApplicationPrivate::platform_theme->themeHint( QPlatformTheme::StyleNames).toStringList(); foreach (const QString &styleName, styleNameList) { if (QStyle *style = QStyleFactory::create(styleName)) { return style; } } return 0; #endif } QStringList InjectorStylePlugin::keys() const { return QStringList() << QLatin1String("gammaray-injector"); } void InjectorStylePlugin::inject() { const QByteArray probeDllPath = qgetenv("GAMMARAY_STYLEINJECTOR_PROBEDLL"); if (probeDllPath.isEmpty()) { qWarning("No probe DLL specified."); return; } QLibrary probeDll(QString::fromLocal8Bit(probeDllPath)); probeDll.setLoadHints(QLibrary::ResolveAllSymbolsHint); if (!probeDll.load()) { qWarning() << "Loading probe DLL failed:" << probeDll.errorString(); return; } const QByteArray probeFunc = qgetenv("GAMMARAY_STYLEINJECTOR_PROBEFUNC"); if (probeFunc.isEmpty()) { qWarning("No probe function specified."); return; } QFunctionPointer probeFuncHandle = probeDll.resolve(probeFunc); if (probeFuncHandle) { reinterpret_cast(probeFuncHandle)(); } else { qWarning() << "Resolving probe function failed:" << probeDll.errorString(); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(gammaray_injector_style, GammaRay::InjectorStylePlugin) #endif gammaray-2.3.0/launcher/injector/injectorstyleplugin.h000066400000000000000000000031611255003167400232220ustar00rootroot00000000000000/* injectorstyleplugin.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_INJECTORSTYLEPLUGIN_H #define GAMMARAY_INJECTORSTYLEPLUGIN_H #include namespace GammaRay { class InjectorStylePlugin : public QStylePlugin { Q_OBJECT #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "injectorstyle.json") #endif public: QStyle *create(const QString &) Q_DECL_OVERRIDE; QStringList keys() const; private: void inject(); }; } #endif // GAMMARAY_INJECTORSTYLEPLUGIN_H gammaray-2.3.0/launcher/injector/interactiveprocess.cpp000066400000000000000000000026551255003167400233630ustar00rootroot00000000000000/* interactiveprocess.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2006 Bradley T. Hughes //krazy:exclude=copyright http://labs.qt.nokia.com/2006/03/16/starting-interactive-processes-with-qprocess/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "interactiveprocess.h" #include #ifdef Q_OS_WIN #include #define dup _dup #define dup2 _dup2 #ifndef __MINGW32__ #define fileno _fileno #endif #elif defined(Q_OS_QNX) #include using std::fileno; #else #include #endif int InteractiveProcess::stdinClone = -1; InteractiveProcess::InteractiveProcess(QObject *parent) : QProcess(parent) { if (stdinClone == -1) { stdinClone = ::dup(fileno(stdin)); } } void InteractiveProcess::setupChildProcess() { ::dup2(stdinClone, fileno(stdin)); } gammaray-2.3.0/launcher/injector/interactiveprocess.h000066400000000000000000000024021255003167400230160ustar00rootroot00000000000000/* interactiveprocess.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2006 Bradley T. Hughes //krazy:exclude=copyright http://labs.qt.nokia.com/2006/03/16/starting-interactive-processes-with-qprocess/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_INTERACTIVEPROCESS_H #define GAMMARAY_INTERACTIVEPROCESS_H #include #include //for EXIT_STATUS class InteractiveProcess : public QProcess { Q_OBJECT public: InteractiveProcess(QObject *parent = 0); protected: void setupChildProcess() Q_DECL_OVERRIDE; private: static int stdinClone; }; #endif // INTERACTIVEPROCESS_H gammaray-2.3.0/launcher/injector/lldbinjector.cpp000066400000000000000000000051751255003167400221220ustar00rootroot00000000000000/* lldbinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "lldbinjector.h" #include using namespace GammaRay; LldbInjector::LldbInjector() { } LldbInjector::~LldbInjector() { } QString LldbInjector::name() const { return QLatin1String("lldb"); } QString LldbInjector::debuggerExecutable() const { return QLatin1String("lldb"); } void LldbInjector::execCmd(const QByteArray& cmd, bool waitForWritten) { // wait for the prompt, otherwise LLDB loses the command if (!m_process->bytesAvailable()) m_process->waitForReadyRead(-1); if (qgetenv("GAMMARAY_UNITTEST") == "1") { std::cout << m_process->readAllStandardOutput().constData(); } m_process->write(cmd + '\n'); if (waitForWritten) { m_process->waitForBytesWritten(-1); } } void LldbInjector::addFunctionBreakpoint(const QByteArray& function) { execCmd("breakpoint set -b " + function); } void LldbInjector::addMethodBreakpoint(const QByteArray& method) { execCmd("breakpoint set -M " + method); } bool LldbInjector::launch(const QStringList& programAndArgs, const QString& probeDll, const QString& probeFunc) { QStringList args; args.push_back(QLatin1String("--")); args.append(programAndArgs); if (!startDebugger(args)) { return -1; } waitForMain(); return injectAndDetach(probeDll, probeFunc); } bool LldbInjector::attach(int pid, const QString& probeDll, const QString& probeFunc) { Q_ASSERT(pid > 0); if (!startDebugger(QStringList() << QLatin1String("-p") << QString::number(pid))) { return false; } return injectAndDetach(probeDll, probeFunc); } gammaray-2.3.0/launcher/injector/lldbinjector.h000066400000000000000000000036511255003167400215640ustar00rootroot00000000000000/* lldbinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LLDBINJECTOR_H #define GAMMARAY_LLDBINJECTOR_H #include "injector/debuggerinjector.h" namespace GammaRay { class LldbInjector : public DebuggerInjector { public: LldbInjector(); ~LldbInjector(); QString name() const Q_DECL_OVERRIDE; bool launch(const QStringList& programAndArgs, const QString& probeDll, const QString& probeFunc) Q_DECL_OVERRIDE; bool attach(int pid, const QString& probeDll, const QString& probeFunc) Q_DECL_OVERRIDE; protected: QString debuggerExecutable() const Q_DECL_OVERRIDE; void execCmd(const QByteArray& cmd, bool waitForWritten = true) Q_DECL_OVERRIDE; void addFunctionBreakpoint(const QByteArray& function) Q_DECL_OVERRIDE; void addMethodBreakpoint(const QByteArray& method) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_LLDBINJECTOR_H gammaray-2.3.0/launcher/injector/preloadcheck.cpp000066400000000000000000000140601255003167400220640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "preloadcheck.h" #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) #include #include #include #include #include #include #include static QString findSharedObjectFile(const QString &symbol) { void *sym = dlsym(RTLD_NEXT, qPrintable(symbol)); if (!sym) { return QString(); } Dl_info info; dladdr(sym, &info); const QString fileName = info.dli_fname; return fileName; } PreloadCheck::PreloadCheck() { } bool PreloadCheck::test(const QString &symbol) { const QString fileName = findSharedObjectFile(symbol); if (fileName.isEmpty()) { setErrorString(QObject::tr("Cannot find file containing symbol: %1").arg(symbol)); return false; } if (!QFile(fileName).exists()) { setErrorString(QObject::tr("Invalid shared object: %1").arg(fileName)); return false; } QStringList args; args << "--relocs" << "--wide" << fileName; QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start("readelf", args, QIODevice::ReadOnly); if (!proc.waitForFinished()) { // TODO: Find out if we want to error out if 'readelf' is missing // The question is: Do all (major) distributions ship binutils by default? // Major distros do, but not custom embedded ones... setErrorString(QObject::tr("Failed to run 'readelf' (binutils) binary: %1"). arg(QString(proc.errorString()))); return true; } if (proc.exitCode() != 0) { setErrorString(QObject::tr("Cannot read shared object: %1").arg(QString(proc.readAll()))); return false; } // Example line on x86_64: // 00000049f3d8 054300000007 R_X86_64_JUMP_SLO 000000000016c930 qt_startup_hook + 0 // Example line on i386: // 002e02f0 00034407 R_386_JUMP_SLOT 00181490 qt_startup_hook QRegExp rx("^(?:[^ ]+\\s+){4}([^ ]+)(?:.*)$"); while (proc.canReadLine()) { const QString line = proc.readLine().trimmed(); if (!rx.exactMatch(line)) { continue; } const QString currentSymbol = rx.cap(1); if (currentSymbol == symbol) { qDebug() << "Found relocatable symbol in" << fileName << ":" << symbol; setErrorString(QString()); return true; } } #ifdef __mips__ // Mips, besides the plt, has another method of // calling functions from .so files, and this method doesn't need JUMP_SLOT // relocations (in fact, it doesn't need any relocations). This method uses .got // entries and lazy binding stubs. if (testMips(symbol, fileName)) { qDebug() << "Call of function " << symbol << " will go through lazy binding stub"; setErrorString(QString()); return true; } #endif setErrorString(QObject::tr("Symbol is not marked as relocatable: %1").arg(symbol)); return false; } #ifdef __mips__ // The way to determine whether the call to function will go // through .got and lazy binding stub is: // - find the value of dynamic symbol index of the function with the command // "readelf --dyn-syms" // - find the value of dynamic tag MIPS_GOTSYM with the command "readelf -d" // - if (dyn_sym_index >= MIPS_GOTSYM) then the function has entry in the global // part of the .got, and the call will go through lazy binding stub and be // resolved by dynamic linker. bool PreloadCheck::testMips(const QString &symbol, const QString &fileName) { QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start("readelf", QStringList() << "--dyn-syms" << "-d" << fileName, QIODevice::ReadOnly); if (!proc.waitForFinished()) { setErrorString(QObject::tr("Failed to run 'readelf' (binutils) binary: %1"). arg(QString(proc.errorString()))); return false; } if (proc.exitCode() != 0) { setErrorString(QObject::tr("Cannot read shared object: %1").arg(QString(proc.readAll()))); return false; } //Example line of dynamic symbol table on mips: //3851: 001e66f4 8 FUNC GLOBAL DEFAULT 11 qt_startup_hook QRegExp rxSym("^(\\d+):\\s+(?:[^ ]+\\s+){6}([^ ]+)(?:.*)$"); //Example line of dynamic tag on mips: //0x70000013 (MIPS_GOTSYM) 0xec3 QRegExp rxGot("^0x[0-9a-fA-F]+\\s+\\((.+)\\)\\s+(0x[0-9a-fA-F]+)(?:.*)$"); int dyn_sym_index = 0; int mips_gotsym = 0; bool foundDynSymbol = false; bool foundGotTag = false; while (proc.canReadLine()) { const QString line = proc.readLine().trimmed(); QString currentMatch; const QString tag = "MIPS_GOTSYM"; if (rxGot.exactMatch(line)) { currentMatch = rxGot.cap(1); if (currentMatch == tag) { bool conversionOk = false; int value = rxGot.cap(2).toInt(&conversionOk, 16); if (conversionOk){ mips_gotsym = value; foundGotTag = true; } } } else if (rxSym.exactMatch(line)) { currentMatch = rxSym.cap(2); if (currentMatch == symbol) { dyn_sym_index = rxSym.cap(1).toInt(); foundDynSymbol = true; } } if (foundGotTag && foundDynSymbol) break; } if (foundGotTag && foundDynSymbol && (dyn_sym_index >= mips_gotsym)) { return true; } return false; } #endif QString PreloadCheck::errorString() const { return m_errorString; } void PreloadCheck::setErrorString(const QString &err) { m_errorString = err; } #endif gammaray-2.3.0/launcher/injector/preloadcheck.h000066400000000000000000000043151255003167400215330ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PRELOADCHECK #define GAMMARAY_PRELOADCHECK #if !defined Q_OS_WIN && !defined Q_OS_MAC #include /** * This class checks if it's possible to overwrite symbols * by setting the LD_PRELOAD environment variable */ class PreloadCheck { public: PreloadCheck(); /** * Test whether it is possible to overwrite @p symbol * via LD_PRELOAD * * On Linux the 'readelf' binary is called to find out whether * @p symbol is marked as relocatable * * @return True in case it's possible to overwrite @p symbol, otherwise false * @sa errorString() */ bool test(const QString &symbol); QString errorString() const; protected: void setErrorString(const QString &err); private: #ifdef __mips__ /** * Additional method for testing whether the call to the function will go * through .got and lazy binding stub (MIPS specific) * * @see https://github.com/KDAB/GammaRay/issues/63 */ bool testMips(const QString &symbol, const QString &fileName); #endif QString m_errorString; }; #endif #endif // GAMMARAY_PRELOADCHECK gammaray-2.3.0/launcher/injector/preloadinjector.cpp000066400000000000000000000044571255003167400226350ustar00rootroot00000000000000/* preloadinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "preloadinjector.h" #include "interactiveprocess.h" #include "preloadcheck.h" #ifndef Q_OS_WIN #include #include #include using namespace GammaRay; PreloadInjector::PreloadInjector() : ProcessInjector() { } bool PreloadInjector::launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) { Q_UNUSED(probeFunc); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); #ifdef Q_OS_MAC env.insert("DYLD_FORCE_FLAT_NAMESPACE", QLatin1String("1")); env.insert("DYLD_INSERT_LIBRARIES", probeDll); env.insert("GAMMARAY_UNSET_DYLD", "1"); #else env.insert("LD_PRELOAD", probeDll); env.insert("GAMMARAY_UNSET_PRELOAD", "1"); PreloadCheck check; const bool success = check.test("qt_startup_hook"); #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) // before 5.4 this is fatal, after that we have the built-in hooks and DLL initialization as an even better way if (!success) { mExitCode = 1; mErrorString = check.errorString(); return false; } #else Q_UNUSED(success); #endif #endif return launchProcess(programAndArgs, env); } #endif gammaray-2.3.0/launcher/injector/preloadinjector.h000066400000000000000000000031461255003167400222740ustar00rootroot00000000000000/* preloadinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PRELOADINJECTOR_H #define GAMMARAY_PRELOADINJECTOR_H #include "processinjector.h" #include #ifndef Q_OS_WIN namespace GammaRay { class PreloadInjector : public ProcessInjector { public: PreloadInjector(); QString name() const { return QString("preload"); } bool launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) Q_DECL_OVERRIDE; }; } #endif #endif // GAMMARAY_PRELOADINJECTOR_H gammaray-2.3.0/launcher/injector/processinjector.cpp000066400000000000000000000057431255003167400226640ustar00rootroot00000000000000/* processinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "processinjector.h" #include "interactiveprocess.h" #include using namespace GammaRay; ProcessInjector::ProcessInjector() : mExitCode(-1), mProcessError(QProcess::UnknownError), mExitStatus(QProcess::NormalExit) { } ProcessInjector::~ProcessInjector() { } bool ProcessInjector::launchProcess(const QStringList& programAndArgs, const QProcessEnvironment& env) { InteractiveProcess proc; proc.setProcessEnvironment(env); proc.setProcessChannelMode(QProcess::ForwardedChannels); QStringList args = programAndArgs; if (!env.value("GAMMARAY_TARGET_WRAPPER").isEmpty()) { const QString fullWrapperCmd = env.value("GAMMARAY_TARGET_WRAPPER"); // ### TODO properly handle quoted arguments! QStringList newArgs = fullWrapperCmd.split(' '); newArgs += args; args = newArgs; qDebug() << "Launching with target wrapper:" << args; } else if (env.value("GAMMARAY_GDB").toInt()) { QStringList newArgs; newArgs << "gdb"; #ifndef Q_OS_MAC newArgs << "--eval-command" << "run"; #endif newArgs << "--args"; newArgs += args; args = newArgs; } const QString program = args.takeFirst(); proc.start(program, args); proc.waitForFinished(-1); mExitCode = proc.exitCode(); mProcessError = proc.error(); mExitStatus = proc.exitStatus(); mErrorString = proc.errorString(); if (mProcessError == QProcess::FailedToStart) { mErrorString.prepend(QString("Could not start '%1': ").arg(program)); } return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit && mProcessError == QProcess::UnknownError; } int ProcessInjector::exitCode() { return mExitCode; } QProcess::ExitStatus ProcessInjector::exitStatus() { return mExitStatus; } QProcess::ProcessError ProcessInjector::processError() { return mProcessError; } QString ProcessInjector::errorString() { return mErrorString; } gammaray-2.3.0/launcher/injector/processinjector.h000066400000000000000000000037421255003167400223260ustar00rootroot00000000000000/* processinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROCESSINJECTOR_H #define GAMMARAY_PROCESSINJECTOR_H #include "abstractinjector.h" namespace GammaRay { /** Convenience base class for injectors using QProcess * to launch the target process. * Provides support for using gdb or valgrind for debugging the target. */ class ProcessInjector : public AbstractInjector { public: ProcessInjector(); ~ProcessInjector(); int exitCode() Q_DECL_OVERRIDE; QProcess::ExitStatus exitStatus() Q_DECL_OVERRIDE; QProcess::ProcessError processError() Q_DECL_OVERRIDE; QString errorString() Q_DECL_OVERRIDE; protected: bool launchProcess(const QStringList &programAndArgs, const QProcessEnvironment &env); int mExitCode; QString mErrorString; private: QProcess::ProcessError mProcessError; QProcess::ExitStatus mExitStatus; }; } #endif // GAMMARAY_PROCESSINJECTOR_H gammaray-2.3.0/launcher/injector/styleinjector.cpp000066400000000000000000000053061255003167400223410ustar00rootroot00000000000000/* styleinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "styleinjector.h" #include "interactiveprocess.h" #include #include #include #include #include #include #ifdef HAVE_QT_WIDGETS #include #endif #include using namespace GammaRay; StyleInjector::StyleInjector() : ProcessInjector() { } bool StyleInjector::launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("GAMMARAY_STYLEINJECTOR_PROBEDLL", probeDll); env.insert("GAMMARAY_STYLEINJECTOR_PROBEFUNC", probeFunc); QString qtPluginPath = env.value("QT_PLUGIN_PATH"); if (!qtPluginPath.isEmpty()) { qtPluginPath.append(":"); } qtPluginPath.append(Paths::currentProbePath()); env.insert("QT_PLUGIN_PATH", qtPluginPath); QStringList args = programAndArgs; args << QLatin1String("-style") << QLatin1String("gammaray-injector"); return launchProcess(args, env); } bool StyleInjector::selfTest() { #ifdef HAVE_QT_WIDGETS QCoreApplication::addLibraryPath(Paths::currentProbePath()); if (!QStyleFactory::keys().contains(QLatin1String("gammaray-injector"))) { mErrorString = QObject::tr("Injector style plugin is not found in the Qt style " "plug-in search path or cannot be loaded"); return false; } return true; #else mErrorString = QObject::tr("GammaRay was compiled without QtWidget support, style injector is not available."); return false; #endif } gammaray-2.3.0/launcher/injector/styleinjector.h000066400000000000000000000031371255003167400220060ustar00rootroot00000000000000/* styleinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINJECTOR_H #define GAMMARAY_STYLEINJECTOR_H #include "processinjector.h" namespace GammaRay { class StyleInjector : public GammaRay::ProcessInjector { public: StyleInjector(); QString name() const { return QString("style"); } bool launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc) Q_DECL_OVERRIDE; bool selfTest() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_STYLEINJECTOR_H gammaray-2.3.0/launcher/injector/windllinjector.cpp000066400000000000000000000105251255003167400224710ustar00rootroot00000000000000/* windllinjector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Patrick Spendrin Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //krazy:excludeall=null,captruefalse #include "windllinjector.h" #include #ifdef Q_OS_WIN #include #include using namespace GammaRay; WinDllInjector::WinDllInjector() : mExitCode(-1), mProcessError(QProcess::UnknownError), mExitStatus(QProcess::NormalExit), m_destProcess(NULL), m_destThread(NULL) { } bool WinDllInjector::launch(const QStringList &programAndArgs, const QString &probeDll, const QString &/*probeFunc*/) { DWORD dwCreationFlags = CREATE_NO_WINDOW; dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; dwCreationFlags |= CREATE_SUSPENDED; STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), 0, 0, 0, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, 0, 0, 0, STARTF_USESTDHANDLES, 0, 0, 0, GetStdHandle(STD_INPUT_HANDLE), GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE) }; PROCESS_INFORMATION pid; memset(&pid, 0, sizeof(PROCESS_INFORMATION)); const QString applicationName = programAndArgs.join(" "); BOOL success = CreateProcess(0, (wchar_t *)applicationName.utf16(), 0, 0, TRUE, dwCreationFlags, 0, 0, &startupInfo, &pid); if (!success) { return false; } m_destProcess = pid.hProcess; m_destThread = pid.hThread; m_dllPath = probeDll; m_dllPath.replace('/', '\\'); inject(); ResumeThread(pid.hThread); WaitForSingleObject(pid.hProcess, INFINITE); DWORD exitCode; GetExitCodeProcess(pid.hProcess, &exitCode); mExitCode = exitCode; //TODO mProcessError = proc.error(); //TODO mExitStatus = proc.exitStatus(); //TODO mErrorString = proc.errorString(); return mExitCode == EXIT_SUCCESS; } bool WinDllInjector::attach(int pid, const QString &probeDll, const QString &/*probeFunc*/) { m_dllPath = probeDll; m_dllPath.replace('/', '\\'); m_destProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid); if (!m_destProcess) { return false; } return inject(); } int WinDllInjector::exitCode() { return mExitCode; } QProcess::ProcessError WinDllInjector::processError() { return mProcessError; } QProcess::ExitStatus WinDllInjector::exitStatus() { return mExitStatus; } bool WinDllInjector::inject() { int strsize = (m_dllPath.size() * 2) + 2; void *mem = VirtualAllocEx(m_destProcess, NULL, strsize, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(m_destProcess, mem, (void*)m_dllPath.utf16(), strsize, NULL); HMODULE kernel32handle = GetModuleHandleW(L"Kernel32"); FARPROC loadLib = GetProcAddress(kernel32handle, "LoadLibraryW"); m_destThread = CreateRemoteThread(m_destProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLib, mem, 0, NULL); WaitForSingleObject(m_destThread, INFINITE); DWORD result; GetExitCodeThread(m_destThread, &result); CloseHandle(m_destThread); VirtualFreeEx(m_destProcess, mem, strsize, MEM_RELEASE); return true; } QString WinDllInjector::errorString() { return mErrorString; } #endif gammaray-2.3.0/launcher/injector/windllinjector.h000066400000000000000000000042001255003167400221270ustar00rootroot00000000000000/* windllinjector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Patrick Spendrin Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WINDLLINJECTOR_H #define GAMMARAY_WINDLLINJECTOR_H #include "injector/abstractinjector.h" #include #ifdef Q_OS_WIN #include #include namespace GammaRay { class WinDllInjector : public AbstractInjector { public: WinDllInjector(); QString name() const { return QString("windll"); } virtual bool launch(const QStringList &programAndArgs, const QString &probeDll, const QString &probeFunc); virtual bool attach(int pid, const QString &probeDll, const QString &probeFunc); virtual int exitCode(); virtual QProcess::ExitStatus exitStatus(); virtual QProcess::ProcessError processError(); virtual QString errorString(); private: int mExitCode; QProcess::ProcessError mProcessError; QProcess::ExitStatus mExitStatus; QString mErrorString; bool inject(); bool inject2(); HANDLE m_destProcess; HANDLE m_destThread; QString m_dllPath; }; } #endif #endif // GAMMARAY_WINDLLINJECTOR_H gammaray-2.3.0/launcher/launcher.cpp000066400000000000000000000237031255003167400174300ustar00rootroot00000000000000/* launcher.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "launcher.h" #include "probefinder.h" #include "injector/abstractinjector.h" #include "injector/injectorfactory.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; class SemaphoreWaiter : public QThread { Q_OBJECT public: explicit SemaphoreWaiter(qint64 id, QObject *parent = 0) : QThread(parent), m_id(id) {} ~SemaphoreWaiter() {} void run() { #ifdef HAVE_SHM QSystemSemaphore sem("gammaray-semaphore-" + QString::number(m_id), 0, QSystemSemaphore::Create); sem.acquire(); emit semaphoreReleased(); #endif } signals: void semaphoreReleased(); private: qint64 m_id; }; class InjectorThread : public QThread { Q_OBJECT public: explicit InjectorThread(const LaunchOptions &options, const QString &probeDll, QObject *parent = 0) : QThread(parent), m_options(options), m_probeDll(probeDll) { Q_ASSERT(options.isValid()); } ~InjectorThread() {} AbstractInjector::Ptr createInjector() const { if (m_options.injectorType().isEmpty()) { if (m_options.isAttach()) { return InjectorFactory::defaultInjectorForAttach(); } else { return InjectorFactory::defaultInjectorForLaunch(m_options.probeABI()); } } return InjectorFactory::createInjector(m_options.injectorType()); } void run() { const AbstractInjector::Ptr injector = createInjector(); if (!injector) { if (m_options.injectorType().isEmpty()) { if (m_options.isAttach()) { emit error(-1, tr("Uh-oh, there is no default attach injector on this platform.")); } else { emit error(-1, tr("Uh-oh, there is no default launch injector on this platform.")); } } else { emit error(-1, tr("Injector %1 not found.").arg(m_options.injectorType())); } return; } bool success = false; if (m_options.isLaunch()) { success = injector->launch(m_options.launchArguments(), m_probeDll, QLatin1String("gammaray_probe_inject")); } if (m_options.isAttach()) { success = injector->attach(m_options.pid(), m_probeDll, QLatin1String("gammaray_probe_inject")); } if (!success) { QString errorMessage; if (m_options.isLaunch()) errorMessage = tr("Failed to launch target '%1'.").arg(m_options.launchArguments().join(" ")); if (m_options.isAttach()) errorMessage = tr("Failed to attach to target with PID %1.").arg(m_options.pid()); if (!injector->errorString().isEmpty()) errorMessage += tr("\nError: %1").arg(injector->errorString()); emit error(injector->exitCode() ? injector->exitCode() : 1, errorMessage); } } signals: void error(int exitCode, const QString &errorMessage); private: LaunchOptions m_options; QString m_probeDll; }; Launcher::Launcher(const LaunchOptions& options, QObject* parent): QObject(parent), m_options(options), #ifdef HAVE_SHM m_shm(0), #endif m_state(Initial) { Q_ASSERT(options.isValid()); m_safetyTimer.setSingleShot(true); m_safetyTimer.setInterval(60 * 1000); connect(&m_safetyTimer, SIGNAL(timeout()), SLOT(timeout())); // wait for the event loop to be available QMetaObject::invokeMethod(this, "delayedInit", Qt::QueuedConnection); } Launcher::~Launcher() { m_client.waitForFinished(); } qint64 Launcher::instanceIdentifier() const { if (m_options.isAttach()) return m_options.pid(); return QCoreApplication::applicationPid(); } void Launcher::delayedInit() { const QString probeDll = ProbeFinder::findProbe(QLatin1String(GAMMARAY_PROBE_NAME), m_options.probeABI()); m_options.setProbeSetting("ProbePath", QFileInfo(probeDll).absolutePath()); sendLauncherId(); sendProbeSettings(); sendProbeSettingsFallback(); if (m_options.uiMode() != LaunchOptions::InProcessUi) { SemaphoreWaiter *semWaiter = new SemaphoreWaiter(instanceIdentifier(), this); connect(semWaiter, SIGNAL(semaphoreReleased()), this, SLOT(semaphoreReleased()), Qt::QueuedConnection); semWaiter->start(); m_safetyTimer.start(); } InjectorThread *injector = new InjectorThread(m_options, probeDll, this); connect(injector, SIGNAL(finished()), this, SLOT(injectorFinished()), Qt::QueuedConnection); connect(injector, SIGNAL(error(int,QString)), this, SLOT(injectorError(int,QString)), Qt::QueuedConnection); injector->start(); } void Launcher::sendLauncherId() { // if we are launching a new process, make sure it knows how to talk to us if (m_options.isLaunch()) { qputenv("GAMMARAY_LAUNCHER_ID", QByteArray::number(instanceIdentifier())); } else { #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) qputenv("GAMMARAY_LAUNCHER_ID", ""); #else qunsetenv("GAMMARAY_LAUNCHER_ID"); #endif } } void Launcher::sendProbeSettings() { #ifdef HAVE_SHM QByteArray ba; // need a full copy of this first, since there's no QIODevice to directly work on void*... QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); { Message msg(Protocol::LauncherAddress, Protocol::ServerVersion); msg.payload() << Protocol::version(); msg.write(&buffer); } { Message msg(Protocol::LauncherAddress, Protocol::ProbeSettings); msg.payload() << m_options.probeSettings(); msg.write(&buffer); } buffer.close(); m_shm = new QSharedMemory(QLatin1String("gammaray-") + QString::number(instanceIdentifier()), this); if (!m_shm->create(qMax(ba.size(), 1024))) { // make sure we have enough space for the answer qWarning() << Q_FUNC_INFO << "Failed to obtain shared memory for probe settings:" << m_shm->errorString() << "- error code (QSharedMemory::SharedMemoryError):" << m_shm->error(); delete m_shm; m_shm = 0; return; } SharedMemoryLocker locker(m_shm); qMemCopy(m_shm->data(), ba.constData(), ba.size()); if (m_shm->size() > ba.size()) // Windows... qMemSet(static_cast(m_shm->data()) + ba.size(), 0xff, m_shm->size() - ba.size()); #endif } void Launcher::sendProbeSettingsFallback() { if (!m_options.isAttach()) return; const QHash probeSettings = m_options.probeSettings(); for (QHash::const_iterator it = probeSettings.constBegin(); it != probeSettings.constEnd(); ++it) qputenv("GAMMARAY_" + it.key(), it.value()); } void Launcher::semaphoreReleased() { m_safetyTimer.stop(); QUrl serverAddress; #ifdef HAVE_SHM { SharedMemoryLocker locker(m_shm); QByteArray ba = QByteArray::fromRawData(static_cast(m_shm->data()), m_shm->size()); QBuffer buffer(&ba); buffer.open(QIODevice::ReadOnly); while (Message::canReadMessage(&buffer)) { const Message msg = Message::readMessage(&buffer); switch (msg.type()) { case Protocol::ServerAddress: { msg.payload() >> serverAddress; break; } default: continue; } } } delete m_shm; m_shm = 0; if (serverAddress.isEmpty()) { qWarning() << "Unable to receive server address."; QCoreApplication::exit(1); return; } #else serverAddress.setScheme("tcp"); serverAddress.setHost("127.0.0.1"); serverAddress.setPort(Endpoint::defaultPort()); #endif std::cout << "GammaRay server listening on: " << qPrintable(serverAddress.toString()) << std::endl; if (m_options.uiMode() != LaunchOptions::OutOfProcessUi) // inject only, so we are done here return; // safer, since we will always be running locally, and the server might give us an external address if (serverAddress.scheme() == "tcp") serverAddress.setHost("127.0.0.1"); startClient(serverAddress); m_state |= ClientStarted; checkDone(); } void Launcher::startClient(const QUrl& serverAddress) { if (!m_client.launch(serverAddress)) { qCritical("Unable to launch gammaray-client!"); QCoreApplication::exit(1); } } void Launcher::injectorFinished() { if ((m_state & InjectorFailed) == 0) m_state |= InjectorFinished; checkDone(); } void Launcher::injectorError(int exitCode, const QString& errorMessage) { m_state |= InjectorFailed; std::cerr << qPrintable(errorMessage) << std::endl; std::cerr << "See for troubleshooting" << std::endl; QCoreApplication::exit(exitCode); } void Launcher::timeout() { std::cerr << "Target not responding - timeout." << std::endl; std::cerr << "See for troubleshooting" << std::endl; m_client.terminate(); QCoreApplication::exit(1); } void Launcher::checkDone() { if (m_state == Complete || (m_options.uiMode() != LaunchOptions::OutOfProcessUi && m_state == InjectorFinished)) { emit finished(); } } #include "launcher.moc" gammaray-2.3.0/launcher/launcher.h000066400000000000000000000046241255003167400170760ustar00rootroot00000000000000/* launcher.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LAUNCHER_H #define GAMMARAY_LAUNCHER_H #include #include #include "launchoptions.h" #include "clientlauncher.h" class QSharedMemory; namespace GammaRay { /** The actual launcher logic of gammaray.exe. */ class Launcher : public QObject { Q_OBJECT public: explicit Launcher(const LaunchOptions &options, QObject *parent = 0); ~Launcher(); /** This is used to identify the communication channels used by the launcher and the target process. */ qint64 instanceIdentifier() const; signals: void finished(); protected: virtual void startClient(const QUrl &serverAddress); private slots: void delayedInit(); void semaphoreReleased(); void injectorError(int exitCode, const QString &errorMessage); void injectorFinished(); void timeout(); private: void sendLauncherId(); void sendProbeSettings(); // in case shared memory isn't available void sendProbeSettingsFallback(); void checkDone(); private: LaunchOptions m_options; #ifndef QT_NO_SHAREDMEMORY QSharedMemory *m_shm; #endif ClientLauncher m_client; QTimer m_safetyTimer; enum State { Initial = 0, InjectorFinished = 1, InjectorFailed = 2, ClientStarted = 4, Complete = InjectorFinished | ClientStarted }; int m_state; }; } #endif // GAMMARAY_LAUNCHER_H gammaray-2.3.0/launcher/launcherfinder.cpp000066400000000000000000000045011255003167400206130ustar00rootroot00000000000000/* launcherfinder.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "launcherfinder.h" #include #include #include #include #include using namespace GammaRay; const char *executableNames[] = { "gammaray", // the Injector "gammaray-launcher", // the LauncherUI "gammaray-client" // the Client }; QString LauncherFinder::findLauncher(LauncherFinder::Type type) { QString fileName = executableNames[type]; #ifdef Q_OS_WIN fileName += ".exe"; #endif QStringList appPaths; //a list of all the paths we have searched QString appPath = Paths::binPath() + QDir::separator() + fileName; QFileInfo fi(appPath); if (fi.isExecutable()) { return fi.absoluteFilePath(); } appPaths.append(appPath); appPath = Paths::libexecPath() + QDir::separator() + fileName; if(!appPaths.contains(appPath)) { fi.setFile(appPath); if (fi.isExecutable()) { return fi.absoluteFilePath(); } appPaths.append(appPath); } qWarning() << fileName << "not found in the expected location(s):"; qWarning() << appPaths.join(", ") << endl << "continuing anyway, hoping for it to be in PATH."; qWarning() << "This is likely a setup problem." << endl; return fileName; } gammaray-2.3.0/launcher/launcherfinder.h000066400000000000000000000027311255003167400202630ustar00rootroot00000000000000/* launcherfinder.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LAUNCHERFINDER_H #define GAMMARAY_LAUNCHERFINDER_H #include namespace GammaRay { /** Utility function to find the various executables related to the launcher. */ namespace LauncherFinder { enum Type { Injector, LauncherUI, Client }; QString findLauncher(Type type); } } #endif // GAMMARAY_LAUNCHERFINDER_H gammaray-2.3.0/launcher/launchoptions.cpp000066400000000000000000000107151255003167400205140ustar00rootroot00000000000000/* launchoptions.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "launchoptions.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif using namespace GammaRay; LaunchOptions::LaunchOptions() : m_pid(-1), m_uiMode(OutOfProcessUi) { } LaunchOptions::~LaunchOptions() { } bool LaunchOptions::isLaunch() const { return !m_launchArguments.isEmpty(); } bool LaunchOptions::isAttach() const { return pid() > 0; } bool LaunchOptions::isValid() const { return isLaunch() != isAttach(); } QStringList LaunchOptions::launchArguments() const { return m_launchArguments; } void LaunchOptions::setLaunchArguments(const QStringList& args) { m_launchArguments = args; Q_ASSERT(m_pid <= 0 || m_launchArguments.isEmpty()); } QString LaunchOptions::absoluteExecutablePath() const { if (m_launchArguments.isEmpty()) return QString(); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QString path = m_launchArguments.first(); const QFileInfo fi(path); if (fi.isFile() && fi.isExecutable()) return path; path = QStandardPaths::findExecutable(m_launchArguments.first()); if (!path.isEmpty()) return path; #endif return m_launchArguments.first(); } int LaunchOptions::pid() const { return m_pid; } void LaunchOptions::setPid(int pid) { m_pid = pid; Q_ASSERT(m_pid <= 0 || m_launchArguments.isEmpty()); } LaunchOptions::UiMode LaunchOptions::uiMode() const { return m_uiMode; } void LaunchOptions::setUiMode(LaunchOptions::UiMode mode) { m_uiMode = mode; setProbeSetting("InProcessUi", mode == InProcessUi); } QString LaunchOptions::injectorType() const { return m_injectorType; } void LaunchOptions::setInjectorType(const QString& injectorType) { m_injectorType = injectorType; } ProbeABI LaunchOptions::probeABI() const { return m_probeABI; } void LaunchOptions::setProbeABI(const ProbeABI& abi) { m_probeABI = abi; } void LaunchOptions::setProbeSetting(const QString& key, const QVariant& value) { QByteArray v; switch (value.type()) { case QVariant::String: v = value.toString().toUtf8(); break; case QVariant::Bool: v = value.toBool() ? "true" : "false"; break; case QVariant::Int: v = QByteArray::number(value.toInt()); break; default: qFatal("unsupported probe settings type"); } m_probeSettings.insert(key.toUtf8(), v); } QHash< QByteArray, QByteArray > LaunchOptions::probeSettings() const { return m_probeSettings; } bool LaunchOptions::execute(const QString& launcherPath) const { Q_ASSERT(!launcherPath.isEmpty()); Q_ASSERT(isValid()); QStringList args; switch (uiMode()) { case InProcessUi: args.push_back("--inprocess"); break; case OutOfProcessUi: args.push_back("--no-inprocess"); break; case NoUi: args.push_back("--inject-only"); break; } if (m_probeABI.isValid()) { args.push_back("--probe"); args.push_back(m_probeABI.id()); } if (m_probeSettings.contains("ServerAddress")) { args.push_back("--listen"); args.push_back(m_probeSettings.value("ServerAddress")); } if (m_probeSettings.value("RemoteAccessEnabled") == "false") args.push_back("--no-listen"); if (isAttach()) { args.push_back("--pid"); args.push_back(QString::number(pid())); } else { args += launchArguments(); } return QProcess::startDetached(launcherPath, args); } gammaray-2.3.0/launcher/launchoptions.h000066400000000000000000000060041255003167400201550ustar00rootroot00000000000000/* launchoptions.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LAUNCHOPTIONS_H #define GAMMARAY_LAUNCHOPTIONS_H #include #include #include class QVariant; namespace GammaRay { /** Describes the injection and probe options used for launching/attacing to a host process. */ class LaunchOptions { public: LaunchOptions(); ~LaunchOptions(); enum UiMode { InProcessUi, OutOfProcessUi, NoUi }; /** Returns @c true if this is valid and has launch arguments set. */ bool isLaunch() const; /** Returns @c true if we are supposed to attach rather than start a new process. */ bool isAttach() const; /** Returns @c true if no valid launch arguments or process id are set. */ bool isValid() const; /** Generic key/value settings send to the probe. */ void setProbeSetting(const QString &key, const QVariant &value); QHash probeSettings() const; /** Program and command line arguments to launch. */ void setLaunchArguments(const QStringList &args); QStringList launchArguments() const; /** Absolute path (as far as it can be determined) of the executable to launch. * Only valid if isLaunch() returns @c true. */ QString absoluteExecutablePath() const; /** Process id for the process to attach to. */ void setPid(int pid); int pid() const; /** UI mode. */ UiMode uiMode() const; void setUiMode(UiMode mode); /** Injector type. */ QString injectorType() const; void setInjectorType(const QString &injectorType); /** Probe ABI. */ ProbeABI probeABI() const; void setProbeABI(const ProbeABI &abi); /** execute this launch options with the given command-line launcher. */ bool execute(const QString& launcherPath) const; private: QStringList m_launchArguments; QString m_injectorType; ProbeABI m_probeABI; int m_pid; UiMode m_uiMode; QHash m_probeSettings; }; } #endif // GAMMARAY_LAUNCHOPTIONS_H gammaray-2.3.0/launcher/main.cpp000066400000000000000000000231071255003167400165510ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "config-gammaray-version.h" #include "injector/injectorfactory.h" #include "launchoptions.h" #include "launcherfinder.h" #include "launcher.h" #include "probefinder.h" #include "common/paths.h" #include "common/probeabi.h" #include "common/probeabidetector.h" #ifdef HAVE_QT_WIDGETS #include #else #include #endif #include #include #include #include #include using namespace GammaRay; QTextStream out(stdout); QTextStream err(stderr); static void usage(const char *argv0) { out << "Usage: " << argv0 << " [options] [--pid | | --connect [:]]" << endl; out << "" << endl; out << "Inspect runtime internals of a Qt-application, such as:" << endl; out << " QObject tree, properties, signal/slots, widgets, models," << endl; out << " graphics views, javascript debugger, resources," << endl; out << " state machines, meta types, fonts, codecs, text documents" << endl; out << "" << endl; out << "Options:" << endl; out << " -i, --injector \tset injection type, possible values:" << endl; out << " \t" << InjectorFactory::availableInjectors().join(", ") << endl; out << " -p, --pid \tattach to running Qt application" << endl; out << " --inprocess \tuse in-process UI" << endl; out << " --inject-only \tonly inject the probe, don't show the UI" << endl; out << " --listen
\tspecify the address the server should listen on [default: 0.0.0.0]" << endl; out << " --no-listen \tdisables remote access entirely (implies --inprocess)" << endl; out << " --list-probes \tlist all installed probes" << endl; out << " --probe \tspecify which probe to use" << endl; out << " --connect [:port]\tconnect to an already injected target" << endl; out << " -h, --help \tprint program help and exit" << endl; out << " -v, --version \tprint program version and exit" << endl; #ifdef HAVE_QT_WIDGETS out << endl << "When run without any options, " << argv0 << " will present a list of running\n" << "Qt-applications from which you can attach the selected injector. Else,\n" << "you can attach to a running process by specifying its pid, or you can\n" << "start a new Qt-application by specifying its name (and optional arguments)." << endl; #endif } static bool startLauncher() { const QString launcherPath = LauncherFinder::findLauncher(LauncherFinder::LauncherUI); QProcess proc; proc.setProcessChannelMode(QProcess::ForwardedChannels); proc.start(launcherPath); if (!proc.waitForFinished(-1)) return false; return proc.exitCode() == 0; } static QUrl urlFromUserInput(const QString &s) { QUrl url(s); if (url.scheme().isEmpty()) { // backward compat: map input without a scheme to tcp + hostname url.setScheme("tcp"); QString host = url.path(); int port = -1; const int pos = host.lastIndexOf(":"); if (pos > 0) { port = host.mid(pos + 1).toUShort(); host = host.left(pos); } url.setHost(host); url.setPort(port); url.setPath(QString()); } return url; } int main(int argc, char **argv) { QCoreApplication::setOrganizationName("KDAB"); QCoreApplication::setOrganizationDomain("kdab.com"); QCoreApplication::setApplicationName("GammaRay"); QStringList args; args.reserve(argc); for (int i = 1; i < argc; ++i) { args.push_back(QString::fromLocal8Bit(argv[i])); } #ifdef HAVE_QT_WIDGETS QApplication app(argc, argv); // for style inspector #else QCoreApplication app(argc, argv); #endif Paths::setRelativeRootPath(GAMMARAY_INVERSE_BIN_DIR); QStringList builtInArgs = QStringList() << QLatin1String("-style") << QLatin1String("-stylesheet") << QLatin1String("-graphicssystem"); LaunchOptions options; while (!args.isEmpty() && args.first().startsWith('-')) { const QString arg = args.takeFirst(); if ((arg == QLatin1String("-i") || arg == QLatin1String("--injector")) && !args.isEmpty()) { options.setInjectorType(args.takeFirst()); continue; } if ((arg == QLatin1String("-p") || arg == QLatin1String("--pid")) && !args.isEmpty()) { options.setPid( args.takeFirst().toInt() ); continue; } if (arg == QLatin1String("-h") || arg == QLatin1String("--help")) { usage(argv[0]); return 0; } if (arg == QLatin1String("-v") || arg == QLatin1String("--version")) { out << "GammaRay version " << GAMMARAY_VERSION_STRING << endl; out << "Copyright (C) 2010-2015 Klaralvdalens Datakonsult AB, " << "a KDAB Group company, info@kdab.com" << endl; return 0; } if (arg == QLatin1String("--inprocess")) { options.setUiMode(LaunchOptions::InProcessUi); } if (arg == QLatin1String("--inject-only")) { options.setUiMode(LaunchOptions::NoUi); } if (arg == QLatin1String("--listen") && !args.isEmpty()) { options.setProbeSetting("ServerAddress", urlFromUserInput(args.takeFirst()).toString()); } if ( arg == QLatin1String("--no-listen")) { options.setProbeSetting("RemoteAccessEnabled", false); options.setUiMode(LaunchOptions::InProcessUi); } if ( arg == QLatin1String("--list-probes")) { foreach( const ProbeABI &abi, ProbeFinder::listProbeABIs()) out << abi.id() << " (" << abi.displayString() << ")" << endl; return 0; } if ( arg == QLatin1String("--probe") && !args.isEmpty()) { const ProbeABI abi = ProbeABI::fromString(args.takeFirst()); if (!abi.isValid()) { out << "Invalid probe ABI specified, see --list-probes for valid ones." << endl; return 1; } if (ProbeFinder::findProbe(GAMMARAY_PROBE_NAME, abi).isEmpty()) { out << abi.id() << "is not a known probe, see --list-probes." << endl; return 1; } options.setProbeABI(abi); } if ( arg == QLatin1String("--connect") && !args.isEmpty()) { const QUrl url = urlFromUserInput(args.takeFirst()); ClientLauncher client; client.launch(url); client.waitForFinished(); return 0; } // debug/test options if (arg == QLatin1String("-filtertest")) { qputenv("GAMMARAY_TEST_FILTER", "1"); } if (arg == QLatin1String("-unittest")) { qputenv("GAMMARAY_UNITTEST", "1"); } if (arg == QLatin1String("-modeltest")) { qputenv("GAMMARAY_MODELTEST", "1"); } // built-in arguments of QApp, could be meant for us if we are showing the launcher window foreach (const QString &builtInArg, builtInArgs) { if (arg == builtInArg && !args.isEmpty()) { args.takeFirst(); } } } options.setLaunchArguments(args); if (!options.isValid()) { if (startLauncher()) return 0; usage(argv[0]); return 1; } if (!options.isValid()) return 0; Q_ASSERT(options.isValid()); // attempt to autodetect probe ABI, if not set explicitly if (!options.probeABI().isValid()) { ProbeABIDetector detector; if (options.isLaunch()) { options.setProbeABI(detector.abiForExecutable(options.absoluteExecutablePath())); } else { options.setProbeABI(detector.abiForProcess(options.pid())); } } // find a compatible probe if (options.probeABI().isValid()) { const ProbeABI bestABI = ProbeFinder::findBestMatchingABI(options.probeABI()); if (!bestABI.isValid()) { out << "No probe found for ABI " << options.probeABI().id() << endl; return 1; } out << "Detected ABI " << options.probeABI().id() << ", using ABI " << bestABI.id() << "." << endl; options.setProbeABI(bestABI); } else { const QVector availableProbes = ProbeFinder::listProbeABIs(); if (availableProbes.isEmpty()) { out << "No probes found, this is likely an installation problem." << endl; return 1; } if (availableProbes.size() > 1) { out << "No probe ABI specified and ABI auto-detection failed, picking " << availableProbes.first().id() << " at random." << endl; out << "To specify the probe ABI explicitly use --probe , available probes are listed using the --list-probes option." << endl; } options.setProbeABI(availableProbes.first()); } Launcher launcher(options); QObject::connect(&launcher, SIGNAL(finished()), &app, SLOT(quit())); return app.exec(); } gammaray-2.3.0/launcher/probefinder.cpp000066400000000000000000000054451255003167400201310ustar00rootroot00000000000000/* probefinder.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probefinder.h" #include #include #include #include #include #include #include #include #include #include namespace GammaRay { namespace ProbeFinder { QString findProbe(const QString &baseName, const ProbeABI &probeAbi) { const QString probePath = Paths::probePath(probeAbi.id()) % QDir::separator() % baseName % Paths::libraryExtension(); const QFileInfo fi(probePath); const QString canonicalPath = fi.canonicalFilePath(); if (!fi.isFile() || !fi.isReadable() || canonicalPath.isEmpty()) { qWarning() << "Cannot locate probe" << probePath; qWarning() << "This is likely a setup problem, due to an incomplete or partially moved installation."; return QString(); } return canonicalPath; } ProbeABI findBestMatchingABI(const ProbeABI& targetABI) { return findBestMatchingABI(targetABI, listProbeABIs()); } ProbeABI findBestMatchingABI(const ProbeABI &targetABI, const QVector &availableABIs) { QVector compatABIs; foreach (const ProbeABI &abi, availableABIs) { if (targetABI.isCompatible(abi)) compatABIs.push_back(abi); } if (compatABIs.isEmpty()) return ProbeABI(); std::sort(compatABIs.begin(), compatABIs.end()); return compatABIs.last(); } QVector listProbeABIs() { QVector abis; const QDir dir(Paths::probePath(QString())); foreach (const QString &abiId, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { const ProbeABI abi = ProbeABI::fromString(abiId); if (abi.isValid()) abis.push_back(abi); } return abis; } } } gammaray-2.3.0/launcher/probefinder.h000066400000000000000000000035601255003167400175720ustar00rootroot00000000000000/* probefinder.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBEFINDER_H #define GAMMARAY_PROBEFINDER_H #include class QString; class QStringList; namespace GammaRay { class ProbeABI; namespace ProbeFinder { /** * Attempts to find the full path of the probe DLL. */ QString findProbe(const QString& baseName, const ProbeABI& probeAbi); /** * Find the best matching probe for the given @p targetABI. * An invalid ProbeABI instance is returned if there is no compatible probe installed. */ ProbeABI findBestMatchingABI(const ProbeABI &targetABI); ProbeABI findBestMatchingABI(const ProbeABI &targetABI, const QVector &availableABIs); /** * List all available probe ABIs. */ QVector listProbeABIs(); } } #endif // GAMMARAY_PROBEFINDER_H gammaray-2.3.0/launcher/ui/000077500000000000000000000000001255003167400155335ustar00rootroot00000000000000gammaray-2.3.0/launcher/ui/CMakeLists.txt000066400000000000000000000031431255003167400202740ustar00rootroot00000000000000set(gammaray_launcher_ui_internal_srcs promolabel.cpp launcherwindow.cpp launchpage.cpp selftestpage.cpp connectpage.cpp networkdiscoverymodel.cpp attachdialog.cpp processmodel.cpp processfiltermodel.cpp probeabimodel.cpp ) if(NOT WIN32) list(APPEND gammaray_launcher_ui_internal_srcs processlist_unix.cpp) else() list(APPEND gammaray_launcher_ui_internal_srcs processlist_win.cpp) endif() qt4_wrap_ui(gammaray_launcher_ui_internal_srcs attachdialog.ui launcherwindow.ui launchpage.ui selftestpage.ui connectpage.ui ) add_library(gammaray_launcher_ui_internal STATIC ${gammaray_launcher_ui_internal_srcs}) target_link_libraries(gammaray_launcher_ui_internal LINK_PUBLIC gammaray_launcher_shared LINK_PRIVATE ${QT_QTCORE_LIBRARIES} ${QT_QTCONCURRENT_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTNETWORK_LIBRARIES} gammaray_ui ) set(gammaray_launcher_ui_srcs main.cpp) # TODO we don't need all the class icons here, so split the qrc file accordingly qt4_add_resources(gammaray_launcher_ui_srcs ${CMAKE_SOURCE_DIR}/resources/gammaray.qrc) add_executable(gammaray-launcher WIN32 ${gammaray_launcher_ui_srcs}) target_link_libraries(gammaray-launcher ${QT_QTGUI_LIBRARIES} gammaray_common_internal gammaray_launcher_ui_internal ) if(QNXNTO) target_link_libraries(gammaray-launcher cpp) endif() gammaray_embed_info_plist(gammaray-launcher ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in) set_target_properties(gammaray-launcher PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${LIBEXEC_INSTALL_DIR}" ) install(TARGETS gammaray-launcher DESTINATION ${LIBEXEC_INSTALL_DIR}) gammaray-2.3.0/launcher/ui/Info.plist.in000066400000000000000000000006341255003167400201130ustar00rootroot00000000000000 CFBundleIdentifier com.kdab.GammaRay.launcherUi CFBundleInfoDictionaryVersion 6.0 CFBundleName GammaRay CFBundleVersion @GAMMARAY_VERSION_STRING@ CFBundleShortVersion @GAMMARAY_VERSION@ gammaray-2.3.0/launcher/ui/attachdialog.cpp000066400000000000000000000123551255003167400206710ustar00rootroot00000000000000/* attachdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "attachdialog.h" #include "launchoptions.h" #include "processfiltermodel.h" #include "processmodel.h" #include "probeabimodel.h" #include #include #include #include #include #include #include #include #include using namespace GammaRay; AttachDialog::AttachDialog(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), m_abiModel(new ProbeABIModel(this)) { ui.setupUi(this); #if defined(Q_OS_MAC) QMargins margins = ui.formLayout->contentsMargins(); margins.setRight(margins.right() +2); margins.setBottom(margins.bottom() +2); ui.formLayout->setContentsMargins(margins); #endif m_model = new ProcessModel(this); m_proxyModel = new ProcessFilterModel(this); m_proxyModel->setSourceModel(m_model); m_proxyModel->setDynamicSortFilter(true); ui.view->setModel(m_proxyModel); // hide state ui.view->hideColumn(ProcessModel::StateColumn); ui.view->sortByColumn(ProcessModel::NameColumn, Qt::AscendingOrder); ui.view->setSortingEnabled(true); ui.view->setEditTriggers(QAbstractItemView::NoEditTriggers); ui.view->setSelectionBehavior(QAbstractItemView::SelectRows); ui.view->setSelectionMode(QAbstractItemView::SingleSelection); connect(ui.view->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SIGNAL(updateButtonState())); connect(ui.view->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(selectABI(QModelIndex))); connect(ui.view, SIGNAL(activated(QModelIndex)), SIGNAL(activate())); ui.filter->setProxy(m_proxyModel); ui.probeBox->setModel(m_abiModel); QSettings settings; ui.accessMode->setCurrentIndex(settings.value(QLatin1String("Launcher/AttachAccessMode")).toInt()); setWindowTitle(tr("GammaRay - Attach to Process")); setWindowIcon(QIcon(":gammaray/GammaRay-128x128.png")); ui.stackedWidget->setCurrentWidget(ui.loadingLabel); emit updateButtonState(); updateProcesses(); } bool AttachDialog::isValid() const { return ui.view->currentIndex().isValid(); } void AttachDialog::writeSettings() { QSettings settings; settings.setValue(QLatin1String("Launcher/AttachAccessMode"), ui.accessMode->currentIndex()); } LaunchOptions AttachDialog::launchOptions() const { LaunchOptions opt; opt.setPid(pid()); opt.setProbeABI(ui.probeBox->itemData(ui.probeBox->currentIndex()).value()); switch (ui.accessMode->currentIndex()) { case 0: // local, out-of-process opt.setProbeSetting("ServerAddress", "tcp://127.0.0.1/"); opt.setUiMode(LaunchOptions::OutOfProcessUi); break; case 1: // remote, out-of-process opt.setProbeSetting("ServerAddress", "tcp://0.0.0.0/"); opt.setUiMode(LaunchOptions::OutOfProcessUi); break; case 2: // in-process opt.setProbeSetting("RemoteAccessEnabled", false); opt.setUiMode(LaunchOptions::InProcessUi); break; } return opt; } int AttachDialog::pid() const { return ui.view->currentIndex().data(ProcessModel::PIDRole).toInt(); } void AttachDialog::updateProcesses() { QFutureWatcher* watcher = new QFutureWatcher(this); connect(watcher, SIGNAL(finished()), this, SLOT(updateProcessesFinished())); watcher->setFuture(QtConcurrent::run(processList, m_model->processes())); } void AttachDialog::updateProcessesFinished() { QFutureWatcher* watcher = dynamic_cast*>(sender()); Q_ASSERT(watcher); ui.stackedWidget->setCurrentWidget(ui.listViewPage); const int oldPid = pid(); m_model->mergeProcesses(watcher->result()); if (oldPid != pid()) { ui.view->setCurrentIndex(QModelIndex()); } watcher->deleteLater(); QTimer::singleShot(1000, this, SLOT(updateProcesses())); } void AttachDialog::selectABI(const QModelIndex& processIndex) { if (!processIndex.isValid()) return; const ProbeABI abi = processIndex.data(ProcessModel::ABIRole).value(); const int abiIndex = m_abiModel->indexOfBestMatchingABI(abi); if (abiIndex >= 0) ui.probeBox->setCurrentIndex(abiIndex); } gammaray-2.3.0/launcher/ui/attachdialog.h000066400000000000000000000040331255003167400203300ustar00rootroot00000000000000/* attachdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ATTACHDIALOG_H #define GAMMARAY_ATTACHDIALOG_H #include #include "processlist.h" #include "ui_attachdialog.h" namespace GammaRay { class LaunchOptions; class ProcessModel; class ProcessFilterModel; class ProbeABIModel; class AttachDialog : public QWidget { Q_OBJECT public: explicit AttachDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); LaunchOptions launchOptions() const; int pid() const; /// Returns @c true if a valid process is selected. bool isValid() const; void writeSettings(); signals: void updateButtonState(); void activate(); private slots: void updateProcesses(); void updateProcessesFinished(); void selectABI(const QModelIndex &processIndex); private: Ui::AttachDialog ui; ProcessModel *m_model; ProcessFilterModel *m_proxyModel; ProbeABIModel *m_abiModel; }; } // namespace GammaRay #endif // ATTACHDIALOG_H gammaray-2.3.0/launcher/ui/attachdialog.ui000066400000000000000000000070451255003167400205240ustar00rootroot00000000000000 GammaRay::AttachDialog 0 0 400 323 Dialog :/gammaray/GammaRay-128x128.png:/gammaray/GammaRay-128x128.png 1 <html><head/><body><p align="center"><img src=":/gammaray/GammaRay-48x48.png"/></p><p align="center">Retrieving the list of processes which use Qt ...</p></body></html> 0 false Pro&be: probeBox &Access mode: accessMode 0 Out-of-process, local debugging only Out-of-process, remote debugging enabled In-process listViewPage loadingLabel KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
1
gammaray-2.3.0/launcher/ui/connectpage.cpp000066400000000000000000000055451255003167400205360ustar00rootroot00000000000000/* connectpage.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectpage.h" #include "ui_connectpage.h" #include "networkdiscoverymodel.h" #include "clientlauncher.h" #include #include #include using namespace GammaRay; ConnectPage::ConnectPage(QWidget* parent): QWidget(parent), ui(new Ui::ConnectPage) { ui->setupUi(this); connect(ui->host, SIGNAL(textChanged(QString)), SIGNAL(updateButtonState())); connect(ui->port, SIGNAL(valueChanged(int)), SIGNAL(updateButtonState())); NetworkDiscoveryModel* model = new NetworkDiscoveryModel(this); ui->instanceView->setModel(model); connect(ui->instanceView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(instanceSelected())); connect(ui->instanceView, SIGNAL(activated(QModelIndex)), SIGNAL(activate())); QSettings settings; ui->host->setText(settings.value("Connect/Host", QString()).toString()); ui->port->setValue(settings.value("Connect/Port", Endpoint::defaultPort()).toInt()); } ConnectPage::~ConnectPage() { } bool ConnectPage::isValid() const { return !ui->host->text().isEmpty(); } void ConnectPage::launchClient() { QUrl url; url.setScheme("tcp"); url.setHost(ui->host->text()); url.setPort(ui->port->value()); ClientLauncher::launchDetached(url); } void ConnectPage::writeSettings() { QSettings settings; settings.setValue("Connect/Host", ui->host->text()); settings.setValue("Connect/Port", ui->port->value()); } void ConnectPage::instanceSelected() { const QModelIndexList rows = ui->instanceView->selectionModel()->selectedRows(); if (rows.size() != 1) return; ui->host->setText(rows.first().data(NetworkDiscoveryModel::HostNameRole).toString()); ui->port->setValue(rows.first().data(NetworkDiscoveryModel::PortRole).toInt()); } gammaray-2.3.0/launcher/ui/connectpage.h000066400000000000000000000033021255003167400201700ustar00rootroot00000000000000/* connectpage.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTPAGE_H #define GAMMARAY_CONNECTPAGE_H #include namespace GammaRay { namespace Ui { class ConnectPage; } /** UI for connecting to a running GammaRay instance. */ class ConnectPage : public QWidget { Q_OBJECT public: explicit ConnectPage(QWidget* parent = 0); ~ConnectPage(); bool isValid() const; void writeSettings(); public slots: void launchClient(); signals: void updateButtonState(); void activate(); private slots: void instanceSelected(); private: QScopedPointer ui; }; } #endif // GAMMARAY_CONNECTPAGE_H gammaray-2.3.0/launcher/ui/connectpage.ui000066400000000000000000000032051255003167400203600ustar00rootroot00000000000000 GammaRay::ConnectPage 0 0 400 300 Connect to a running remote instance. &Host: host &Port: port 65536 false true gammaray-2.3.0/launcher/ui/launcherwindow.cpp000066400000000000000000000072161255003167400212760ustar00rootroot00000000000000/* launcherwindow.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "launcherwindow.h" #include "ui_launcherwindow.h" #include "launchoptions.h" #include #include #include using namespace GammaRay; LauncherWindow::LauncherWindow(QWidget *parent) : QDialog(parent), ui(new Ui::LauncherWindow) { ui->setupUi(this); ui->aboutLabel->setText(AboutData::aboutText()); connect(ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged())); connect(ui->attachPage, SIGNAL(updateButtonState()), SLOT(tabChanged())); connect(ui->launchPage, SIGNAL(updateButtonState()), SLOT(tabChanged())); connect(ui->connectPage, SIGNAL(updateButtonState()), SLOT(tabChanged())); connect(ui->attachPage, SIGNAL(activate()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(click())); connect(ui->connectPage, SIGNAL(activate()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(click())); setWindowTitle(tr("GammaRay Launcher")); QSettings settings; ui->tabWidget->setCurrentIndex(settings.value(QLatin1String("Launcher/TabIndex")).toInt()); } LauncherWindow::~LauncherWindow() { delete ui; } LaunchOptions LauncherWindow::launchOptions() const { QWidget *current = ui->tabWidget->currentWidget(); if (current == ui->launchPage) { return ui->launchPage->launchOptions(); } else if (current == ui->attachPage) { return ui->attachPage->launchOptions(); } return LaunchOptions(); } void LauncherWindow::tabChanged() { if (ui->tabWidget->currentWidget() == ui->attachPage) { ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Attach")); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->attachPage->isValid()); } else if (ui->tabWidget->currentWidget() == ui->launchPage) { ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Launch")); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->launchPage->isValid()); } else if (ui->tabWidget->currentWidget() == ui->connectPage) { ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Connect")); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->connectPage->isValid()); } else { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } } void LauncherWindow::accept() { QSettings settings; settings.setValue(QLatin1String("Launcher/TabIndex"), ui->tabWidget->currentIndex()); ui->launchPage->writeSettings(); ui->attachPage->writeSettings(); ui->connectPage->writeSettings(); if (ui->tabWidget->currentWidget() == ui->connectPage) { ui->connectPage->launchClient(); } QDialog::accept(); } gammaray-2.3.0/launcher/ui/launcherwindow.h000066400000000000000000000032701255003167400207370ustar00rootroot00000000000000/* launcherwindow.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LAUNCHERWINDOW_H #define GAMMARAY_LAUNCHERWINDOW_H #include namespace GammaRay { class LaunchOptions; namespace Ui { class LauncherWindow; } class LauncherWindow : public QDialog { Q_OBJECT public: explicit LauncherWindow(QWidget *parent = 0); ~LauncherWindow(); /// returns all information required to perform the launch/attach LaunchOptions launchOptions() const; void accept() Q_DECL_OVERRIDE; private slots: void tabChanged(); private: Ui::LauncherWindow *ui; }; } #endif // GAMMARAY_LAUNCHERWINDOW_H gammaray-2.3.0/launcher/ui/launcherwindow.ui000066400000000000000000000131611255003167400211250ustar00rootroot00000000000000 GammaRay::LauncherWindow 0 0 748 482 Dialog :/gammaray/GammaRay-128x128.png:/gammaray/GammaRay-128x128.png 3 Attach Launch Connect Self Test About 0 0 :/gammaray/GammaRay-128x128.png Qt::Vertical 20 40 0 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true true 0 Qt::Horizontal QDialogButtonBox::Close|QDialogButtonBox::Ok GammaRay::PromoLabel QWidget
promolabel.h
1
GammaRay::AttachDialog QWidget
attachdialog.h
1
GammaRay::LaunchPage QWidget
launchpage.h
1
GammaRay::SelfTestPage QWidget
selftestpage.h
1
GammaRay::ConnectPage QWidget
connectpage.h
1
buttonBox accepted() GammaRay::LauncherWindow accept() 248 254 157 274 buttonBox rejected() GammaRay::LauncherWindow reject() 316 260 286 274
gammaray-2.3.0/launcher/ui/launchpage.cpp000066400000000000000000000136041255003167400203520ustar00rootroot00000000000000/* launchpage.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "launchpage.h" #include "ui_launchpage.h" #include "launchoptions.h" #include "probefinder.h" #include "probeabimodel.h" #include #include #include #include #include using namespace GammaRay; LaunchPage::LaunchPage(QWidget *parent) : QWidget(parent), ui(new Ui::LaunchPage), m_argsModel(new QStringListModel(this)), m_abiModel(new ProbeABIModel(this)), m_abiIsValid(true) { ui->setupUi(this); #if defined(Q_OS_MAC) QMargins margins = ui->formLayout->contentsMargins(); margins.setRight(margins.right() +2); margins.setBottom(margins.bottom() +2); ui->formLayout->setContentsMargins(margins); #endif connect(ui->progSelectButton, SIGNAL(clicked()), SLOT(showFileDialog())); connect(ui->addArgButton, SIGNAL(clicked()), SLOT(addArgument())); connect(ui->removeArgButton, SIGNAL(clicked()), SLOT(removeArgument())); connect(ui->progEdit, SIGNAL(textChanged(QString)), SLOT(detectABI(QString))); connect(ui->progEdit, SIGNAL(textChanged(QString)), SIGNAL(updateButtonState())); ui->argsBox->setModel(m_argsModel); QCompleter *pathCompleter = new QCompleter(this); QFileSystemModel *fsModel = new QFileSystemModel(this); fsModel->setRootPath(QDir::rootPath()); pathCompleter->setModel(fsModel); ui->progEdit->setCompleter(pathCompleter); ui->probeBox->setModel(m_abiModel); QSettings settings; ui->progEdit->setText(settings.value(QLatin1String("Launcher/Program")).toString()); m_argsModel->setStringList(settings.value(QLatin1String("Launcher/Arguments")).toStringList()); ui->accessMode->setCurrentIndex(settings.value(QLatin1String("Launcher/AccessMode")).toInt()); updateArgumentButtons(); } LaunchPage::~LaunchPage() { delete ui; } void LaunchPage::writeSettings() { QSettings settings; settings.setValue(QLatin1String("Launcher/Program"), ui->progEdit->text()); settings.setValue(QLatin1String("Launcher/Arguments"), notEmptyString(m_argsModel->stringList())); settings.setValue(QLatin1String("Launcher/AccessMode"), ui->accessMode->currentIndex()); } QStringList LaunchPage::notEmptyString(const QStringList &list) const { QStringList notEmptyStringList; const int numberOfArguments = list.count(); for (int i = 0; i < numberOfArguments; ++i) { if(!list.at(i).trimmed().isEmpty()) { notEmptyStringList << list.at(i); } } return notEmptyStringList; } LaunchOptions LaunchPage::launchOptions() const { LaunchOptions opt; QStringList l; l.push_back(ui->progEdit->text()); l.append(notEmptyString(m_argsModel->stringList())); opt.setLaunchArguments(l); opt.setProbeABI(ui->probeBox->itemData(ui->probeBox->currentIndex()).value()); switch (ui->accessMode->currentIndex()) { case 0: // local, out-of-process opt.setProbeSetting("RemoteAccessEnabled", true); opt.setProbeSetting("ServerAddress", "tcp://127.0.0.1/"); opt.setUiMode(LaunchOptions::OutOfProcessUi); break; case 1: // remote, out-of-process opt.setProbeSetting("RemoteAccessEnabled", true); opt.setProbeSetting("ServerAddress", "tcp://0.0.0.0/"); opt.setUiMode(LaunchOptions::OutOfProcessUi); break; case 2: // in-process opt.setProbeSetting("RemoteAccessEnabled", false); opt.setUiMode(LaunchOptions::InProcessUi); break; } return opt; } void LaunchPage::showFileDialog() { const QString exeFilePath = QFileDialog::getOpenFileName( this, tr("Executable to Launch"), ui->progEdit->text() #ifdef Q_OS_WIN ,tr("Executable (*.exe)") #endif ); if (exeFilePath.isEmpty()) { return; } ui->progEdit->setText(exeFilePath); } void LaunchPage::addArgument() { m_argsModel->insertRows(m_argsModel->rowCount(), 1); const QModelIndex newIndex = m_argsModel->index(m_argsModel->rowCount() - 1, 0); ui->argsBox->edit(newIndex); updateArgumentButtons(); } void LaunchPage::removeArgument() { // TODO check if there's a selection at all and update button state accordingly m_argsModel->removeRows(ui->argsBox->currentIndex().row(), 1); updateArgumentButtons(); } bool LaunchPage::isValid() { if (ui->progEdit->text().isEmpty() || !m_abiIsValid) { return false; } const QFileInfo fi(ui->progEdit->text()); #ifdef Q_OS_MAC if (fi.isBundle() && (fi.suffix() == "app")) { return true; } #endif return fi.exists() && fi.isFile() && fi.isExecutable(); } void LaunchPage::updateArgumentButtons() { ui->removeArgButton->setEnabled(m_argsModel->rowCount() > 0); } void LaunchPage::detectABI(const QString &path) { const ProbeABI abi = m_abiDetector.abiForExecutable(path); const int index = m_abiModel->indexOfBestMatchingABI(abi); if (index >= 0) ui->probeBox->setCurrentIndex(index); m_abiIsValid = index >= 0; emit updateButtonState(); } gammaray-2.3.0/launcher/ui/launchpage.h000066400000000000000000000040271255003167400200160ustar00rootroot00000000000000/* launchpage.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LAUNCHPAGE_H #define GAMMARAY_LAUNCHPAGE_H #include #include class QStringListModel; namespace GammaRay { class ProbeABIModel; class LaunchOptions; namespace Ui { class LaunchPage; } class LaunchPage : public QWidget { Q_OBJECT public: explicit LaunchPage(QWidget *parent = 0); ~LaunchPage(); LaunchOptions launchOptions() const; bool isValid(); void writeSettings(); signals: void updateButtonState(); private slots: void showFileDialog(); void addArgument(); void removeArgument(); void updateArgumentButtons(); void detectABI(const QString &path); private: QStringList notEmptyString(const QStringList &list) const; Ui::LaunchPage *ui; QStringListModel *m_argsModel; ProbeABIModel *m_abiModel; ProbeABIDetector m_abiDetector; bool m_abiIsValid; }; } #endif // GAMMARAY_LAUNCHPAGE_H gammaray-2.3.0/launcher/ui/launchpage.ui000066400000000000000000000072261255003167400202100ustar00rootroot00000000000000 GammaRay::LaunchPage 0 0 401 305 &Executable: progEdit ... &Program arguments: argsBox &Add &Remove Qt::Vertical 20 170 Pro&be: probeBox 0 0 &Access Mode: accessMode 0 Out-of-process, local-only Out-of-process, remote debugging enabled In-process gammaray-2.3.0/launcher/ui/main.cpp000066400000000000000000000036051255003167400171670ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "launcherwindow.h" #include "launchoptions.h" #include "launcherfinder.h" #include "common/paths.h" #include using namespace GammaRay; int main(int argc, char **argv) { QCoreApplication::setOrganizationName("KDAB"); QCoreApplication::setOrganizationDomain("kdab.com"); QCoreApplication::setApplicationName("GammaRay"); QApplication app(argc, argv); Paths::setRelativeRootPath(GAMMARAY_INVERSE_LIBEXEC_DIR); LauncherWindow launcher; launcher.show(); const int result = app.exec(); if (launcher.result() == QDialog::Accepted) { const LaunchOptions opts = launcher.launchOptions(); if (opts.isValid()) { opts.execute(LauncherFinder::findLauncher(LauncherFinder::Injector)); } } return result; } gammaray-2.3.0/launcher/ui/networkdiscoverymodel.cpp000066400000000000000000000113261255003167400227040ustar00rootroot00000000000000/* networkdiscoverymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "networkdiscoverymodel.h" #include #include #include #include #include using namespace GammaRay; bool NetworkDiscoveryModel::ServerInfo::operator==(const NetworkDiscoveryModel::ServerInfo& other) { return url == other.url; } NetworkDiscoveryModel::NetworkDiscoveryModel(QObject* parent): QAbstractTableModel(parent), m_socket(new QUdpSocket(this)) { m_socket->bind(Endpoint::broadcastPort(), QUdpSocket::ShareAddress); connect(m_socket, SIGNAL(readyRead()), SLOT(processPendingDatagrams())); QTimer *expireTimer = new QTimer(this); expireTimer->setInterval(15 * 1000); expireTimer->setSingleShot(false); connect(expireTimer, SIGNAL(timeout()), SLOT(expireEntries())); expireTimer->start(); } NetworkDiscoveryModel::~NetworkDiscoveryModel() { } void NetworkDiscoveryModel::processPendingDatagrams() { while (m_socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_socket->pendingDatagramSize()); m_socket->readDatagram(datagram.data(), datagram.size()); QDataStream stream(datagram); qint32 broadcastVersion; stream >> broadcastVersion; if (broadcastVersion != Protocol::broadcastFormatVersion()) continue; ServerInfo info; stream >> info.version >> info.url >> info.label; info.lastSeen = QDateTime::currentDateTime(); QVector::iterator it = std::find(m_data.begin(), m_data.end(), info); if (it == m_data.end()) { beginInsertRows(QModelIndex(), m_data.size(), m_data.size()); m_data.push_back(info); endInsertRows(); } else { it->lastSeen = info.lastSeen; } } } void NetworkDiscoveryModel::expireEntries() { const QDateTime threshold = QDateTime::currentDateTime().addSecs(-30); for (QVector::iterator it = m_data.begin(); it != m_data.end();) { if (it->lastSeen >= threshold) { ++it; } else { const int currentRow = std::distance(m_data.begin(), it); beginRemoveRows(QModelIndex(), currentRow, currentRow); it = m_data.erase(it); endRemoveRows(); } } } QVariant NetworkDiscoveryModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); const ServerInfo &info = m_data.at(index.row()); if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return info.label; case 1: return info.url.toString(); } } else if (role == Qt::ToolTipRole) { if (info.version != Protocol::version()) return tr("Incompatible GammaRay version."); } else if (role == HostNameRole) { return info.url.host(); } else if (role == PortRole) { return info.url.port(); } return QVariant(); } int NetworkDiscoveryModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 2; } int NetworkDiscoveryModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_data.size(); } QVariant NetworkDiscoveryModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Name"); case 1: return tr("Host"); } } return QVariant(); } Qt::ItemFlags NetworkDiscoveryModel::flags(const QModelIndex& index) const { const Qt::ItemFlags baseFlags = QAbstractItemModel::flags(index); if (!index.isValid()) return baseFlags; const ServerInfo &info = m_data.at(index.row()); if (info.version != Protocol::version()) return baseFlags & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled); return baseFlags; } gammaray-2.3.0/launcher/ui/networkdiscoverymodel.h000066400000000000000000000045101255003167400223460ustar00rootroot00000000000000/* networkdiscoverymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_NETWORKDISCOVERYMODEL_H #define GAMMARAY_NETWORKDISCOVERYMODEL_H #include #include #include #include class QUdpSocket; namespace GammaRay { /** Lists all active server instances found via network autodiscovery. */ class NetworkDiscoveryModel : public QAbstractTableModel { Q_OBJECT public: enum Role { HostNameRole = Qt::UserRole + 1, PortRole }; explicit NetworkDiscoveryModel(QObject* parent); ~NetworkDiscoveryModel(); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE; private slots: void processPendingDatagrams(); void expireEntries(); private: QUdpSocket *m_socket; struct ServerInfo { bool operator==(const ServerInfo &other); qint32 version; QUrl url; QString label; QDateTime lastSeen; }; QVector m_data; }; } #endif // GAMMARAY_NETWORKDISCOVERYMODEL_H gammaray-2.3.0/launcher/ui/probeabimodel.cpp000066400000000000000000000040501255003167400210420ustar00rootroot00000000000000/* probeabimodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "probeabimodel.h" #include using namespace GammaRay; ProbeABIModel::ProbeABIModel(QObject* parent): QAbstractListModel(parent) { m_abis = ProbeFinder::listProbeABIs(); } ProbeABIModel::~ProbeABIModel() { } QVariant ProbeABIModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); const ProbeABI &abi = m_abis.at(index.row()); switch (role) { case Qt::DisplayRole: return abi.displayString(); case Qt::UserRole: return QVariant::fromValue(abi); } return QVariant(); } int ProbeABIModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_abis.count(); } int ProbeABIModel::indexOfBestMatchingABI(const ProbeABI& targetABI) const { if (!targetABI.isValid()) return -1; const ProbeABI bestMatchingABI = ProbeFinder::findBestMatchingABI(targetABI, m_abis); return m_abis.indexOf(bestMatchingABI); } gammaray-2.3.0/launcher/ui/probeabimodel.h000066400000000000000000000035741255003167400205210ustar00rootroot00000000000000/* probeabimodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROBEABIMODEL_H #define GAMMARAY_PROBEABIMODEL_H #include #include #include namespace GammaRay { /** Model for selecting a probe ABI in the launcher UI. */ class ProbeABIModel : public QAbstractListModel { Q_OBJECT public: explicit ProbeABIModel(QObject *parent = 0); ~ProbeABIModel(); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; int indexOfBestMatchingABI(const ProbeABI &targetABI) const; private: QVector m_abis; }; } // not in its own header to not pollute the metatype space in the target Q_DECLARE_METATYPE(GammaRay::ProbeABI) #endif // GAMMARAY_PROBEABIMODEL_H gammaray-2.3.0/launcher/ui/processfiltermodel.cpp000066400000000000000000000065611255003167400221540ustar00rootroot00000000000000/* processfiltermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "processfiltermodel.h" #include "processmodel.h" #include #if defined(Q_OS_WIN) #include #include static QString qGetLogin() { char winUserName[UNLEN + 1]; // UNLEN is defined in LMCONS.H DWORD winUserNameSize = sizeof(winUserName); GetUserNameA(winUserName, &winUserNameSize); return QString::fromLocal8Bit(winUserName); } #else #include #include #include static QString qGetLogin(){ struct passwd *pw = getpwuid(getuid()); if (!pw || !pw->pw_name) { return QString(); } return QString::fromLocal8Bit(pw->pw_name); } #endif using namespace GammaRay; ProcessFilterModel::ProcessFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { m_currentProcId = QString::number(qApp->applicationPid()); m_currentUser = qGetLogin(); #ifndef Q_OS_WIN if (m_currentUser == QLatin1String("root")) { // empty current user == no filter. as root we want to show all m_currentUser.clear(); } #endif } bool ProcessFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const QString l = sourceModel()->data(left).toString(); const QString r = sourceModel()->data(right).toString(); if (left.column() == ProcessModel::PIDColumn) { return l.toInt() < r.toInt(); } return l.compare(r, Qt::CaseInsensitive) <= 0; } bool ProcessFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { ProcessModel *source = dynamic_cast(sourceModel()); if (!source) { return true; } const ProcData &data = source->dataForRow(source_row); if (!data.abi.isValid()) { return false; } // hide ourselves as well as the process that launched us if (data.ppid == m_currentProcId || data.name == QLatin1String("gammaray")) { return false; } if (!m_currentUser.isEmpty() && data.user != m_currentUser) { return false; } return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } bool ProcessFilterModel::filterAcceptsColumn(int source_column, const QModelIndex &/*source_parent*/) const { // hide user row if current user was found return m_currentUser.isEmpty() || source_column != ProcessModel::UserColumn; } gammaray-2.3.0/launcher/ui/processfiltermodel.h000066400000000000000000000034701255003167400216150ustar00rootroot00000000000000/* processfiltermodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROCESSFILTERMODEL_H #define GAMMARAY_PROCESSFILTERMODEL_H #include namespace GammaRay { // A filterable and sortable process model class ProcessFilterModel : public QSortFilterProxyModel { public: explicit ProcessFilterModel(QObject *parent); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; private: bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; QString m_currentProcId; QString m_currentUser; }; } #endif // GAMMARAY_PROCESSFILTERMODEL_H gammaray-2.3.0/launcher/ui/processlist.h000066400000000000000000000032271255003167400202620ustar00rootroot00000000000000/************************************************************************** ** ** This code is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at info@qt.nokia.com. ** **************************************************************************/ #ifndef GAMMARAY_PROCESSLIST_H #define GAMMARAY_PROCESSLIST_H #include #include #include struct ProcData { QString ppid; QString name; QString image; QString state; QString user; GammaRay::ProbeABI abi; ProcData() {} }; typedef QList ProcDataList; extern ProcDataList processList(const ProcDataList &previous); #endif // PROCESSLIST_H gammaray-2.3.0/launcher/ui/processlist_unix.cpp000066400000000000000000000125771255003167400216700ustar00rootroot00000000000000/************************************************************************** ** ** This code is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at info@qt.nokia.com. ** **************************************************************************/ #include "processlist.h" #include #include #include #include #include static GammaRay::ProbeABIDetector s_abiDetector; static bool isUnixProcessId(const QString &procname) { for (int i = 0; i != procname.size(); ++i) { if (!procname.at(i).isDigit()) { return false; } } return true; } struct PidAndNameMatch : public std::unary_function { explicit PidAndNameMatch(const QString &ppid, const QString &name) : m_ppid(ppid), m_name(name) { } bool operator()(const ProcData &p) const { return p.ppid == m_ppid && m_name == p.name; } const QString m_ppid; const QString m_name; }; // Determine UNIX processes by running ps static ProcDataList unixProcessListPS(const ProcDataList &previous) { #ifdef Q_OS_MAC // command goes last, otherwise it is cut off static const char formatC[] = "pid state user command"; #else static const char formatC[] = "pid,state,user,cmd"; #endif ProcDataList rc; QProcess psProcess; QStringList args; args << QLatin1String("-e") << QLatin1String("-o") << QLatin1String(formatC); psProcess.start(QLatin1String("ps"), args); if (!psProcess.waitForStarted()) { return rc; } psProcess.waitForFinished(); QByteArray output = psProcess.readAllStandardOutput(); // Split "457 S+ /Users/foo.app" const QStringList lines = QString::fromLocal8Bit(output).split(QLatin1Char('\n')); const int lineCount = lines.size(); const QChar blank = QLatin1Char(' '); for (int l = 1; l < lineCount; l++) { // Skip header const QString line = lines.at(l).simplified(); // we can't just split on blank as the process name might // contain them const int endOfPid = line.indexOf(blank); const int endOfState = line.indexOf(blank, endOfPid+1); const int endOfUser = line.indexOf(blank, endOfState+1); if (endOfPid >= 0 && endOfState >= 0 && endOfUser >= 0) { ProcData procData; procData.ppid = line.left(endOfPid); procData.state = line.mid(endOfPid+1, endOfState-endOfPid-1); procData.user = line.mid(endOfState+1, endOfUser-endOfState-1); procData.name = line.right(line.size()-endOfUser-1); ProcDataList::ConstIterator it = std::find_if(previous.constBegin(), previous.constEnd(), PidAndNameMatch(procData.ppid, procData.name)); if (it != previous.constEnd()) { procData.abi = it->abi; } else { procData.abi = s_abiDetector.abiForProcess(procData.ppid.toLongLong()); } rc.push_back(procData); } } return rc; } // Determine UNIX processes by reading "/proc". Default to ps if // it does not exist ProcDataList processList(const ProcDataList &previous) { const QDir procDir(QLatin1String("/proc/")); if (!procDir.exists()) { return unixProcessListPS(previous); } ProcDataList rc; const QStringList procIds = procDir.entryList(); if (procIds.isEmpty()) { return rc; } foreach (const QString &procId, procIds) { if (!isUnixProcessId(procId)) { continue; } QString filename = QLatin1String("/proc/"); filename += procId; filename += QLatin1String("/stat"); QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { continue; // process may have exited } const QStringList data = QString::fromLocal8Bit(file.readAll()).split(' '); ProcData proc; proc.ppid = procId; proc.name = data.at(1); if (proc.name.startsWith(QLatin1Char('(')) && proc.name.endsWith(QLatin1Char(')'))) { proc.name.truncate(proc.name.size() - 1); proc.name.remove(0, 1); } proc.state = data.at(2); // PPID is element 3 proc.user = QFileInfo(file).owner(); file.close(); QFile cmdFile(QLatin1String("/proc/") + procId + QLatin1String("/cmdline")); if(cmdFile.open(QFile::ReadOnly)) { QByteArray cmd = cmdFile.readAll(); cmd.replace('\0', ' '); if (!cmd.isEmpty()) { proc.name = QString::fromLocal8Bit(cmd).trimmed(); } } cmdFile.close(); proc.abi = s_abiDetector.abiForProcess(procId.toLongLong()); rc.push_back(proc); } return rc; } gammaray-2.3.0/launcher/ui/processlist_win.cpp000066400000000000000000000123311255003167400214660ustar00rootroot00000000000000/************************************************************************** ** ** This code is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at info@qt.nokia.com. ** **************************************************************************/ #include "processlist.h" #include #include // Enable Win API of XP SP1 and later #ifdef Q_OS_WIN # if !defined(_WIN32_WINNT) # define _WIN32_WINNT 0x0502 # endif # include # if !defined(PROCESS_SUSPEND_RESUME) // Check flag for MinGW # define PROCESS_SUSPEND_RESUME (0x0800) # endif // PROCESS_SUSPEND_RESUME #endif // Q_OS_WIN #include #include static GammaRay::ProbeABIDetector s_abiDetector; // Resolve QueryFullProcessImageNameW out of kernel32.dll due // to incomplete MinGW import libs and it not being present // on Windows XP. static inline BOOL queryFullProcessImageName(HANDLE h, DWORD flags, LPWSTR buffer, DWORD *size) { // Resolve required symbols from the kernel32.dll typedef BOOL (WINAPI *QueryFullProcessImageNameWProtoType)(HANDLE, DWORD, LPWSTR, PDWORD); static QueryFullProcessImageNameWProtoType queryFullProcessImageNameW = 0; if (!queryFullProcessImageNameW) { QLibrary kernel32Lib(QLatin1String("kernel32.dll"), 0); if (kernel32Lib.isLoaded() || kernel32Lib.load()) { queryFullProcessImageNameW = (QueryFullProcessImageNameWProtoType)kernel32Lib.resolve("QueryFullProcessImageNameW"); } } if (!queryFullProcessImageNameW) { return FALSE; } // Read out process return (*queryFullProcessImageNameW)(h, flags, buffer, size); } struct ProcessInfo { QString imageName; QString processOwner; }; static inline ProcessInfo processInfo(DWORD processId) { ProcessInfo pi; HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, TOKEN_READ, processId); if (handle == INVALID_HANDLE_VALUE) { return pi; } WCHAR buffer[MAX_PATH]; DWORD bufSize = MAX_PATH; if (queryFullProcessImageName(handle, 0, buffer, &bufSize)) { pi.imageName = QString::fromUtf16(reinterpret_cast(buffer)); } HANDLE processTokenHandle = NULL; if (!OpenProcessToken(handle, TOKEN_READ, &processTokenHandle) || !processTokenHandle) { return pi; } DWORD size = 0; GetTokenInformation(processTokenHandle, TokenUser, NULL, 0, &size); if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { QByteArray buf; buf.resize(size); PTOKEN_USER userToken = reinterpret_cast(buf.data()); if (userToken && GetTokenInformation(processTokenHandle, TokenUser, userToken, size, &size)) { SID_NAME_USE sidNameUse; TCHAR user[MAX_PATH] = { 0 }; DWORD userNameLength = MAX_PATH; TCHAR domain[MAX_PATH] = { 0 }; DWORD domainNameLength = MAX_PATH; if (LookupAccountSid(NULL, userToken->User.Sid, user, &userNameLength, domain, &domainNameLength, &sidNameUse)) { pi.processOwner = QString::fromUtf16(reinterpret_cast(user)); } } } CloseHandle(processTokenHandle); CloseHandle(handle); return pi; } ProcDataList processList(const ProcDataList &/*previous*/) { ProcDataList rc; PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { return rc; } for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) { ProcData procData; procData.ppid = QString::number(pe.th32ProcessID); procData.name = QString::fromUtf16(reinterpret_cast(pe.szExeFile)); const ProcessInfo processInf = processInfo(pe.th32ProcessID); procData.image = processInf.imageName; procData.user = processInf.processOwner; procData.abi = s_abiDetector.abiForProcess(pe.th32ProcessID); rc.push_back(procData); } CloseHandle(snapshot); return rc; } gammaray-2.3.0/launcher/ui/processmodel.cpp000066400000000000000000000140101255003167400207320ustar00rootroot00000000000000/* processmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "processmodel.h" #include "probeabimodel.h" #include #include using namespace GammaRay; bool operator<(const ProcData &l, const ProcData &r) { return l.ppid < r.ppid; } bool operator==(const ProcData &l, const ProcData &r) { return l.ppid == r.ppid; } QDebug operator<<(QDebug d, const ProcData &data) { d << "ProcData{.ppid=" << data.ppid << ", .name=" << data.name << ", .image=" << data.image << ", .state=" << data.state << ", .user=" << data.user << ", .type=" << data.abi.id() << "}"; return d; } ProcessModel::ProcessModel(QObject *parent) : QAbstractTableModel(parent) { m_availableABIs = ProbeFinder::listProbeABIs(); } ProcessModel::~ProcessModel() { } void ProcessModel::setProcesses(const ProcDataList &processes) { beginResetModel(); m_data = processes; // sort for merging to work properly qStableSort(m_data); endResetModel(); } void ProcessModel::mergeProcesses(const ProcDataList &processes) { // sort like m_data ProcDataList sortedProcesses = processes; qStableSort(sortedProcesses); // iterator over m_data int i = 0; foreach (const ProcData &newProc, sortedProcesses) { bool shouldInsert = true; while (i < m_data.count()) { const ProcData &oldProc = m_data.at(i); if (oldProc < newProc) { // remove old proc, seems to be outdated beginRemoveRows(QModelIndex(), i, i); m_data.removeAt(i); endRemoveRows(); continue; } else if (newProc == oldProc) { // already contained, hence increment and break ++i; shouldInsert = false; break; } else { // newProc < oldProc // new entry, break and insert it break; } } if (shouldInsert) { beginInsertRows(QModelIndex(), i, i); m_data.insert(i, newProc); endInsertRows(); // let i point to old element again ++i; } } // make sure the new data is properly inserted Q_ASSERT(m_data == sortedProcesses); } void ProcessModel::clear() { beginRemoveRows(QModelIndex(), 0, m_data.count()); m_data.clear(); endRemoveRows(); } ProcData ProcessModel::dataForIndex(const QModelIndex &index) const { return m_data.at(index.row()); } ProcData ProcessModel::dataForRow(int row) const { return m_data.at(row); } QModelIndex ProcessModel::indexForPid(const QString &pid) const { for (int i = 0; i < m_data.size(); ++i) { if (m_data.at(i).ppid == pid) { return index(i, 0); } } return QModelIndex(); } QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { return QVariant(); } if (section == PIDColumn) { return tr("Process ID"); } else if (section == NameColumn) { return tr("Name"); } else if (section == StateColumn) { return tr("State"); } else if (section == UserColumn) { return tr("User"); } return QVariant(); } QVariant ProcessModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const ProcData &data = m_data.at(index.row()); if (role == Qt::DisplayRole) { if (index.column() == PIDColumn) { return data.ppid; } else if (index.column() == NameColumn) { return data.image.isEmpty() ? data.name : data.image; } else if (index.column() == StateColumn) { return data.state; } else if (index.column() == UserColumn) { return data.user; } } else if (role == Qt::ToolTipRole) { const ProbeABI bestABI = ProbeFinder::findBestMatchingABI(data.abi, m_availableABIs); return tr("Name: %1\nPID: %2\nOwner: %3\nQt ABI: %4\nProbe available: %5") .arg(data.image.isEmpty() ? data.name : data.image) .arg(data.ppid) .arg(data.user) .arg(data.abi.displayString()) .arg(bestABI.isValid() ? tr("yes") : tr("no")); } else if (role == PIDRole) { return data.ppid.toInt(); // why is this a QString in the first place!? } else if (role == NameRole) { return data.image.isEmpty() ? data.name : data.image; } else if (role == StateRole) { return data.state; } else if (role == UserRole) { return data.user; } else if (role == ABIRole) { return QVariant::fromValue(data.abi); } return QVariant(); } int ProcessModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : COLUMN_COUNT; } int ProcessModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_data.count(); } ProcDataList ProcessModel::processes() const { return m_data; } Qt::ItemFlags ProcessModel::flags(const QModelIndex& index) const { const ProbeABI abi = index.data(ABIRole).value(); const ProbeABI bestABI = ProbeFinder::findBestMatchingABI(abi, m_availableABIs); const Qt::ItemFlags f = QAbstractItemModel::flags(index); if (!bestABI.isValid()) return f & ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable); return f; } gammaray-2.3.0/launcher/ui/processmodel.h000066400000000000000000000051041255003167400204030ustar00rootroot00000000000000/* processmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROCESSMODEL_H #define GAMMARAY_PROCESSMODEL_H #include #include #include #include "processlist.h" namespace GammaRay { class ProcessModel : public QAbstractTableModel { public: explicit ProcessModel(QObject *parent = 0); virtual ~ProcessModel(); void setProcesses(const ProcDataList &processes); void mergeProcesses(const ProcDataList &processes); ProcData dataForIndex(const QModelIndex &index) const; ProcData dataForRow(int row) const; QModelIndex indexForPid(const QString &pid) const; ProcDataList processes() const; void clear(); enum Columns { PIDColumn, NameColumn, StateColumn, UserColumn, COLUMN_COUNT }; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; enum CustomRoles { PIDRole = Qt::UserRole, NameRole, StateRole, UserRole, ABIRole }; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: ProcDataList m_data; QVector m_availableABIs; }; } #endif // GAMMARAY_PROCESSMODEL_H gammaray-2.3.0/launcher/ui/promolabel.cpp000066400000000000000000000045601255003167400204000ustar00rootroot00000000000000/* mainwindow.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "promolabel.h" #include #include #include #include using namespace GammaRay; PromoLabel::PromoLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f) { updatePixmap(); setCursor(QCursor(Qt::PointingHandCursor)); setToolTip(tr("Visit KDAB Website")); } bool PromoLabel::event(QEvent *e) { if (e->type() == QEvent::PaletteChange) { updatePixmap(); } return QLabel::event(e); } void PromoLabel::mouseReleaseEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton && ev->modifiers() == Qt::NoModifier) { QDesktopServices::openUrl(QUrl("http://www.kdab.com")); ev->accept(); return; } QLabel::mouseReleaseEvent(ev); } QImage PromoLabel::tintedImage(const QString &image, const QColor &color) { QImage img(image); img = img.alphaChannel(); QColor newColor = color; for (int i = 0; i < img.colorCount(); ++i) { newColor.setAlpha(qGray(img.color(i))); img.setColor(i, newColor.rgba()); } return img; } void PromoLabel::updatePixmap() { // load image and adapt it to user's foreground color setPixmap(QPixmap::fromImage(tintedImage(QString(":gammaray/kdabproducts.png"), palette().foreground().color()))); } gammaray-2.3.0/launcher/ui/promolabel.h000066400000000000000000000031301255003167400200350ustar00rootroot00000000000000/* mainwindow.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROMOLABEL_H #define GAMMARAY_PROMOLABEL_H #include namespace GammaRay { class PromoLabel : public QLabel { Q_OBJECT public: explicit PromoLabel(QWidget *parent = 0, Qt::WindowFlags f = 0); static QImage tintedImage(const QString &image, const QColor &color); protected: bool event(QEvent *e) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *ev) Q_DECL_OVERRIDE; private: void updatePixmap(); }; } #endif // PROMOLABEL_H gammaray-2.3.0/launcher/ui/selftestpage.cpp000066400000000000000000000076451255003167400207410ustar00rootroot00000000000000/* selftestpage.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "selftestpage.h" #include "probefinder.h" #include "ui_selftestpage.h" #include "injector/injectorfactory.h" #include #include #include using namespace GammaRay; SelfTestPage::SelfTestPage(QWidget *parent) : QWidget(parent), ui(new Ui::SelfTestPage), m_resultModel(new QStandardItemModel(this)) { ui->setupUi(this); ui->resultView->setModel(m_resultModel); run(); } SelfTestPage::~SelfTestPage() { delete ui; } void SelfTestPage::run() { m_resultModel->clear(); testProbe(); testAvailableInjectors(); testInjectors(); } void SelfTestPage::testProbe() { int validProbeCount = 0; const QVector probeABIs = ProbeFinder::listProbeABIs(); foreach (const ProbeABI &abi, probeABIs) { const QString probePath = ProbeFinder::findProbe(QLatin1String(GAMMARAY_PROBE_NAME), abi); if (probePath.isEmpty()) { error(tr("No probe found for ABI %1.").arg(abi.id())); continue; } QFileInfo fi(probePath); if (!fi.exists() || !fi.isFile() || !fi.isReadable()) { error(tr("Probe at %1 is invalid.")); continue; } information(tr("Found valid probe for ABI %1 at %2.").arg(abi.id()).arg(probePath)); ++validProbeCount; } if (validProbeCount == 0) { error(tr("No probes found - GammaRay no functional.")); } } void SelfTestPage::testAvailableInjectors() { const QStringList injectors = InjectorFactory::availableInjectors(); if (injectors.isEmpty()) { error(tr("No injectors available - GammaRay not functional.")); return; } information(tr("The following injectors are available: %1"). arg(injectors.join(QLatin1String(", ")))); } void SelfTestPage::testInjectors() { foreach (const QString &injectorType, InjectorFactory::availableInjectors()) { AbstractInjector::Ptr injector = InjectorFactory::createInjector(injectorType); if (!injector) { error(tr("Unable to create instance of injector %1.").arg(injectorType)); continue; } if (injector->selfTest()) { information(tr("Injector %1 successfully passed its self-test."). arg(injectorType)); } else { error(tr("Injector %1 failed to pass its self-test: %2."). arg(injectorType, injector->errorString())); } } } void SelfTestPage::error(const QString &msg) { QStandardItem *item = new QStandardItem; item->setEditable(false); item->setText(msg); item->setIcon(style()->standardIcon(QStyle::SP_MessageBoxCritical)); m_resultModel->appendRow(item); } void SelfTestPage::information(const QString &msg) { QStandardItem *item = new QStandardItem; item->setEditable(false); item->setText(msg); item->setIcon(style()->standardIcon(QStyle::SP_MessageBoxInformation)); m_resultModel->appendRow(item); } gammaray-2.3.0/launcher/ui/selftestpage.h000066400000000000000000000033451255003167400203770ustar00rootroot00000000000000/* selftestpage.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SELFTESTPAGE_H #define GAMMARAY_SELFTESTPAGE_H #include class QStandardItemModel; namespace GammaRay { namespace Ui { class SelfTestPage; } class SelfTestPage : public QWidget { Q_OBJECT public: explicit SelfTestPage(QWidget *parent = 0); ~SelfTestPage(); public slots: void run(); private: void testProbe(); void testAvailableInjectors(); void testInjectors(); void error(const QString &msg); void information(const QString &msg); private: Ui::SelfTestPage *ui; QStandardItemModel *m_resultModel; }; } #endif // GAMMARAY_SELFTESTPAGE_H gammaray-2.3.0/launcher/ui/selftestpage.ui000066400000000000000000000007321255003167400205620ustar00rootroot00000000000000 GammaRay::SelfTestPage 0 0 400 300 gammaray-2.3.0/plugins/000077500000000000000000000000001255003167400147765ustar00rootroot00000000000000gammaray-2.3.0/plugins/CMakeLists.txt000066400000000000000000000014451255003167400175420ustar00rootroot00000000000000add_subdirectory(codecbrowser) add_subdirectory(fontbrowser) add_subdirectory(kjobtracker) add_subdirectory(objectvisualizer) add_subdirectory(quickinspector) add_subdirectory(selectionmodelinspector) add_subdirectory(signalmonitor) add_subdirectory(statemachineviewer) add_subdirectory(timertop) add_subdirectory(webinspector) if(Qt5Core_FOUND) add_subdirectory(translatorinspector) endif() if(Qt5Widgets_FOUND OR QT_QTGUI_FOUND) add_subdirectory(actioninspector) add_subdirectory(widgetinspector) add_subdirectory(sceneinspector) add_subdirectory(styleinspector) endif() if(QT_QTSCRIPTTOOLS_FOUND OR Qt5ScriptTools_FOUND) add_subdirectory(scriptenginedebugger) endif() if(Qt5Qml_FOUND) add_subdirectory(qmlsupport) endif() if(Qt5Bluetooth_FOUND) add_subdirectory(bluetooth) endif() gammaray-2.3.0/plugins/actioninspector/000077500000000000000000000000001255003167400202025ustar00rootroot00000000000000gammaray-2.3.0/plugins/actioninspector/CMakeLists.txt000066400000000000000000000013541255003167400227450ustar00rootroot00000000000000# probe part set(gammaray_actioninspector_plugin_srcs actionvalidator.cpp actioninspector.cpp actionmodel.cpp ) gammaray_add_plugin(gammaray_actioninspector_plugin gammaray_actioninspector.desktop ${gammaray_actioninspector_plugin_srcs} ) target_link_libraries(gammaray_actioninspector_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_core ) # ui part if(GAMMARAY_BUILD_UI) set(gammaray_actioninspector_ui_plugin_srcs actioninspectorwidget.cpp ) gammaray_add_plugin(gammaray_actioninspector_ui_plugin gammaray_actioninspector_ui.desktop ${gammaray_actioninspector_ui_plugin_srcs} ) target_link_libraries(gammaray_actioninspector_ui_plugin ${QT_QTGUI_LIBRARIES} gammaray_ui ) endif() gammaray-2.3.0/plugins/actioninspector/actioninspector.cpp000066400000000000000000000056611255003167400241220ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "actioninspector.h" #include "actionmodel.h" #include #include #include #include #include #include #include #include using namespace GammaRay; using namespace std; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_DECLARE_METATYPE(QActionGroup*) Q_DECLARE_METATYPE(QMenu*) #endif ActionInspector::ActionInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) { registerMetaTypes(); ObjectBroker::registerObject("com.kdab.GammaRay.ActionInspector", this); ActionModel *actionModel = new ActionModel(this); connect(probe->probe(), SIGNAL(objectCreated(QObject*)), actionModel, SLOT(objectAdded(QObject*))); connect(probe->probe(), SIGNAL(objectDestroyed(QObject*)), actionModel, SLOT(objectRemoved(QObject*))); probe->registerModel("com.kdab.GammaRay.ActionModel", actionModel); } ActionInspector::~ActionInspector() { } void ActionInspector::triggerAction(int row) { QAbstractItemModel *model = ObjectBroker::model("com.kdab.GammaRay.ActionModel"); const QModelIndex index = model->index(row, 0); if (!index.isValid()) { return; } QObject *obj = index.data(ObjectModel::ObjectRole).value(); QAction *action = qobject_cast(obj); if (action) { action->trigger(); } } void ActionInspector::registerMetaTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT1(QAction, QObject); MO_ADD_PROPERTY_RO(QAction, QActionGroup*, actionGroup); MO_ADD_PROPERTY_CR(QAction, QVariant, data, setData); MO_ADD_PROPERTY (QAction, bool, isSeparator, setSeparator); MO_ADD_PROPERTY_RO(QAction, QMenu*, menu); MO_ADD_PROPERTY_RO(QAction, QWidget*, parentWidget); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(ActionInspectorFactory) #endif gammaray-2.3.0/plugins/actioninspector/actioninspector.h000066400000000000000000000037621255003167400235670ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ACTIONINSPECTOR_ACTIONINSPECTOR_H #define GAMMARAY_ACTIONINSPECTOR_ACTIONINSPECTOR_H #include #include namespace GammaRay { class ActionInspector : public QObject { Q_OBJECT public: explicit ActionInspector(ProbeInterface *probe, QObject *parent = 0); virtual ~ActionInspector(); public Q_SLOTS: void triggerAction(int row); private: void registerMetaTypes(); }; class ActionInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_actioninspector.json") public: explicit ActionInspectorFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Action Inspector"); } }; } #endif // GAMMARAY_ACTIONINSPECTOR_H gammaray-2.3.0/plugins/actioninspector/actioninspectorwidget.cpp000066400000000000000000000056661255003167400253330ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "actioninspectorwidget.h" #include "actionmodel.h" // for column enum only #include #include #include "kde/kfilterproxysearchline.h" #include "kde/krecursivefilterproxymodel.h" #include #include #include #include #include using namespace GammaRay; ActionInspectorWidget::ActionInspectorWidget(QWidget *parent) : QWidget(parent) { QAbstractItemModel *actionModel = ObjectBroker::model("com.kdab.GammaRay.ActionModel"); QSortFilterProxyModel *searchFilterProxy = new KRecursiveFilterProxyModel(this); searchFilterProxy->setSourceModel(actionModel); searchFilterProxy->setDynamicSortFilter(true); m_proxy = searchFilterProxy; QVBoxLayout *vbox = new QVBoxLayout(this); KFilterProxySearchLine *objectSearchLine = new KFilterProxySearchLine(this); objectSearchLine->setProxy(searchFilterProxy); vbox->addWidget(objectSearchLine); QTreeView *objectTreeView = new QTreeView(this); objectTreeView->setModel(searchFilterProxy); objectTreeView->setSortingEnabled(true); objectTreeView->sortByColumn(ActionModel::ShortcutsPropColumn); objectTreeView->setRootIsDecorated(false); vbox->addWidget(objectTreeView); connect(objectTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(triggerAction(QModelIndex))); mObjectTreeView = objectTreeView; } ActionInspectorWidget::~ActionInspectorWidget() { } void ActionInspectorWidget::triggerAction(const QModelIndex &index) { if (!index.isValid()) { return; } Q_ASSERT(index.model() == m_proxy); Endpoint::instance()->invokeObject("com.kdab.GammaRay.ActionInspector", "triggerAction", QVariantList() << m_proxy->mapToSource(index).row()); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(ActionInspectorUiFactory) #endif gammaray-2.3.0/plugins/actioninspector/actioninspectorwidget.h000066400000000000000000000037111255003167400247650ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ACTIONINSPECTOR_ACTIONINSPECTORWIDGET_H #define GAMMARAY_ACTIONINSPECTOR_ACTIONINSPECTORWIDGET_H #include #include #include class QAbstractProxyModel; class QTreeView; class QModelIndex; namespace GammaRay { class ActionInspectorWidget : public QWidget { Q_OBJECT public: explicit ActionInspectorWidget(QWidget *parent = 0); ~ActionInspectorWidget(); private Q_SLOTS: void triggerAction(const QModelIndex &index); private: QTreeView *mObjectTreeView; QAbstractProxyModel *m_proxy; }; class ActionInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_actioninspector.json") }; } #endif // GAMMARAY_ACTIONINSPECTORWIDGET_H gammaray-2.3.0/plugins/actioninspector/actionmodel.cpp000066400000000000000000000130161255003167400232050ustar00rootroot00000000000000/* actionmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "actionmodel.h" #include "actionvalidator.h" #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QAction::Priority) using namespace GammaRay; template static QString toString(QList list) { QStringList items; Q_FOREACH (const T &item, list) { items << item; } return items.join(", "); } ActionModel::ActionModel(QObject *parent) : QAbstractTableModel(parent), m_duplicateFinder(new ActionValidator(this)) { } ActionModel::~ActionModel() { } void ActionModel::objectAdded(QObject* object) { // see Probe::objectCreated, that promises a valid object in the main thread Q_ASSERT(QThread::currentThread() == thread()); Q_ASSERT(object); QAction* const action = qobject_cast(object); if (!action) return; QVector::iterator it = std::lower_bound(m_actions.begin(), m_actions.end(), action); Q_ASSERT(it == m_actions.end() || *it != action); const int row = std::distance(m_actions.begin(), it); Q_ASSERT(row >= 0 && row <= m_actions.size()); beginInsertRows(QModelIndex(), row, row); m_actions.insert(it, action); Q_ASSERT(m_actions.at(row) == action); m_duplicateFinder->insert(action); endInsertRows(); } void ActionModel::objectRemoved(QObject* object) { Q_ASSERT(thread() == QThread::currentThread()); QAction* const action = reinterpret_cast(object); // never dereference this, just use for comparison QVector::iterator it = std::lower_bound(m_actions.begin(), m_actions.end(), reinterpret_cast(object)); if (it == m_actions.end() || *it != action) return; const int row = std::distance(m_actions.begin(), it); Q_ASSERT(row >= 0 && row < m_actions.size()); Q_ASSERT(m_actions.at(row) == action); beginRemoveRows(QModelIndex(), row, row); m_actions.erase(it); m_duplicateFinder->remove(action); endRemoveRows(); } int ActionModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return ColumnCount; } int ActionModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_actions.size(); } QVariant ActionModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_ASSERT(section >= 0); if (role == Qt::DisplayRole) { switch (section) { case AddressColumn: return tr("Address"); case NameColumn: return tr("Name"); case CheckablePropColumn: return tr("Checkable"); case CheckedPropColumn: return tr("Checked"); case PriorityPropColumn: return tr("Priority"); case ShortcutsPropColumn: return tr("Shortcut(s)"); default: return QVariant(); } } return QAbstractTableModel::headerData(section, orientation, role); } QVariant ActionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); QMutexLocker lock(Probe::objectLock()); QAction *action = m_actions.at(index.row()); if (!Probe::instance()->isValidObject(action)) return QVariant(); const int column = index.column(); if (role == Qt::DisplayRole) { switch (column) { case AddressColumn: return Util::addressToString(action); case NameColumn: return action->text(); case CheckablePropColumn: return action->isCheckable(); case CheckedPropColumn: return VariantHandler::displayString(action->isChecked()); case PriorityPropColumn: return Util::enumToString(action->priority(), 0, action); case ShortcutsPropColumn: return toString(action->shortcuts()); default: return QVariant(); } } else if (role == Qt::DecorationRole) { if (column == NameColumn) { return action->icon(); } else if (column == ShortcutsPropColumn && m_duplicateFinder->hasAmbiguousShortcut(action)) { QIcon icon = QIcon::fromTheme("dialog-warning"); if (!icon.isNull()) { return icon; } else { return QColor(Qt::red); } } } else if (role == Qt::ToolTipRole) { if (column == ShortcutsPropColumn && m_duplicateFinder->hasAmbiguousShortcut(action)) { return tr("Warning: Ambiguous shortcut detected."); } } else if (role == ObjectModel::ObjectRole) { return QVariant::fromValue(action); } return QVariant(); } gammaray-2.3.0/plugins/actioninspector/actionmodel.h000066400000000000000000000044361255003167400226600ustar00rootroot00000000000000/* actionmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ACTIONINSPECTOR_ACTIONMODEL_H #define GAMMARAY_ACTIONINSPECTOR_ACTIONMODEL_H #include #include class QAction; namespace GammaRay { class ActionValidator; class ActionModel : public QAbstractTableModel { Q_OBJECT public: enum Column { AddressColumn, NameColumn, CheckablePropColumn, CheckedPropColumn, PriorityPropColumn, ShortcutsPropColumn, /** Mark column count */ ColumnCount }; explicit ActionModel(QObject *parent = 0); ~ActionModel(); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; public slots: void objectAdded(QObject *object); void objectRemoved(QObject *object); private: // sorted vector of QActions QVector m_actions; ActionValidator *m_duplicateFinder; }; } #endif // GAMMARAY_ACTIONMODEL_H gammaray-2.3.0/plugins/actioninspector/actionvalidator.cpp000066400000000000000000000063031255003167400240730ustar00rootroot00000000000000/* actionvalidator.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "actionvalidator.h" #include using namespace GammaRay; uint qHash(const QKeySequence &sequence) { return qHash(sequence.toString(QKeySequence::PortableText)); } ActionValidator::ActionValidator(QObject *parent) : QObject(parent) { } QList ActionValidator::actions() const { return m_shortcutActionMap.values(); } QList ActionValidator::actions(const QKeySequence& sequence) const { return m_shortcutActionMap.values(sequence); } void ActionValidator::setActions(const QList& actions) { clearActions(); m_shortcutActionMap.reserve(actions.size()); Q_FOREACH (QAction *action, actions) { insert(action); } } void ActionValidator::clearActions() { m_shortcutActionMap.clear(); } void ActionValidator::insert(QAction *action) { Q_ASSERT(action); Q_FOREACH (const QKeySequence &sequence, action->shortcuts()) { if (m_shortcutActionMap.values(sequence).contains(action)) { continue; } m_shortcutActionMap.insertMulti(sequence, action); } // also track object destruction connect(action, SIGNAL(destroyed(QObject*)), SLOT(handleActionDestroyed(QObject*))); } void ActionValidator::remove(QAction *action) { Q_ASSERT(action); safeRemove(action); } void ActionValidator::safeRemove(QAction *action) { Q_FOREACH (const QKeySequence &sequence, m_shortcutActionMap.keys()) { if (!m_shortcutActionMap.values(sequence).contains(action)) { continue; } QList oldValues = m_shortcutActionMap.values(sequence); const bool success = oldValues.removeOne(action); Q_UNUSED(success); Q_ASSERT(success); m_shortcutActionMap[sequence] = action; } } void ActionValidator::handleActionDestroyed(QObject *object) { QAction *action = static_cast(object); safeRemove(action); } bool ActionValidator::hasAmbiguousShortcut(const QAction *action) const { if (!action) { return false; } Q_FOREACH (const QKeySequence &sequence, action->shortcuts()) { if (m_shortcutActionMap.values(sequence).size() > 1) { return true; } } return false; } gammaray-2.3.0/plugins/actioninspector/actionvalidator.h000066400000000000000000000041001255003167400235310ustar00rootroot00000000000000/* actionvalidator.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ACTIONINSPECTOR_ACTIONVALIDATOR_H #define GAMMARAY_ACTIONINSPECTOR_ACTIONVALIDATOR_H #include #include #include class QAction; namespace GammaRay { class ActionValidator : public QObject { Q_OBJECT public: explicit ActionValidator(QObject *parent = 0); QList actions() const; QList actions(const QKeySequence &sequence) const; void setActions(const QList &actions); void clearActions(); void insert(QAction *action); void remove(QAction *action); /// helper method to find out if action has an ambiguous shortcut bool hasAmbiguousShortcut(const QAction *action) const; private Q_SLOTS: void handleActionDestroyed(QObject *object); private: /// Does not deref the action pointer void safeRemove(QAction *action); // Multi-Map QHash m_shortcutActionMap; }; } #endif // GAMMARAY_ACTIONVALIDATOR_H gammaray-2.3.0/plugins/actioninspector/gammaray_actioninspector.desktop000066400000000000000000000002331255003167400266550ustar00rootroot00000000000000[Desktop Entry] Name=Action Inspector X-GammaRay-Types=QAction; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_actioninspector_plugin gammaray-2.3.0/plugins/actioninspector/gammaray_actioninspector.json000066400000000000000000000001341255003167400261550ustar00rootroot00000000000000{ "id": "gammaray_actioninspector", "name": "Actions", "types": [ "QAction" ] } gammaray-2.3.0/plugins/actioninspector/gammaray_actioninspector_ui.desktop000066400000000000000000000002271255003167400273550ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_actioninspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_actioninspector_ui_plugin gammaray-2.3.0/plugins/bluetooth/000077500000000000000000000000001255003167400170035ustar00rootroot00000000000000gammaray-2.3.0/plugins/bluetooth/CMakeLists.txt000066400000000000000000000002471255003167400215460ustar00rootroot00000000000000# probe plugin gammaray_add_plugin(gammaray_bluetooth gammaray_bluetooth.desktop bluetooth.cpp) target_link_libraries(gammaray_bluetooth gammaray_core Qt5::Bluetooth) gammaray-2.3.0/plugins/bluetooth/bluetooth.cpp000066400000000000000000000130441255003167400215160ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "bluetooth.h" #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QBluetooth::SecurityFlags) Q_DECLARE_METATYPE(QBluetoothDeviceDiscoveryAgent::Error) Q_DECLARE_METATYPE(QBluetoothDeviceDiscoveryAgent::InquiryType) Q_DECLARE_METATYPE(QBluetoothServer::Error) Q_DECLARE_METATYPE(QBluetoothServiceInfo::Protocol) #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) Q_DECLARE_METATYPE(QBluetoothServiceDiscoveryAgent::Error) Q_DECLARE_METATYPE(QBluetoothSocket::SocketError) Q_DECLARE_METATYPE(QBluetoothSocket::SocketState) #endif using namespace GammaRay; static QString bluetoothAddressToString(const QBluetoothAddress &addr) { return addr.toString(); } static QString bluetoothInquiryTypeToString(QBluetoothDeviceDiscoveryAgent::InquiryType type) { switch (type) { case QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry: return "Unlimited"; case QBluetoothDeviceDiscoveryAgent::LimitedInquiry: return "Limited"; } Q_UNREACHABLE(); return QString(); } Bluetooth::Bluetooth(ProbeInterface* probe, QObject* parent) : QObject(parent) { Q_UNUSED(probe); qRegisterMetaType(); MetaObject *mo = 0; MO_ADD_METAOBJECT1(QBluetoothDeviceDiscoveryAgent, QObject); MO_ADD_PROPERTY_RO(QBluetoothDeviceDiscoveryAgent, QBluetoothDeviceDiscoveryAgent::Error, error); MO_ADD_PROPERTY_RO(QBluetoothDeviceDiscoveryAgent, QString, errorString); MO_ADD_PROPERTY_RO(QBluetoothDeviceDiscoveryAgent, bool, isActive); MO_ADD_METAOBJECT1(QBluetoothLocalDevice, QObject); MO_ADD_PROPERTY_RO(QBluetoothLocalDevice, QBluetoothAddress, address); #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) MO_ADD_PROPERTY_RO(QBluetoothLocalDevice, QList, connectedDevices); #endif MO_ADD_PROPERTY (QBluetoothLocalDevice, QBluetoothLocalDevice::HostMode, hostMode, setHostMode); MO_ADD_PROPERTY_RO(QBluetoothLocalDevice, bool, isValid); MO_ADD_PROPERTY_RO(QBluetoothLocalDevice, QString, name); MO_ADD_METAOBJECT1(QBluetoothServer, QObject); MO_ADD_PROPERTY_RO(QBluetoothServer, QBluetoothServer::Error, error); MO_ADD_PROPERTY_RO(QBluetoothServer, bool, hasPendingConnections); MO_ADD_PROPERTY_RO(QBluetoothServer, bool, isListening); MO_ADD_PROPERTY (QBluetoothServer, int, maxPendingConnections, setMaxPendingConnections); MO_ADD_PROPERTY (QBluetoothServer, QBluetooth::SecurityFlags, securityFlags, setSecurityFlags); MO_ADD_PROPERTY_RO(QBluetoothServer, quint16, serverPort); MO_ADD_PROPERTY_RO(QBluetoothServer, QBluetoothServiceInfo::Protocol, serverType); MO_ADD_METAOBJECT1(QBluetoothServiceDiscoveryAgent, QObject); MO_ADD_PROPERTY_RO(QBluetoothServiceDiscoveryAgent, QBluetoothServiceDiscoveryAgent::Error, error); MO_ADD_PROPERTY_RO(QBluetoothServiceDiscoveryAgent, QString, errorString); MO_ADD_PROPERTY_RO(QBluetoothServiceDiscoveryAgent, bool, isActive); MO_ADD_PROPERTY_RO(QBluetoothServiceDiscoveryAgent, QBluetoothAddress, remoteAddress); MO_ADD_PROPERTY_CR(QBluetoothServiceDiscoveryAgent, QList, uuidFilter, setUuidFilter); MO_ADD_METAOBJECT1(QBluetoothSocket, QIODevice); MO_ADD_PROPERTY_RO(QBluetoothSocket, QBluetoothSocket::SocketError, error); MO_ADD_PROPERTY_RO(QBluetoothSocket, QString, errorString); MO_ADD_PROPERTY_RO(QBluetoothSocket, QBluetoothAddress, localAddress); MO_ADD_PROPERTY_RO(QBluetoothSocket, QString, localName); MO_ADD_PROPERTY_RO(QBluetoothSocket, quint16, localPort); MO_ADD_PROPERTY_RO(QBluetoothSocket, QBluetoothAddress, peerAddress); MO_ADD_PROPERTY_RO(QBluetoothSocket, QString, peerName); MO_ADD_PROPERTY_RO(QBluetoothSocket, quint16, peerPort); MO_ADD_PROPERTY_RO(QBluetoothSocket, int, socketDescriptor); MO_ADD_PROPERTY_RO(QBluetoothSocket, QBluetoothServiceInfo::Protocol, socketType); MO_ADD_PROPERTY_RO(QBluetoothSocket, QBluetoothSocket::SocketState, state); VariantHandler::registerStringConverter(bluetoothAddressToString); VariantHandler::registerStringConverter(bluetoothInquiryTypeToString); } QString BluetoothFactory::name() const { return tr("Bluetooth"); } gammaray-2.3.0/plugins/bluetooth/bluetooth.h000066400000000000000000000033161255003167400211640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_BLUETOOTH_BLUETOOTH_H #define GAMMARAY_BLUETOOTH_BLUETOOTH_H #include namespace GammaRay { class Bluetooth : public QObject { Q_OBJECT public: explicit Bluetooth(ProbeInterface *probe, QObject *parent = 0); }; class BluetoothFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_bluetooth.json") public: explicit BluetoothFactory(QObject *parent = 0) : QObject(parent) { } QString name() const Q_DECL_OVERRIDE; }; } #endif gammaray-2.3.0/plugins/bluetooth/gammaray_bluetooth.desktop000066400000000000000000000003611255003167400242610ustar00rootroot00000000000000[Desktop Entry] Name=Bluetooth X-GammaRay-Types=QBluetoothDeviceDiscoveryAgent;QBluetoothLocalDevice;QBluetoothServiceDiscoveryAgent;QBluetoothSocket; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_bluetooth Hidden=true gammaray-2.3.0/plugins/bluetooth/gammaray_bluetooth.json000066400000000000000000000003231255003167400235570ustar00rootroot00000000000000{ "id": "gammaray_bluetooth", "name": "Bluetooth", "types": [ "QBluetoothDeviceDiscoveryAgent", "QBluetoothLocalDevice", "QBluetoothServiceDiscoveryAgent", "QBluetoothSocket" ], "hidden": true } gammaray-2.3.0/plugins/codecbrowser/000077500000000000000000000000001255003167400174575ustar00rootroot00000000000000gammaray-2.3.0/plugins/codecbrowser/CMakeLists.txt000066400000000000000000000014341255003167400222210ustar00rootroot00000000000000# probe part set(gammaray_codecbrowser_plugin_srcs codecbrowser.cpp codecmodel.cpp ) gammaray_add_plugin(gammaray_codecbrowser_plugin gammaray_codecbrowser.desktop ${gammaray_codecbrowser_plugin_srcs} ) target_link_libraries(gammaray_codecbrowser_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) # ui part if(GAMMARAY_BUILD_UI) set(gammaray_codecbrowser_plugin_ui_srcs codecbrowserwidget.cpp ) qt4_wrap_ui(gammaray_codecbrowser_plugin_ui_srcs codecbrowserwidget.ui ) gammaray_add_plugin(gammaray_codecbrowser_ui_plugin gammaray_codecbrowser_ui.desktop ${gammaray_codecbrowser_plugin_ui_srcs} ) target_link_libraries(gammaray_codecbrowser_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common gammaray_ui ) endif() gammaray-2.3.0/plugins/codecbrowser/codecbrowser.cpp000066400000000000000000000051371255003167400226520ustar00rootroot00000000000000/* codecbrowser.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "codecbrowser.h" #include "codecmodel.h" #include #include #include using namespace GammaRay; CodecBrowser::CodecBrowser(ProbeInterface* probe, QObject* parent) : QObject(parent) { ObjectBroker::registerObject("com.kdab.GammaRay.CodecBrowser", this); AllCodecsModel* model = new AllCodecsModel(this); probe->registerModel("com.kdab.GammaRay.AllCodecsModel", model); m_codecSelectionModel = ObjectBroker::selectionModel(model); connect(m_codecSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateCodecs(QItemSelection,QItemSelection))); m_selectedCodecsModel = new SelectedCodecsModel(this); probe->registerModel("com.kdab.GammaRay.SelectedCodecsModel", m_selectedCodecsModel); } void CodecBrowser::textChanged(const QString &text) { m_selectedCodecsModel->updateText(text); } void CodecBrowser::updateCodecs(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(selected); Q_UNUSED(deselected); const auto rows = m_codecSelectionModel->selectedRows(); QStringList currentCodecNames; currentCodecNames.reserve(rows.size()); foreach (const QModelIndex &index, rows) { const QString codecName = index.data().toString(); currentCodecNames.append(codecName); } m_selectedCodecsModel->setCodecs(currentCodecNames); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(CodecBrowserFactory) #endif gammaray-2.3.0/plugins/codecbrowser/codecbrowser.h000066400000000000000000000043311255003167400223120ustar00rootroot00000000000000/* codecbrowser.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CODECBROWSER_CODECBROWSER_H #define GAMMARAY_CODECBROWSER_CODECBROWSER_H #include class QItemSelection; class QItemSelectionModel; namespace GammaRay { class SelectedCodecsModel; namespace Ui { class CodecBrowser; } class CodecBrowser : public QObject { Q_OBJECT public: explicit CodecBrowser(ProbeInterface *probe, QObject *parent = 0); public slots: void textChanged(const QString &text); private slots: void updateCodecs(const QItemSelection &selected, const QItemSelection &deselected); private: SelectedCodecsModel *m_selectedCodecsModel; QItemSelectionModel *m_codecSelectionModel; }; class CodecBrowserFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_codecbrowser.json") public: explicit CodecBrowserFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Text Codecs"); } }; } #endif // GAMMARAY_CODECBROWSER_H gammaray-2.3.0/plugins/codecbrowser/codecbrowserwidget.cpp000066400000000000000000000047051255003167400240560ustar00rootroot00000000000000/* codecbrowserwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "codecbrowserwidget.h" #include "ui_codecbrowserwidget.h" #include #include #include using namespace GammaRay; CodecBrowserWidget::CodecBrowserWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CodecBrowserWidget) { ui->setupUi(this); ui->codecList->setRootIsDecorated(false); ui->codecList->setModel(ObjectBroker::model("com.kdab.GammaRay.AllCodecsModel")); ui->codecList->setSelectionModel(ObjectBroker::selectionModel(ui->codecList->model())); ui->codecList->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->selectedCodecs->setRootIsDecorated(false); ui->selectedCodecs->setModel(ObjectBroker::model("com.kdab.GammaRay.SelectedCodecsModel")); new DeferredResizeModeSetter(ui->codecList->header(), 0, QHeaderView::ResizeToContents); new DeferredResizeModeSetter(ui->selectedCodecs->header(), 0, QHeaderView::ResizeToContents); connect(ui->codecText, SIGNAL(textChanged(QString)), SLOT(textChanged(QString))); } CodecBrowserWidget::~CodecBrowserWidget() { } void CodecBrowserWidget::textChanged(const QString& text) { Endpoint::instance()->invokeObject("com.kdab.GammaRay.CodecBrowser", "textChanged", QVariantList() << text); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(CodecBrowserUiFactory) #endif gammaray-2.3.0/plugins/codecbrowser/codecbrowserwidget.h000066400000000000000000000036201255003167400235160ustar00rootroot00000000000000/* codecbrowserwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CODECBROWSERWIDGET_CODECBROWSERWIDGET_H #define GAMMARAY_CODECBROWSERWIDGET_CODECBROWSERWIDGET_H #include #include namespace GammaRay { namespace Ui { class CodecBrowserWidget; } class CodecBrowserWidget : public QWidget { Q_OBJECT public: explicit CodecBrowserWidget(QWidget *parent = 0); ~CodecBrowserWidget(); private slots: void textChanged(const QString &text); private: QScopedPointer ui; }; class CodecBrowserUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_codecbrowser.json") }; } #endif // GAMMARAY_CODECBROWSERWIDGET_H gammaray-2.3.0/plugins/codecbrowser/codecbrowserwidget.ui000066400000000000000000000022051255003167400237020ustar00rootroot00000000000000 GammaRay::CodecBrowserWidget 0 0 400 300 Qt::Horizontal Enter text for preview... gammaray-2.3.0/plugins/codecbrowser/codecmodel.cpp000066400000000000000000000113111255003167400222560ustar00rootroot00000000000000/* codecmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "codecmodel.h" #include using namespace GammaRay; AllCodecsModel::AllCodecsModel(QObject *parent) : QAbstractItemModel(parent) { } int AllCodecsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } QVariant AllCodecsModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return QTextCodec::availableCodecs().at(index.row()); } if (index.column() == 1) { QList aliases = QTextCodec::codecForName(QTextCodec::availableCodecs().at(index.row()))->aliases(); QString result; int size = aliases.size(); int i = 0; foreach (const QByteArray &ba, aliases) { result.append(ba); ++i; if (i != size) { result.append(", "); } } return result; } } return QVariant(); } QVariant AllCodecsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return "Codec"; } else if (section == 1) { return "Aliases"; } } return QVariant(); } QModelIndex AllCodecsModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) { return QModelIndex(); } if (!hasIndex(row, column, parent)) { return QModelIndex(); } return createIndex(row, column); } QModelIndex AllCodecsModel::parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); } int AllCodecsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return QTextCodec::availableCodecs().size(); } SelectedCodecsModel::SelectedCodecsModel(QObject *parent) : QAbstractItemModel(parent) { } void SelectedCodecsModel::setCodecs(const QStringList &codecs) { beginResetModel(); m_codecs = codecs; endResetModel(); } QStringList SelectedCodecsModel::currentCodecs() const { return m_codecs; } void SelectedCodecsModel::updateText(const QString &text) { m_text = text; if (!m_codecs.isEmpty()) { emit dataChanged(index(0, 1), index(m_codecs.size() - 1, 1)); } } QVariant SelectedCodecsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return "Codec"; } if (section == 1) { return "Data"; } } return QAbstractItemModel::headerData(section, orientation, role); } int SelectedCodecsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_codecs.size(); } QModelIndex SelectedCodecsModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) { return QModelIndex(); } if (!hasIndex(row, column, parent)) { return QModelIndex(); } return createIndex(row, column); } QModelIndex SelectedCodecsModel::parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); } int SelectedCodecsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } QVariant SelectedCodecsModel::data(const QModelIndex &index, int role) const { if (index.column() == 0) { if (role == Qt::DisplayRole) { return m_codecs.at(index.row()); } } else if (index.column() == 1) { if (role == Qt::DisplayRole) { const QByteArray ba = QTextCodec::codecForName(m_codecs.at(index.row()).toLatin1())->fromUnicode(m_text); // QString result; // foreach () return ba.toHex(); } } return QVariant(); } gammaray-2.3.0/plugins/codecbrowser/codecmodel.h000066400000000000000000000057531255003167400217400ustar00rootroot00000000000000/* codecmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CODECBROWSER_CODECMODEL_H #define GAMMARAY_CODECBROWSER_CODECMODEL_H #include #include #include namespace GammaRay { class AllCodecsModel : public QAbstractItemModel { Q_OBJECT public: explicit AllCodecsModel(QObject *parent); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; }; class SelectedCodecsModel : public QAbstractItemModel { Q_OBJECT public: explicit SelectedCodecsModel(QObject *parent); void setCodecs(const QStringList &codecs); QStringList currentCodecs() const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; public slots: void updateText(const QString &text); private: QStringList m_codecs; QString m_text; }; } #endif gammaray-2.3.0/plugins/codecbrowser/gammaray_codecbrowser.desktop000066400000000000000000000002231255003167400254060ustar00rootroot00000000000000[Desktop Entry] Name=Text Codecs X-GammaRay-Types=QObject; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_codecbrowser_plugin gammaray-2.3.0/plugins/codecbrowser/gammaray_codecbrowser.json000066400000000000000000000001351255003167400247100ustar00rootroot00000000000000{ "id": "gammaray_codecbrowser", "name": "Text Codecs", "types": [ "QObject" ] } gammaray-2.3.0/plugins/codecbrowser/gammaray_codecbrowser_ui.desktop000066400000000000000000000002211255003167400261010ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_codecbrowser X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_codecbrowser_ui_plugin gammaray-2.3.0/plugins/fontbrowser/000077500000000000000000000000001255003167400173505ustar00rootroot00000000000000gammaray-2.3.0/plugins/fontbrowser/CMakeLists.txt000066400000000000000000000020051255003167400221050ustar00rootroot00000000000000# probe part set(gammaray_fontbrowser_plugin_srcs fontbrowserinterface.cpp fontbrowser.cpp fontmodel.cpp fontbrowserserver.cpp ) gammaray_add_plugin(gammaray_fontbrowser_plugin gammaray_fontbrowser.desktop ${gammaray_fontbrowser_plugin_srcs} ) target_link_libraries(gammaray_fontbrowser_plugin gammaray_core) if(Qt5Core_FOUND) target_link_libraries(gammaray_fontbrowser_plugin Qt5::Gui) else() target_link_libraries(gammaray_fontbrowser_plugin ${QT_QTGUI_LIBRARIES}) endif() # ui part if(GAMMARAY_BUILD_UI) set(gammaray_fontbrowser_plugin_ui_srcs fontbrowserinterface.cpp fontbrowserwidget.cpp fontbrowserclient.cpp ) qt4_wrap_ui(gammaray_fontbrowser_plugin_ui_srcs fontbrowserwidget.ui ) gammaray_add_plugin(gammaray_fontbrowser_ui_plugin gammaray_fontbrowser_ui.desktop ${gammaray_fontbrowser_plugin_ui_srcs} ) target_link_libraries(gammaray_fontbrowser_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common gammaray_ui ) endif() gammaray-2.3.0/plugins/fontbrowser/fontbrowser.cpp000066400000000000000000000025021255003167400224250ustar00rootroot00000000000000/* fontbrowser.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontbrowser.h" #include using namespace GammaRay; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(FontBrowserFactory) #endif gammaray-2.3.0/plugins/fontbrowser/fontbrowser.h000066400000000000000000000041421255003167400220740ustar00rootroot00000000000000/* fontbrowser.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTBROWSER_H #define GAMMARAY_FONTBROWSER_FONTBROWSER_H #include #include "fontbrowserserver.h" #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #else #include #endif namespace GammaRay { class FontBrowserFactory : public QObject #ifndef Q_MOC_RUN // Qt4 moc fails on the ifdef'ed multi-inheritance and generates invalid code #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) , public StandardToolFactory #else , public StandardToolFactory #endif #endif { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_fontbrowser.json") public: explicit FontBrowserFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Fonts"); } }; } #endif // GAMMARAY_FONTBROWSER_H gammaray-2.3.0/plugins/fontbrowser/fontbrowserclient.cpp000066400000000000000000000035421255003167400236310ustar00rootroot00000000000000/* fontbrowserclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontbrowserclient.h" #include #include using namespace GammaRay; FontBrowserClient::FontBrowserClient(QObject *parent) : FontBrowserInterface(parent) { } #define WRAP_REMOTE(func, type) \ void FontBrowserClient::func(type arg) \ { \ Endpoint::instance()->invokeObject(objectName(), #func, QVariantList() << arg); \ } WRAP_REMOTE(setPointSize, int) WRAP_REMOTE(toggleBoldFont, bool) WRAP_REMOTE(toggleItalicFont, bool) WRAP_REMOTE(toggleUnderlineFont, bool) WRAP_REMOTE(updateText, const QString&) void FontBrowserClient::setColors(const QColor &foreground, const QColor &background) { Endpoint::instance()->invokeObject(objectName(), "setColors", QVariantList() << foreground << background); } gammaray-2.3.0/plugins/fontbrowser/fontbrowserclient.h000066400000000000000000000035561255003167400233030ustar00rootroot00000000000000/* fontbrowserclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTBROWSERCLIENT_H #define GAMMARAY_FONTBROWSER_FONTBROWSERCLIENT_H #include "fontbrowserinterface.h" namespace GammaRay { class FontBrowserClient : public FontBrowserInterface { Q_OBJECT Q_INTERFACES(GammaRay::FontBrowserInterface) public: explicit FontBrowserClient(QObject *parent = 0); public slots: void setPointSize(int size) Q_DECL_OVERRIDE; void toggleBoldFont(bool bold) Q_DECL_OVERRIDE; void toggleItalicFont(bool italic) Q_DECL_OVERRIDE; void toggleUnderlineFont(bool underline) Q_DECL_OVERRIDE; void updateText(const QString &text) Q_DECL_OVERRIDE; void setColors(const QColor &foreground, const QColor &background) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_FONTBROWSERCLIENT_H gammaray-2.3.0/plugins/fontbrowser/fontbrowserinterface.cpp000066400000000000000000000026371255003167400243170ustar00rootroot00000000000000/* fontbrowserinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontbrowserinterface.h" #include using namespace GammaRay; FontBrowserInterface::FontBrowserInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } FontBrowserInterface::~FontBrowserInterface() { } gammaray-2.3.0/plugins/fontbrowser/fontbrowserinterface.h000066400000000000000000000036321255003167400237600ustar00rootroot00000000000000/* fontbrowserinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTBROWSERINTERFACE_H #define GAMMARAY_FONTBROWSER_FONTBROWSERINTERFACE_H #include class QColor; namespace GammaRay { class FontBrowserInterface : public QObject { Q_OBJECT public: explicit FontBrowserInterface(QObject *parent); virtual ~FontBrowserInterface(); public slots: virtual void updateText(const QString &text) = 0; virtual void toggleBoldFont(bool bold) = 0; virtual void toggleItalicFont(bool italic) = 0; virtual void toggleUnderlineFont(bool underline) = 0; virtual void setPointSize(int size) = 0; virtual void setColors(const QColor &foreground, const QColor &background) = 0; }; } Q_DECLARE_INTERFACE(GammaRay::FontBrowserInterface, "com.kdab.GammaRay.FontBrowser") #endif // FONTBROWSERINTERFACE_H gammaray-2.3.0/plugins/fontbrowser/fontbrowserserver.cpp000066400000000000000000000076621255003167400236700ustar00rootroot00000000000000/* fontbrowserserver.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontbrowserserver.h" #include "fontmodel.h" #include #include #include #include #include using namespace GammaRay; FontBrowserServer::FontBrowserServer(ProbeInterface *probe, QObject *parent) : FontBrowserInterface(parent) , m_selectedFontModel(new FontModel(this)) { QStandardItemModel *model = new QStandardItemModel(this); model->setHorizontalHeaderLabels(QStringList() << tr("Fonts") << tr("Smooth sizes")); QFontDatabase database; foreach (const QString &family, database.families()) { QStandardItem *familyItem = new QStandardItem; familyItem->setText(family); familyItem->setEditable(false); familyItem->setData(QFont(family)); foreach (const QString &style, database.styles(family)) { QStandardItem *styleItem0 = new QStandardItem; styleItem0->setText(style); styleItem0->setEditable(false); styleItem0->setData(database.font(family, style, 10)); QString sizes; foreach (int points, database.smoothSizes(family, style)) { sizes += QString::number(points) + ' '; } QStandardItem *styleItem1 = new QStandardItem; styleItem1->setText(sizes.trimmed()); styleItem1->setEditable(false); styleItem1->setToolTip(sizes.trimmed()); familyItem->appendRow(QList() << styleItem0 << styleItem1); } model->appendRow(familyItem); } probe->registerModel("com.kdab.GammaRay.FontModel", model); m_fontSelectionModel = ObjectBroker::selectionModel(model); connect(m_fontSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateFonts())); probe->registerModel("com.kdab.GammaRay.SelectedFontModel", m_selectedFontModel); } void FontBrowserServer::updateFonts() { const auto rows = m_fontSelectionModel->selectedRows(); QList currentFonts; currentFonts.reserve(rows.size()); foreach (const QModelIndex &index, rows) { currentFonts << index.data(Qt::UserRole + 1).value(); } m_selectedFontModel->updateFonts(currentFonts); } void FontBrowserServer::setPointSize(int size) { m_selectedFontModel->setPointSize(size); } void FontBrowserServer::toggleBoldFont(bool bold) { m_selectedFontModel->toggleBoldFont(bold); } void FontBrowserServer::toggleItalicFont(bool italic) { m_selectedFontModel->toggleItalicFont(italic); } void FontBrowserServer::toggleUnderlineFont(bool underline) { m_selectedFontModel->toggleUnderlineFont(underline); } void FontBrowserServer::updateText(const QString &text) { m_selectedFontModel->updateText(text); } void FontBrowserServer::setColors(const QColor &foreground, const QColor &background) { m_selectedFontModel->setColors(foreground, background); } gammaray-2.3.0/plugins/fontbrowser/fontbrowserserver.h000066400000000000000000000041521255003167400233240ustar00rootroot00000000000000/* fontbrowserserver.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTBROWSERSERVER_H #define GAMMARAY_FONTBROWSER_FONTBROWSERSERVER_H #include "fontbrowserinterface.h" class QItemSelectionModel; namespace GammaRay { class ProbeInterface; class FontModel; class FontBrowserServer : public FontBrowserInterface { Q_OBJECT Q_INTERFACES(GammaRay::FontBrowserInterface) public: explicit FontBrowserServer(ProbeInterface *probe, QObject *parent = 0); private slots: void updateFonts(); void setPointSize(int size) Q_DECL_OVERRIDE; void toggleBoldFont(bool bold) Q_DECL_OVERRIDE; void toggleItalicFont(bool italic) Q_DECL_OVERRIDE; void toggleUnderlineFont(bool underline) Q_DECL_OVERRIDE; void updateText(const QString &text) Q_DECL_OVERRIDE; void setColors(const QColor &foreground, const QColor &background) Q_DECL_OVERRIDE; private: FontModel *m_selectedFontModel; QItemSelectionModel *m_fontSelectionModel; }; } #endif // FONTBROWSERSERVER_H gammaray-2.3.0/plugins/fontbrowser/fontbrowserwidget.cpp000066400000000000000000000073341255003167400236410ustar00rootroot00000000000000/* fontbrowserwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontbrowserwidget.h" #include "ui_fontbrowserwidget.h" #include "fontbrowserclient.h" #include #include #include #include using namespace GammaRay; static QObject* fontBrowserClientFactory(const QString &/*name*/, QObject *parent) { return new FontBrowserClient(parent); } FontBrowserWidget::FontBrowserWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::FontBrowserWidget) , m_selectedFontModel(0) , m_fontBrowser(0) { ObjectBroker::registerClientObjectFactoryCallback(fontBrowserClientFactory); m_fontBrowser = ObjectBroker::object(); ui->setupUi(this); m_selectedFontModel = ObjectBroker::model("com.kdab.GammaRay.SelectedFontModel"); ui->selectedFontsView->setModel(m_selectedFontModel); ui->selectedFontsView->setRootIsDecorated(false); new DeferredResizeModeSetter(ui->selectedFontsView->header(), 0, QHeaderView::ResizeToContents); connect(ui->fontText, SIGNAL(textChanged(QString)), m_fontBrowser, SLOT(updateText(QString))); connect(ui->boldBox, SIGNAL(toggled(bool)), m_fontBrowser, SLOT(toggleBoldFont(bool))); connect(ui->italicBox, SIGNAL(toggled(bool)), m_fontBrowser, SLOT(toggleItalicFont(bool))); connect(ui->underlineBox, SIGNAL(toggled(bool)), m_fontBrowser, SLOT(toggleUnderlineFont(bool))); connect(ui->pointSize, SIGNAL(valueChanged(int)), m_fontBrowser, SLOT(setPointSize(int))); QAbstractItemModel *fontModel = ObjectBroker::model("com.kdab.GammaRay.FontModel"); ui->fontTree->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->fontTree->setModel(fontModel); ui->fontTree->setSelectionModel(ObjectBroker::selectionModel(fontModel)); new DeferredResizeModeSetter(ui->fontTree->header(), 0, QHeaderView::ResizeToContents); ui->pointSize->setValue(font().pointSize()); // init m_fontBrowser->updateText(ui->fontText->text()); m_fontBrowser->toggleBoldFont(ui->boldBox->isChecked()); m_fontBrowser->toggleItalicFont(ui->italicBox->isChecked()); m_fontBrowser->toggleUnderlineFont(ui->underlineBox->isChecked()); m_fontBrowser->setPointSize(ui->pointSize->value()); QMetaObject::invokeMethod(this, "delayedInit", Qt::QueuedConnection); } FontBrowserWidget::~FontBrowserWidget() { } void FontBrowserWidget::delayedInit() { m_fontBrowser->setColors(palette().color(QPalette::Foreground), palette().color(QPalette::Base)); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(FontBrowserUiFactory) #endif gammaray-2.3.0/plugins/fontbrowser/fontbrowserwidget.h000066400000000000000000000040671255003167400233060ustar00rootroot00000000000000/* fontbrowserwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTBROWSERWIDGET_H #define GAMMARAY_FONTBROWSER_FONTBROWSERWIDGET_H #include #include class QAbstractItemModel; class QItemSelection; namespace GammaRay { class FontBrowserInterface; namespace Ui { class FontBrowserWidget; } class FontBrowserWidget : public QWidget { Q_OBJECT public: explicit FontBrowserWidget(QWidget *parent = 0); ~FontBrowserWidget(); private slots: void delayedInit(); private: QScopedPointer ui; QAbstractItemModel *m_selectedFontModel; FontBrowserInterface *m_fontBrowser; }; class FontBrowserUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_fontbrowser.json") }; } #endif // GAMMARAY_FONTBROWSERWIDGET_H gammaray-2.3.0/plugins/fontbrowser/fontbrowserwidget.ui000066400000000000000000000055111255003167400234670ustar00rootroot00000000000000 GammaRay::FontBrowserWidget 0 0 742 300 Qt::Horizontal true The quick brown fox jumps over the lazy dog Enter some text here... 0 Point Size: Bold Italic Underline Qt::Horizontal 40 20 gammaray-2.3.0/plugins/fontbrowser/fontmodel.cpp000066400000000000000000000122021255003167400220400ustar00rootroot00000000000000/* fontmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "fontmodel.h" #include #include #include using namespace GammaRay; FontModel::FontModel(QObject *parent) : QAbstractItemModel(parent) , m_size(12) , m_bold(false) , m_italic(false) , m_underline(false) { } QList FontModel::currentFonts() const { return m_fonts; } void FontModel::updateFonts(const QList &fonts) { for (int i = 0; i < m_fonts.size(); ++i) { QFont &font = m_fonts[i]; font.setPointSize(m_size); font.setBold(m_bold); font.setItalic(m_italic); font.setUnderline(m_underline); } beginResetModel(); m_fonts = fonts; endResetModel(); } void FontModel::updateText(const QString &text) { if (text == m_text) { return; } beginResetModel(); m_text = text; endResetModel(); } QVariant FontModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return "Font Family"; } else if (section == 1) { return "Style Name"; } else if (section == 2) { return "Text Preview"; } } return QAbstractItemModel::headerData(section, orientation, role); } int FontModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_fonts.size(); } QModelIndex FontModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) { return QModelIndex(); } if (!hasIndex(row, column, parent)) { return QModelIndex(); } return createIndex(row, column); } QModelIndex FontModel::parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); } int FontModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } QVariant FontModel::data(const QModelIndex &index, int role) const { if (index.column() == 0) { if (role == Qt::DisplayRole) { return m_fonts.at(index.row()).family(); } } else if (index.column() == 1) { if (role == Qt::DisplayRole) { #if QT_VERSION >= 0x040800 return m_fonts.at(index.row()).styleName(); #else return tr("N/A"); #endif } } else if (index.column() == 2) { if (role == Qt::DecorationRole || role == Qt::SizeHintRole) { const QFont &font = m_fonts.at(index.row()); QFontMetrics metrics(font); const QString text = m_text.isEmpty() ? tr("") : m_text; const QRect rect = metrics.boundingRect(text.left(100)); if (role == Qt::SizeHintRole) { return rect.size(); } QPixmap pixmap(rect.size()); pixmap.fill(m_background); QPainter painter(&pixmap); painter.setPen(m_foreground); painter.setFont(font); painter.drawText(0, -rect.y(), text); return pixmap; } } return QVariant(); } void FontModel::setPointSize(int size) { if (size == m_size) { return; } m_size = size; for (int i = 0; i < m_fonts.size(); ++i) { m_fonts[i].setPointSize(size); } fontDataChanged(); } void FontModel::toggleItalicFont(bool italic) { if (italic == m_italic) { return; } m_italic = italic; for (int i = 0; i < m_fonts.size(); ++i) { m_fonts[i].setItalic(italic); } fontDataChanged(); } void FontModel::toggleUnderlineFont(bool underline) { if (underline == m_underline) { return; } m_underline = underline; for (int i = 0; i < m_fonts.size(); ++i) { m_fonts[i].setUnderline(underline); } fontDataChanged(); } void FontModel::toggleBoldFont(bool bold) { if (bold == m_bold) { return; } m_bold = bold; for (int i = 0; i < m_fonts.size(); ++i) { m_fonts[i].setBold(bold); } fontDataChanged(); } void FontModel::setColors(const QColor &foreground, const QColor &background) { if (foreground == m_foreground && background == m_background) { return; } m_foreground = foreground; m_background = background; fontDataChanged(); } void FontModel::fontDataChanged() { if (m_fonts.isEmpty()) { return; } emit dataChanged(index(0, 2), index(rowCount() - 1, 2)); } gammaray-2.3.0/plugins/fontbrowser/fontmodel.h000066400000000000000000000051251255003167400215130ustar00rootroot00000000000000/* fontmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_FONTBROWSER_FONTMODEL_H #define GAMMARAY_FONTBROWSER_FONTMODEL_H #include #include #include namespace GammaRay { class FontModel : public QAbstractItemModel { Q_OBJECT public: explicit FontModel(QObject *parent); void updateFonts(const QList &fonts); QList currentFonts() const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; public slots: void updateText(const QString &text); void toggleBoldFont(bool bold); void toggleItalicFont(bool italic); void toggleUnderlineFont(bool underline); void setPointSize(int size); void setColors(const QColor &foreground, const QColor &background); private: void fontDataChanged(); QList m_fonts; QString m_text; int m_size; bool m_bold; bool m_italic; bool m_underline; QColor m_foreground; QColor m_background; }; } #endif gammaray-2.3.0/plugins/fontbrowser/gammaray_fontbrowser.desktop000066400000000000000000000002521255003167400251720ustar00rootroot00000000000000[Desktop Entry] Name=Font Browser X-GammaRay-Types="QGuiApplication;QApplication;" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_fontbrowser_plugin gammaray-2.3.0/plugins/fontbrowser/gammaray_fontbrowser.json000066400000000000000000000001651255003167400244750ustar00rootroot00000000000000{ "id": "gammaray_fontbrowser", "name": "Font Browser", "types": [ "QGuiApplication", "QApplication" ] } gammaray-2.3.0/plugins/fontbrowser/gammaray_fontbrowser_ui.desktop000066400000000000000000000002171255003167400256700ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_fontbrowser X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_fontbrowser_ui_plugin gammaray-2.3.0/plugins/kjobtracker/000077500000000000000000000000001255003167400172775ustar00rootroot00000000000000gammaray-2.3.0/plugins/kjobtracker/CMakeLists.txt000066400000000000000000000032261255003167400220420ustar00rootroot00000000000000if(Qt5Core_FOUND) find_package(KF5CoreAddons NO_MODULE QUIET) set_package_properties(KF5CoreAddons PROPERTIES TYPE OPTIONAL DESCRIPTION "KDE KCoreAddons Framework" URL "http://www.kde.org/" PURPOSE "Required for the KJob tracker plug-in." ) else() # ugly workaround for FindKDE4Internal messing with the install rpath (https://github.com/KDAB/GammaRay/issues/36) set(_old_CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}) find_package(KDE4) set(CMAKE_INSTALL_RPATH ${_old_CMAKE_INSTALL_RPATH}) set_package_properties(KDE4 PROPERTIES TYPE OPTIONAL DESCRIPTION "KDE libraries" URL "http://www.kde.org/" PURPOSE "Required for the KJob tracker plug-in." ) endif() # probe part if(KDE4_FOUND OR KF5CoreAddons_FOUND) include_directories(${KDE4_INCLUDES}) add_definitions(${KDE4_DEFINITIONS}) set(gammaray_kjob_plugin_srcs kjobmodel.cpp kjobtracker.cpp ) gammaray_add_plugin(gammaray_kjobtracker_plugin gammaray_kjobtracker.desktop ${gammaray_kjob_plugin_srcs} ) if(KDE4_FOUND) target_link_libraries(gammaray_kjobtracker_plugin ${KDE4_KDECORE_LIBS} gammaray_core ) else() target_link_libraries(gammaray_kjobtracker_plugin gammaray_core KF5::CoreAddons Qt5::Gui ) endif() endif() # ui part if(GAMMARAY_BUILD_UI) set(gammaray_kjob_ui_plugin_srcs kjobtrackerwidget.cpp ) qt4_wrap_ui(gammaray_kjob_ui_plugin_srcs kjobtrackerwidget.ui ) gammaray_add_plugin(gammaray_kjobtracker_ui_plugin gammaray_kjobtracker_ui.desktop ${gammaray_kjob_ui_plugin_srcs} ) target_link_libraries(gammaray_kjobtracker_ui_plugin gammaray_ui ) endif() gammaray-2.3.0/plugins/kjobtracker/gammaray_kjobtracker.desktop000066400000000000000000000002111255003167400250430ustar00rootroot00000000000000[Desktop Entry] Name=KJobs X-GammaRay-Types=KJob; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_kjobtracker_plugin gammaray-2.3.0/plugins/kjobtracker/gammaray_kjobtracker.json000066400000000000000000000001231255003167400243450ustar00rootroot00000000000000{ "id": "gammaray_kjobtracker", "name": "KJobs", "types": [ "KJob" ] } gammaray-2.3.0/plugins/kjobtracker/gammaray_kjobtracker_ui.desktop000066400000000000000000000002171255003167400255460ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_kjobtracker X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_kjobtracker_ui_plugin gammaray-2.3.0/plugins/kjobtracker/kjobmodel.cpp000066400000000000000000000127741255003167400217640ustar00rootroot00000000000000/* kjobmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "kjobmodel.h" #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #else #include #endif #include using namespace GammaRay; /* * TODO * - show job hierarchy * - show all job info messages * - show progress information * - allow to cancel/suspend if job supports that * - track runtime * - allow to clear the model * - tooltips with additional information (capabilities etc) */ KJobModel::KJobModel(QObject *parent) : QAbstractTableModel(parent) { } QVariant KJobModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const KJobInfo &job = m_data.at(index.row()); if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return job.name; case 1: return job.type; case 2: return job.statusText; } } else if (role == Qt::ForegroundRole) { switch (job.state) { case KJobInfo::Finished: case KJobInfo::Deleted: return qApp->palette().brush(QPalette::Disabled, QPalette::Foreground); case KJobInfo::Error: return QVariant::fromValue(Qt::red); case KJobInfo::Killed: return qApp->palette().link(); default: return QVariant(); } } return QVariant(); } int KJobModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } int KJobModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_data.size(); } QVariant KJobModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Job"); case 1: return tr("Type"); case 2: return tr("Status"); } } return QAbstractItemModel::headerData(section, orientation, role); } void KJobModel::objectAdded(QObject *obj) { KJob *job = qobject_cast(obj); if (!job) { return; } beginInsertRows(QModelIndex(), rowCount(), rowCount()); KJobInfo jobInfo; jobInfo.job = job; connect(job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*))); connect(job, SIGNAL(finished(KJob*)), SLOT(jobFinished(KJob*))); connect(job, SIGNAL(infoMessage(KJob*,QString,QString)), SLOT(jobInfo(KJob*,QString))); jobInfo.name = obj->objectName().isEmpty() ? Util::addressToString(obj) : obj->objectName(); jobInfo.type = obj->metaObject()->className(); jobInfo.state = KJobInfo::Running; m_data.push_back(jobInfo); endInsertRows(); } void KJobModel::objectRemoved(QObject *obj) { const int pos = indexOfJob(obj); if (pos < 0) { return; } // KJob dtor emits finished, so this shouldn't happen, in theory // We however seem to get here for very short-lived jobs that emit before objectAdded() // is called (while we wait for the vtable to be complete), so we only see the result // of their deleteLater(). if (m_data[pos].state == KJobInfo::Running) { m_data[pos].state = KJobInfo::Deleted; m_data[pos].statusText = tr("Deleted"); emit dataChanged(index(pos, 0), index(pos, columnCount() - 1)); } } void KJobModel::jobResult(KJob *job) { const int pos = indexOfJob(job); if (pos < 0) { return; } if (job->error()) { m_data[pos].state = KJobInfo::Error; m_data[pos].statusText = job->errorString(); } else { if (m_data.at(pos).state == KJobInfo::Killed) { // we can get finished() before result(), which is perfectly fine m_data[pos].statusText.clear(); } m_data[pos].state = KJobInfo::Finished; } emit dataChanged(index(pos, 0), index(pos, columnCount()-1)); } void KJobModel::jobFinished(KJob *obj) { const int pos = indexOfJob(obj); if (pos < 0) { return; } if (m_data.at(pos).state == KJobInfo::Running) { m_data[pos].state = KJobInfo::Killed; m_data[pos].statusText = tr("Killed"); } emit dataChanged(index(pos, 0), index(pos, columnCount()-1)); } void KJobModel::jobInfo(KJob *job, const QString &plainMessage) { const int pos = indexOfJob(job); if (pos < 0) { return; } if (m_data.at(pos).state == KJobInfo::Running) { m_data[pos].statusText = plainMessage; } emit dataChanged(index(pos, 0), index(pos, columnCount()-1)); } int KJobModel::indexOfJob(QObject *obj) const { for (int i = 0; i < m_data.size(); ++i) { if (m_data.at(i).job == obj) { return i; } } return -1; } gammaray-2.3.0/plugins/kjobtracker/kjobmodel.h000066400000000000000000000045161255003167400214240ustar00rootroot00000000000000/* kjobmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_KJOBTRACKER_KJOBMODEL_H #define GAMMARAY_KJOBTRACKER_KJOBMODEL_H #include #include class KJob; namespace GammaRay { class KJobModel : public QAbstractTableModel { Q_OBJECT public: explicit KJobModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private slots: void objectAdded(QObject *obj); void objectRemoved(QObject *obj); void jobResult(KJob *job); void jobFinished(KJob *obj); void jobInfo(KJob *job, const QString &plainMessage); private: int indexOfJob(QObject *obj) const; struct KJobInfo { KJob *job; QString name; QString type; QString statusText; enum { Running, Finished, Error, Killed, Deleted } state; }; QVector m_data; }; } #endif // GAMMARAY_KJOBMODEL_H gammaray-2.3.0/plugins/kjobtracker/kjobtracker.cpp000066400000000000000000000034401255003167400223050ustar00rootroot00000000000000/* kjobtracker.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "kjobtracker.h" #include "kjobmodel.h" #include #include #include using namespace GammaRay; KJobTracker::KJobTracker(ProbeInterface *probe, QObject *parent) : QObject(parent), m_jobModel(new KJobModel(this)) { connect(probe->probe(), SIGNAL(objectCreated(QObject*)), m_jobModel, SLOT(objectAdded(QObject*))); connect(probe->probe(), SIGNAL(objectDestroyed(QObject*)), m_jobModel, SLOT(objectRemoved(QObject*))); probe->registerModel("com.kdab.GammaRay.KJobModel", m_jobModel); } KJobTracker::~KJobTracker() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(KJobTrackerFactory) #endif gammaray-2.3.0/plugins/kjobtracker/kjobtracker.h000066400000000000000000000036461255003167400217620ustar00rootroot00000000000000/* kjobtracker.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_KJOBTRACKER_KJOBTRACKER_H #define GAMMARAY_KJOBTRACKER_KJOBTRACKER_H #include #include class KJob; namespace GammaRay { class KJobModel; class KJobTracker : public QObject { Q_OBJECT public: explicit KJobTracker(ProbeInterface *probe, QObject *parent = 0); virtual ~KJobTracker(); private: KJobModel *m_jobModel; }; class KJobTrackerFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_kjobtracker.json") public: explicit KJobTrackerFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("KJobs"); } }; } #endif // GAMMARAY_KJOBTRACKER_H gammaray-2.3.0/plugins/kjobtracker/kjobtrackerwidget.cpp000066400000000000000000000034721255003167400235160ustar00rootroot00000000000000/* kjobtrackerwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "kjobtrackerwidget.h" #include "ui_kjobtrackerwidget.h" #include using namespace GammaRay; #include #include #include using namespace GammaRay; KJobTrackerWidget::KJobTrackerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::KJobTrackerWidget) { ui->setupUi(this); QSortFilterProxyModel *filter = new QSortFilterProxyModel(this); filter->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.KJobModel")); ui->searchLine->setProxy(filter); ui->jobView->setModel(filter); } KJobTrackerWidget::~KJobTrackerWidget() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(KJobTrackerUiFactory) #endif gammaray-2.3.0/plugins/kjobtracker/kjobtrackerwidget.h000066400000000000000000000034711255003167400231620ustar00rootroot00000000000000/* kjobtrackerwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_KJOBTRACKER_KJOBTRACKERWIDGET_H #define GAMMARAY_KJOBTRACKER_KJOBTRACKERWIDGET_H #include #include namespace GammaRay { namespace Ui { class KJobTrackerWidget; } class KJobTrackerWidget : public QWidget { Q_OBJECT public: explicit KJobTrackerWidget(QWidget *parent = 0); ~KJobTrackerWidget(); private: QScopedPointer ui; }; class KJobTrackerUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_kjobtracker.json") }; } #endif // GAMMARAY_KJOBTRACKERWIDGET_H gammaray-2.3.0/plugins/kjobtracker/kjobtrackerwidget.ui000066400000000000000000000017671255003167400233560ustar00rootroot00000000000000 GammaRay::KJobTrackerWidget 0 0 400 300 false true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/plugins/objectvisualizer/000077500000000000000000000000001255003167400203625ustar00rootroot00000000000000gammaray-2.3.0/plugins/objectvisualizer/CMakeLists.txt000066400000000000000000000026371255003167400231320ustar00rootroot00000000000000# probe part set(gammaray_objectvisualizer_plugin_srcs objectvisualizer.cpp objectvisualizermodel.cpp ) gammaray_add_plugin(gammaray_objectvisualizer_plugin gammaray_objectvisualizer.desktop ${gammaray_objectvisualizer_plugin_srcs} ) target_link_libraries(gammaray_objectvisualizer_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) ######## START VTK VISUALIZATION # VTK includes QtGui/... stuff => breaks compilation with Qt5 if(VTK_FOUND AND NOT Qt5Core_FOUND AND GAMMARAY_BUILD_UI) set(OPTIONAL_VTK_LIBRARIES ) add_definitions(-DVTKGUI_ENABLED -DVTK_EXCLUDE_STRSTREAM_HEADERS) include_directories( ${VTK_INCLUDE_DIRS} ) include(${VTK_USE_FILE}) link_directories(${VTK_LIBRARY_DIRS}) set(gammaray_objectvisualizer_ui_plugin_srcs objectvisualizerwidget.cpp vtkcontainer.cpp vtkpanel.cpp vtkwidget.cpp ) list(APPEND OPTIONAL_VTK_LIBRARIES ${VTK_LIBRARIES} ) if(${VTK_MAJOR_VERSION} EQUAL 5) list(APPEND OPTIONAL_VTK_LIBRARIES QVTK) elseif(${VTK_MAJOR_VERSION} EQUAL 6) list(APPEND OPTIONAL_VTK_LIBRARIES vtkGUISupportQt) endif() gammaray_add_plugin(gammaray_objectvisualizer_ui_plugin gammaray_objectvisualizer_ui.desktop ${gammaray_objectvisualizer_ui_plugin_srcs} ) target_link_libraries(gammaray_objectvisualizer_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${OPTIONAL_VTK_LIBRARIES} ${VTK_QT_LIBRARY} gammaray_common gammaray_ui ) endif() ######## END VTK VISUALIZATION gammaray-2.3.0/plugins/objectvisualizer/gammaray_objectvisualizer.desktop000066400000000000000000000002401255003167400272130ustar00rootroot00000000000000[Desktop Entry] Name=Object Visualization X-GammaRay-Types=QObject; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_objectvisualizer_plugin gammaray-2.3.0/plugins/objectvisualizer/gammaray_objectvisualizer.json000066400000000000000000000001521255003167400265150ustar00rootroot00000000000000{ "id": "gammaray_objectvisualizer", "name": "Object Visualization", "types": [ "QObject" ] } gammaray-2.3.0/plugins/objectvisualizer/gammaray_objectvisualizer_ui.desktop000066400000000000000000000002311255003167400277100ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_objectvisualizer X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_objectvisualizer_ui_plugin gammaray-2.3.0/plugins/objectvisualizer/objectvisualizer.cpp000066400000000000000000000031341255003167400244530ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectvisualizer.h" #include "objectvisualizermodel.h" #include using namespace GammaRay; GraphViewer::GraphViewer(ProbeInterface *probe, QObject *parent) : QObject(parent) { ObjectVisualizerModel *model = new ObjectVisualizerModel(this); model->setSourceModel(probe->objectTreeModel()); probe->registerModel("com.kdab.GammaRay.ObjectVisualizerModel", model); } GraphViewer::~GraphViewer() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(GraphViewerFactory) #endif gammaray-2.3.0/plugins/objectvisualizer/objectvisualizer.h000066400000000000000000000035421255003167400241230ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZER_H #define GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZER_H #include namespace GammaRay { class GraphViewer : public QObject { Q_OBJECT public: explicit GraphViewer(ProbeInterface *probe, QObject *parent = 0); ~GraphViewer(); }; class GraphViewerFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_objectvisualizer.json") public: explicit GraphViewerFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Object Visualizer"); } }; } #endif // GAMMARAY_GRAPHVIEWER_H gammaray-2.3.0/plugins/objectvisualizer/objectvisualizermodel.cpp000066400000000000000000000045011255003167400254730ustar00rootroot00000000000000/* objectvisualizermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectvisualizermodel.h" #include using namespace GammaRay; ObjectVisualizerModel::ObjectVisualizerModel(QObject* parent) : QIdentityProxyModel(parent) { } ObjectVisualizerModel::~ObjectVisualizerModel() { } QVariant ObjectVisualizerModel::data(const QModelIndex& proxyIndex, int role) const { if (role == ObjectDisplayName) { QObject *obj = data(proxyIndex, ObjectModel::ObjectRole).value(); return Util::displayString(obj); } else if (role == ObjectId) { QObject *obj = data(proxyIndex, ObjectModel::ObjectRole).value(); return static_cast(reinterpret_cast(obj)); } else if (role == ClassName) { QObject *obj = data(proxyIndex, ObjectModel::ObjectRole).value(); Q_ASSERT(obj); return obj->metaObject()->className(); } return QIdentityProxyModel::data(proxyIndex, role); } QMap< int, QVariant > ObjectVisualizerModel::itemData(const QModelIndex& index) const { QMap d = QIdentityProxyModel::itemData(index); d.insert(ObjectId, data(index, ObjectId)); d.insert(ObjectDisplayName, data(index, ObjectDisplayName)); d.insert(ClassName, data(index, ClassName)); return d; } gammaray-2.3.0/plugins/objectvisualizer/objectvisualizermodel.h000066400000000000000000000041141255003167400251400ustar00rootroot00000000000000/* objectvisualizermodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZERMODEL_H #define GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZERMODEL_H #include #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) #include typedef QSortFilterProxyModel QIdentityProxyModel; #else #include #endif #include namespace GammaRay { /** Augment the regular object tree by some information needed for the visualization * on the client side. */ class ObjectVisualizerModel : public QIdentityProxyModel { Q_OBJECT public: enum Role { ObjectId = ObjectModel::UserRole, ObjectDisplayName, ClassName }; explicit ObjectVisualizerModel(QObject *parent); ~ObjectVisualizerModel(); QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_OBJECTVISUALIZERMODEL_H gammaray-2.3.0/plugins/objectvisualizer/objectvisualizerwidget.cpp000066400000000000000000000070061255003167400256610ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectvisualizerwidget.h" #include "vtkcontainer.h" #include "vtkpanel.h" #include "vtkwidget.h" #include "kde/kfilterproxysearchline.h" #include "kde/krecursivefilterproxymodel.h" #include #include #include #include #include #include #include #include #include using namespace GammaRay; GraphViewerWidget::GraphViewerWidget(QWidget *parent) : QWidget(parent), mWidget(new GraphWidget(this)) { mModel = ObjectBroker::model("com.kdab.GammaRay.ObjectVisualizerModel"); QSortFilterProxyModel *objectFilter = new KRecursiveFilterProxyModel(this); objectFilter->setSourceModel(mModel); objectFilter->setDynamicSortFilter(true); QVBoxLayout *vbox = new QVBoxLayout; KFilterProxySearchLine *objectSearchLine = new KFilterProxySearchLine(this); objectSearchLine->setProxy(objectFilter); vbox->addWidget(objectSearchLine); QTreeView *objectTreeView = new QTreeView(this); objectTreeView->setModel(objectFilter); objectTreeView->setSortingEnabled(true); vbox->addWidget(objectTreeView); mObjectTreeView = objectTreeView; QWidget *treeViewWidget = new QWidget(this); treeViewWidget->setLayout(vbox); QSplitter *splitter = new QSplitter(this); splitter->addWidget(treeViewWidget); splitter->addWidget(mWidget); QHBoxLayout *hbox = new QHBoxLayout(this); hbox->addWidget(splitter); QMetaObject::invokeMethod(this, "delayedInit", Qt::QueuedConnection); } GraphViewerWidget::~GraphViewerWidget() { } void GraphViewerWidget::delayedInit() { // make all existing objects known to the vtk widget mWidget->vtkWidget()->setModel(mModel); mWidget->vtkWidget()->setSelectionModel(mObjectTreeView->selectionModel()); /// FIXME: This won't work for remote clients! // select the qApp object (if any) in the object treeView const QAbstractItemModel *viewModel = mObjectTreeView->model(); const QModelIndexList matches = viewModel->match(viewModel->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(qApp), 1, Qt::MatchFlags(Qt::MatchExactly|Qt::MatchRecursive)); if (!matches.isEmpty()) { Q_ASSERT(matches.first().data(ObjectModel::ObjectRole).value() == qApp); mObjectTreeView->setCurrentIndex(matches.first()); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(ObjectVisualizerUiFactory) #endif gammaray-2.3.0/plugins/objectvisualizer/objectvisualizerwidget.h000066400000000000000000000036721255003167400253330ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZERWIDGET_H #define GAMMARAY_OBJECTVISUALIZER_OBJECTVISUALIZERWIDGET_H #include #include class QAbstractItemModel; class QTreeView; class QModelIndex; namespace GammaRay { class GraphWidget; class GraphViewerWidget : public QWidget { Q_OBJECT public: explicit GraphViewerWidget(QWidget *parent = 0); virtual ~GraphViewerWidget(); private Q_SLOTS: void delayedInit(); private: QAbstractItemModel* mModel; QTreeView *mObjectTreeView; GraphWidget *mWidget; }; class ObjectVisualizerUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_objectvisualizer.json") }; } #endif // GAMMARAY_GRAPHVIEWER_H gammaray-2.3.0/plugins/objectvisualizer/vtkcontainer.cpp000066400000000000000000000027741255003167400236070ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "vtkcontainer.h" #include #include "vtkwidget.h" #include "vtkpanel.h" using namespace GammaRay; GraphWidget::GraphWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout(this); m_vtkWidget = new VtkWidget(this); m_vtkPanel = new VtkPanel(m_vtkWidget, this); vbox->addWidget(m_vtkPanel); vbox->addWidget(m_vtkWidget); } GraphWidget::~GraphWidget() { } gammaray-2.3.0/plugins/objectvisualizer/vtkcontainer.h000066400000000000000000000032061255003167400232430ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_VTKCONTAINER_H #define GAMMARAY_OBJECTVISUALIZER_VTKCONTAINER_H #include namespace GammaRay { class VtkPanel; class VtkWidget; class GraphWidget : public QWidget { Q_OBJECT public: explicit GraphWidget(QWidget *parent = 0); virtual ~GraphWidget(); VtkWidget *vtkWidget() const { return m_vtkWidget; } VtkPanel *vtkPanel() const { return m_vtkPanel; } private: VtkWidget *m_vtkWidget; VtkPanel *m_vtkPanel; }; } #endif // GAMMARAY_GRAPHWIDGET_H gammaray-2.3.0/plugins/objectvisualizer/vtkpanel.cpp000066400000000000000000000106311255003167400227130ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "vtkpanel.h" #include "vtkwidget.h" #include #include #include #include #include #include #include #include #include using namespace GammaRay; VtkPanel::VtkPanel(VtkWidget *vtkWidget, QWidget *parent) : QToolBar(parent), m_vtkWidget(vtkWidget), m_currentLayout("spanTree") { addWidget(new QLabel(tr("Layout:"))); m_layoutBox = new QComboBox; #if 0 m_layoutBox->addItem(tr("Tree Layout"), "tree"); #endif m_layoutBox->addItem(tr("Span Tree Layout"), "spanTree"); m_layoutBox->addItem(tr("Force Directed Layout"), "forceDirected"); m_layoutBox->addItem(tr("Force Directed Layout (3D)"), "forceDirected3D"); m_layoutBox->addItem(tr("Simple 2D Layout"), "simple2D"); connect(m_layoutBox, SIGNAL(currentIndexChanged(int)), SLOT(layoutChanged(int))); addWidget(m_layoutBox); addWidget(new QLabel(tr("Stereo:"))); m_stereoBox = new QComboBox; m_stereoBox->addItem(tr("Off"), 0); m_stereoBox->addItem(tr("Crystal Eyes"), VTK_STEREO_CRYSTAL_EYES); m_stereoBox->addItem(tr("Red/Blue"), VTK_STEREO_RED_BLUE); m_stereoBox->addItem(tr("Interlaced"), VTK_STEREO_INTERLACED); m_stereoBox->addItem(tr("Left"), VTK_STEREO_LEFT); m_stereoBox->addItem(tr("Right"), VTK_STEREO_RIGHT); m_stereoBox->addItem(tr("Dresden"), VTK_STEREO_DRESDEN); m_stereoBox->addItem(tr("Anaglyph"), VTK_STEREO_ANAGLYPH); m_stereoBox->addItem(tr("Checkboard"), VTK_STEREO_CHECKERBOARD); connect(m_stereoBox, SIGNAL(currentIndexChanged(int)), SLOT(stereoModeChanged(int))); addWidget(m_stereoBox); } static vtkGraphLayoutStrategy *layoutStrategyForName(const QString &layoutName) { if (layoutName == "tree") { vtkTreeLayoutStrategy *strategy = vtkTreeLayoutStrategy::New(); strategy->SetRadial(true); return strategy; } else if (layoutName == "spanTree") { return vtkSpanTreeLayoutStrategy::New(); } else if (layoutName == "forceDirected") { return vtkForceDirectedLayoutStrategy::New(); } else if (layoutName == "forceDirected3D") { vtkForceDirectedLayoutStrategy *strategy = vtkForceDirectedLayoutStrategy::New(); strategy->SetThreeDimensionalLayout(true); return strategy; } else if (layoutName == "simple2D") { return vtkSimple2DLayoutStrategy::New(); } else { return 0; } } void VtkPanel::layoutChanged(int index) { const QString layoutName = m_layoutBox->itemData(index).toString(); if (m_currentLayout == layoutName) { return; } // update vtkGraphLayoutStrategy *strategy = layoutStrategyForName(layoutName); m_vtkWidget->layoutView()->SetLayoutStrategy(strategy); m_vtkWidget->layoutView()->ResetCamera(); m_vtkWidget->layoutView()->Render(); m_vtkWidget->GetInteractor()->Start(); m_currentLayout = layoutName; } void VtkPanel::stereoModeChanged(int index) { const int stereoMode = m_stereoBox->itemData(index).toInt(); if (stereoMode <= 0) { m_vtkWidget->layoutView()->GetRenderWindow()->SetStereoRender(false); } else { m_vtkWidget->layoutView()->GetRenderWindow()->SetStereoRender(true); m_vtkWidget->layoutView()->GetRenderWindow()->SetStereoType(stereoMode); } m_vtkWidget->layoutView()->GetRenderWindow()->StereoUpdate(); } VtkPanel::~VtkPanel() { } gammaray-2.3.0/plugins/objectvisualizer/vtkpanel.h000066400000000000000000000032141255003167400223570ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_VTKPANEL_H #define GAMMARAY_OBJECTVISUALIZER_VTKPANEL_H #include class QComboBox; namespace GammaRay { class VtkWidget; class VtkPanel : public QToolBar { Q_OBJECT public: explicit VtkPanel(VtkWidget *vtkWidget, QWidget *parent = 0); virtual ~VtkPanel(); public slots: void layoutChanged(int); void stereoModeChanged(int); private: VtkWidget *m_vtkWidget; QComboBox *m_layoutBox; QComboBox *m_stereoBox; QString m_currentLayout; }; } #endif // GAMMARAY_VTKPANEL_H gammaray-2.3.0/plugins/objectvisualizer/vtkwidget.cpp000066400000000000000000000331211255003167400230760ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "vtkwidget.h" #include "objectvisualizermodel.h" #include "common/objectmodel.h" #include "core/util.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 using namespace GammaRay; //#define WITH_DEBUG #ifdef WITH_DEBUG #define DEBUG(msg) std::cout << Q_FUNC_INFO << " " << msg << std::endl; #else #define DEBUG(msg) qt_noop(); #endif #define VTK_CREATE(type, name) \ vtkSmartPointer name = vtkSmartPointer::New() VtkWidget::VtkWidget(QWidget *parent) : QVTKWidget(parent), m_mousePressed(false), m_updateTimer(new QTimer(this)), m_model(0), m_selectionModel(0), m_repopulateTimer(new QTimer(this)), m_colorIndex(0) { setupRenderer(); setupGraph(); show(); m_updateTimer->setInterval(0); m_updateTimer->setSingleShot(true); connect(m_updateTimer, SIGNAL(timeout()), SLOT(renderViewImpl())); m_repopulateTimer->setInterval(100); m_repopulateTimer->setSingleShot(true); connect(m_repopulateTimer, SIGNAL(timeout()), SLOT(doRepopulate())); } VtkWidget::~VtkWidget() { clear(); DEBUG("") } void VtkWidget::setModel(QAbstractItemModel *model) { m_model = model; connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(objectRowsInserted(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(objectRowsAboutToBeRemoved(QModelIndex,int,int))); connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(objectDataChanged(QModelIndex,QModelIndex))); doRepopulate(); // no delay here, otherwise we race against the signals } void VtkWidget::setSelectionModel(QItemSelectionModel *selectionModel) { m_selectionModel = selectionModel; connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged())); } void VtkWidget::setupRenderer() { } void VtkWidget::resetCamera() { m_view->ResetCamera(); } void VtkWidget::mousePressEvent(QMouseEvent *event) { m_mousePressed = true; QVTKWidget::mousePressEvent(event); } void VtkWidget::mouseReleaseEvent(QMouseEvent *event) { m_mousePressed = false; QVTKWidget::mouseReleaseEvent(event); } void VtkWidget::setupGraph() { DEBUG("start") VTK_CREATE(vtkMutableDirectedGraph, graph); m_graph = graph; VTK_CREATE(vtkVariantArray, vertexPropertyArr); vertexPropertyArr->SetNumberOfValues(3); m_vertexPropertyArr = vertexPropertyArr; VTK_CREATE(vtkStringArray, vertexProp0Array); vertexProp0Array->SetName("labels"); m_graph->GetVertexData()->AddArray(vertexProp0Array); // currently not used VTK_CREATE(vtkIntArray, vertexProp1Array); vertexProp1Array->SetName("weight"); m_graph->GetVertexData()->AddArray(vertexProp1Array); // coloring vtkSmartPointer vertexColors = vtkSmartPointer::New(); vertexColors->SetName("Color"); m_graph->GetVertexData()->AddArray(vertexColors); vtkSmartPointer colorLookupTable = vtkSmartPointer::New(); colorLookupTable->Build(); vtkSmartPointer theme = vtkSmartPointer::New(); theme->SetPointLookupTable(colorLookupTable); vtkGraphLayoutView *graphLayoutView = vtkGraphLayoutView::New(); graphLayoutView->AddRepresentationFromInput(graph); graphLayoutView->SetVertexLabelVisibility(true); graphLayoutView->SetVertexLabelArrayName("labels"); graphLayoutView->SetLayoutStrategyToSpanTree(); graphLayoutView->SetVertexColorArrayName("Color"); graphLayoutView->SetColorVertices(true); graphLayoutView->ApplyViewTheme(theme); m_view = graphLayoutView; VTK_CREATE(vtkInteractorStyleTrackballCamera, style); vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); renderWindowInteractor->SetRenderWindow(graphLayoutView->GetRenderWindow()); renderWindowInteractor->SetInteractorStyle(style); renderWindowInteractor->Initialize(); SetRenderWindow(graphLayoutView->GetRenderWindow()); // code for generating edge arrow heads, needs some love // currently it modifies the layouting // how to use: // comment the AddRepresentationFromInput call to vtkGraphLayoutView and uncomment this #if 0 VTK_CREATE(vtkGraphLayout, layout); layout->SetInput(graph); layout->SetLayoutStrategy(strategy); // Tell the view to use the vertex layout we provide graphLayoutView->SetLayoutStrategyToPassThrough(); // The arrows will be positioned on a straight line between two // vertices so tell the view not to draw arcs for parallel edges graphLayoutView->SetEdgeLayoutStrategyToPassThrough(); // Add the graph to the view. This will render vertices and edges, // but not edge arrows. graphLayoutView->AddRepresentationFromInputConnection(layout->GetOutputPort()); // Manually create an actor containing the glyphed arrows. VTK_CREATE(vtkGraphToPolyData, graphToPoly); graphToPoly->SetInputConnection(layout->GetOutputPort()); graphToPoly->EdgeGlyphOutputOn(); // Set the position (0: edge start, 1: edge end) where // the edge arrows should go. graphToPoly->SetEdgeGlyphPosition(0.98); // Make a simple edge arrow for glyphing. VTK_CREATE(vtkGlyphSource2D, arrowSource); arrowSource->SetGlyphTypeToEdgeArrow(); arrowSource->SetScale(0.001); arrowSource->Update(); // Use Glyph3D to repeat the glyph on all edges. VTK_CREATE(vtkGlyph3D, arrowGlyph); arrowGlyph->SetInputConnection(0, graphToPoly->GetOutputPort(1)); arrowGlyph->SetInputConnection(1, arrowSource->GetOutputPort()); // Add the edge arrow actor to the view. VTK_CREATE(vtkPolyDataMapper, arrowMapper); arrowMapper->SetInputConnection(arrowGlyph->GetOutputPort()); VTK_CREATE(vtkActor, arrowActor); arrowActor->SetMapper(arrowMapper); graphLayoutView->GetRenderer()->AddActor(arrowActor); #endif graphLayoutView->ResetCamera(); graphLayoutView->Render(); graphLayoutView->GetInteractor()->Start(); DEBUG("end") } qulonglong VtkWidget::addObject(const QModelIndex &index) { // ignore new objects during scene interaction // TODO: Add some code to add the objects later on => queue objects if (m_mousePressed) { DEBUG("Ignoring new object during scene interaction: " << object << " " << object->metaObject()->className()) return 0; } qulonglong objectId = index.data(ObjectVisualizerModel::ObjectId).toULongLong(); const QString className = index.data(ObjectVisualizerModel::ClassName).toString(); #if 0 // FIXME this breaks the graph structure since this will cause orphan children! if (className == "QVTKInteractorInternal") { return 0; } #endif if (!objectId || m_objectIdMap.contains(objectId)) { return 0; } if (!filterAcceptsObject(index)) { return 0; } const QString label = index.data(ObjectVisualizerModel::ObjectDisplayName).toString(); const int weight = 1; // TODO: Make weight somewhat usable? m_vertexPropertyArr->SetValue(0, vtkUnicodeString::from_utf16(label.utf16())); m_vertexPropertyArr->SetValue(1, weight); static int colorIndex = 0; colorIndex = colorIndex % 10; QMap< QString, int >::const_iterator it = m_typeColorMap.constFind(className); if (it != m_typeColorMap.constEnd()) { m_vertexPropertyArr->SetValue(2, it.value()); } else { m_vertexPropertyArr->SetValue(2, m_colorIndex); m_typeColorMap.insert(className, m_colorIndex); ++m_colorIndex; } const vtkIdType type = m_graph->AddVertex(m_vertexPropertyArr); DEBUG("Add: " << type << " " << object->metaObject()->className()) m_objectIdMap[objectId] = type; // recursively add our children for (int i = 0; i < index.model()->rowCount(index); ++i) { addObject(index.child(i, 0)); } // add edge to parent if (index.parent().isValid()) { const qulonglong parentId = index.parent().data(ObjectVisualizerModel::ObjectId).toULongLong(); if (parentId) { Q_ASSERT(m_objectIdMap.contains(parentId)); const vtkIdType parentType = m_objectIdMap.value(parentId); m_graph->AddEdge(parentType, type); } } renderView(); return objectId; } bool VtkWidget::removeObject(const QModelIndex &index) { for (int i = 0; i < index.model()->rowCount(index); ++i) { removeObject(index.child(i, 0)); } const qulonglong objectId = index.data(ObjectVisualizerModel::ObjectId).toULongLong(); return removeObjectInternal(objectId); } bool VtkWidget::removeObjectInternal(qulonglong objectId) { if (!m_objectIdMap.contains(objectId)) { return false; } // Remove id-for-object from VTK's graph data structure const vtkIdType type = m_objectIdMap[objectId]; const int size = m_graph->GetNumberOfVertices(); m_graph->RemoveVertex(type); // VTK re-orders the vertex IDs after removal! // we have to copy this behavior to track the associated QObject instances const vtkIdType lastId = m_objectIdMap.size() - 1; DEBUG("Type: " << type << " Last: " << lastId) if (type != lastId) { qulonglong lastObjectId = m_objectIdMap.key(lastId); Q_ASSERT(lastObjectId); m_objectIdMap[lastObjectId] = type; } // Remove object from our map if (size > m_graph->GetNumberOfVertices()) { Q_ASSERT(m_objectIdMap.remove(objectId) == 1); } else { DEBUG("Warning: Should not happen: Could not remove vertice with id: " << type) } renderView(); return true; } /// Schedules the re-rendering of the VTK view void VtkWidget::renderView() { m_updateTimer->start(); } void VtkWidget::clear() { // TODO: there must be an easier/faster way to clean the graph data // Just re-create the vtk graph data object? Q_FOREACH (const qulonglong &objectId, m_objectIdMap) { removeObjectInternal(objectId); } m_objectIdMap.clear(); renderView(); } void VtkWidget::renderViewImpl() { DEBUG("") m_view->Render(); m_view->ResetCamera(); } void VtkWidget::selectionChanged() { repopulate(); resetCamera(); } void VtkWidget::repopulate() { if (!m_repopulateTimer->isActive()) { m_repopulateTimer->start(); } } void VtkWidget::doRepopulate() { DEBUG("") clear(); for (int i = 0; i < m_model->rowCount(); ++i) { const QModelIndex index = m_model->index(i, 0); addObject(index); } } // TODO: Move to Util.h? static bool descendantOf(const QModelIndex &ascendant, const QModelIndex &index) { const QModelIndex parent = index.parent(); if (!parent.isValid()) { return false; } if (parent == ascendant) { return true; } return descendantOf(ascendant, parent); } static QModelIndex mapToSource(const QModelIndex &proxyIndex) { if (proxyIndex.model()->inherits("GammaRay::ObjectVisualizerModel")) { return proxyIndex; } const QAbstractProxyModel *proxyModel = qobject_cast(proxyIndex.model()); if (proxyModel) { return mapToSource(proxyModel->mapToSource(proxyIndex)); } else { return proxyIndex; } } bool VtkWidget::filterAcceptsObject(const QModelIndex &index) const { if (!m_selectionModel) { return true; } QModelIndexList rows = m_selectionModel->selectedRows(); foreach (const QModelIndex &row, rows) { const QModelIndex sourceRow = mapToSource(row); if (index == sourceRow) { return true; } return descendantOf(sourceRow, index); } return true; // empty selection } void VtkWidget::objectRowsInserted(const QModelIndex &parent, int start, int end) { for (int i = start; i <= end; ++i) { const QModelIndex index = m_model->index(i, 0, parent); addObject(index); } } void VtkWidget::objectRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { for (int i = start; i <= end; ++i) { const QModelIndex index = m_model->index(i, 0, parent); removeObject(index); } } void VtkWidget::objectDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { const QModelIndex index = m_model->index(i, 0, topLeft.parent()); addObject(index); } } gammaray-2.3.0/plugins/objectvisualizer/vtkwidget.h000066400000000000000000000063541255003167400225530ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTVISUALIZER_VTKWIDGET_H #define GAMMARAY_OBJECTVISUALIZER_VTKWIDGET_H #include #include #include #include class QItemSelectionModel; class QModelIndex; class QAbstractItemModel; class vtkGraphLayoutStrategy; class vtkVariantArray; class vtkGraphLayoutView; class vtkMutableDirectedGraph; class QMouseEvent; class QTimer; namespace GammaRay { class VtkWidget : public QVTKWidget { Q_OBJECT public: explicit VtkWidget(QWidget *parent = 0); virtual ~VtkWidget(); vtkGraphLayoutView *layoutView() const { return m_view; } void setModel(QAbstractItemModel* model); void setSelectionModel(QItemSelectionModel* selectionModel); public Q_SLOTS: void resetCamera(); qulonglong addObject(const QModelIndex& index); bool removeObject(const QModelIndex &index); void clear(); void repopulate(); private Q_SLOTS: bool removeObjectInternal(qulonglong objectId); void doRepopulate(); void selectionChanged(); void renderViewImpl(); void renderView(); void objectRowsInserted(const QModelIndex &parent, int start, int end); void objectRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); void objectDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); protected: virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); bool filterAcceptsObject(const QModelIndex &index) const; private: void setupGraph(); void setupRenderer(); bool m_mousePressed; QTimer *m_updateTimer; QAbstractItemModel* m_model; QItemSelectionModel* m_selectionModel; QTimer *m_repopulateTimer; // TODO: Instead of tracking all available objects, make Probe::m_validObjects public? QMap m_objectIdMap; int m_colorIndex; QMap m_typeColorMap; vtkSmartPointer m_vertexPropertyArr; vtkGraphLayoutView *m_view; vtkSmartPointer m_graph; }; } #endif // GAMMARAY_VTKWIDGET_H gammaray-2.3.0/plugins/qmlsupport/000077500000000000000000000000001255003167400172245ustar00rootroot00000000000000gammaray-2.3.0/plugins/qmlsupport/CMakeLists.txt000066400000000000000000000002451255003167400217650ustar00rootroot00000000000000# probe plugin gammaray_add_plugin(gammaray_qmlsupport gammaray_qmlsupport.desktop qmlsupport.cpp) target_link_libraries(gammaray_qmlsupport gammaray_core Qt5::Qml) gammaray-2.3.0/plugins/qmlsupport/gammaray_qmlsupport.desktop000066400000000000000000000002311255003167400247170ustar00rootroot00000000000000[Desktop Entry] Name=QML Support X-GammaRay-Types=QQmlEngine; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_qmlsupport Hidden=true gammaray-2.3.0/plugins/qmlsupport/gammaray_qmlsupport.json000066400000000000000000000001621255003167400242220ustar00rootroot00000000000000{ "id": "gammaray_qmlsupport", "name": "QML Support", "types": [ "QQmlEngine" ], "hidden": true } gammaray-2.3.0/plugins/qmlsupport/qmlsupport.cpp000066400000000000000000000111571255003167400221630ustar00rootroot00000000000000/* qmlsupport.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "qmlsupport.h" #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QQmlError) using namespace GammaRay; static QString qmlErrorToString(const QQmlError &error) { return QString::fromLatin1("%1:%2:%3: %4") .arg(error.url().toString()) .arg(error.line()) .arg(error.column()) .arg(error.description()); } static QString qmlListPropertyToString(const QVariant &value, bool *ok) { if (qstrncmp(value.typeName(), "QQmlListProperty<", 17) != 0 || !value.isValid()) return QString(); *ok = true; QQmlListProperty *prop = reinterpret_cast*>(const_cast(value.data())); const int count = prop->count(prop); if (!count) return QObject::tr(""); QStringList l; l.reserve(count); for (int i = 0; i < prop->count(prop); ++i) { l.push_back(Util::displayString(prop->at(prop, i))); } return l.join(QLatin1String(", ")); } static QString qjsValueToString(const QJSValue &v) { if (v.isArray()) { return ""; } else if (v.isBool()) { return v.toBool() ? "true" : "false"; } else if (v.isCallable()) { return ""; } else if (v.isDate()) { return v.toDateTime().toString(); } else if (v.isError()) { return ""; } else if (v.isNull()) { return ""; } else if (v.isNumber()) { return QString::number(v.toNumber()); } else if (v.isObject()) { return ""; } else if (v.isQObject()) { return Util::displayString(v.toQObject()); } else if (v.isRegExp()) { return ""; } else if (v.isString()) { return v.toString(); } else if (v.isUndefined()) { return ""; } else if (v.isVariant()) { return VariantHandler::displayString(v.toVariant()); } return ""; } QmlSupport::QmlSupport(GammaRay::ProbeInterface* probe, QObject* parent) : QObject(parent) { Q_UNUSED(probe); MetaObject *mo = 0; MO_ADD_METAOBJECT1(QQmlComponent, QObject); MO_ADD_PROPERTY_RO(QQmlComponent, QList, errors); MO_ADD_PROPERTY_RO(QQmlComponent, bool, isError); MO_ADD_PROPERTY_RO(QQmlComponent, bool, isLoading); MO_ADD_PROPERTY_RO(QQmlComponent, bool, isNull); MO_ADD_PROPERTY_RO(QQmlComponent, bool, isReady); MO_ADD_METAOBJECT1(QQmlContext, QObject); MO_ADD_PROPERTY_CR(QQmlContext, QUrl, baseUrl, setBaseUrl); MO_ADD_PROPERTY (QQmlContext, QObject*, contextObject, setContextObject); MO_ADD_PROPERTY_RO(QQmlContext, QQmlEngine*, engine); MO_ADD_PROPERTY_RO(QQmlContext, bool, isValid); MO_ADD_PROPERTY_RO(QQmlContext, QQmlContext*, parentContext); MO_ADD_METAOBJECT1(QQmlEngine, QObject); MO_ADD_PROPERTY_CR(QQmlEngine, QUrl, baseUrl, setBaseUrl); MO_ADD_PROPERTY_CR(QQmlEngine, QStringList, importPathList, setImportPathList); MO_ADD_PROPERTY (QQmlEngine, bool, outputWarningsToStandardError, setOutputWarningsToStandardError); MO_ADD_PROPERTY_CR(QQmlEngine, QStringList, pluginPathList, setPluginPathList); MO_ADD_PROPERTY_RO(QQmlEngine, QQmlContext*, rootContext); VariantHandler::registerStringConverter(qjsValueToString); VariantHandler::registerStringConverter(qmlErrorToString); VariantHandler::registerGenericStringConverter(qmlListPropertyToString); } QString QmlSupportFactory::name() const { return tr("QML Support"); } gammaray-2.3.0/plugins/qmlsupport/qmlsupport.h000066400000000000000000000034021255003167400216220ustar00rootroot00000000000000/* qmlsupport.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QMLSUPPORT_QMLSUPPORT_H #define GAMMARAY_QMLSUPPORT_QMLSUPPORT_H #include #include namespace GammaRay { class QmlSupport : public QObject { Q_OBJECT public: explicit QmlSupport(ProbeInterface *probe, QObject *parent = 0); }; class QmlSupportFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_qmlsupport.json") public: explicit QmlSupportFactory(QObject *parent = 0) : QObject(parent) { } QString name() const Q_DECL_OVERRIDE; }; } #endif gammaray-2.3.0/plugins/quickinspector/000077500000000000000000000000001255003167400200415ustar00rootroot00000000000000gammaray-2.3.0/plugins/quickinspector/CMakeLists.txt000066400000000000000000000050051255003167400226010ustar00rootroot00000000000000 # check if we can build the Quick inspector # TODO 5.1.0 and below require private V8 headers which do not provide CMake variables, # so we would need to find those manually if(Qt5Quick_FOUND AND HAVE_PRIVATE_Qt5Quick_HEADERS AND NOT ${Qt5Quick_VERSION} VERSION_LESS 5.2.0) set(HAVE_QUICK_INSPECTOR TRUE) # shared stuff set(gammaray_quickinspector_shared_srcs quickinspectorinterface.cpp transferimage.cpp materialextension/materialextensioninterface.cpp geometryextension/sggeometryextensioninterface.cpp ) add_library(gammaray_quickinspector_shared STATIC ${gammaray_quickinspector_shared_srcs}) target_link_libraries(gammaray_quickinspector_shared gammaray_common Qt5::Gui) set_target_properties(gammaray_quickinspector_shared PROPERTIES POSITION_INDEPENDENT_CODE ON) include_directories(${Qt5Quick_PRIVATE_INCLUDE_DIRS}) set(gammaray_quickinspector_srcs quickinspector.cpp quickitemmodel.cpp quickscenegraphmodel.cpp materialextension/materialextension.cpp geometryextension/sggeometryextension.cpp geometryextension/sggeometrymodel.cpp ) gammaray_add_plugin(gammaray_quickinspector gammaray_quickinspector.desktop ${gammaray_quickinspector_srcs} ) target_link_libraries(gammaray_quickinspector gammaray_quickinspector_shared gammaray_core Qt5::Quick ) if(GAMMARAY_BUILD_UI) # ui plugin set(gammaray_quickinspector_ui_srcs quickinspectorclient.cpp quickinspectorwidget.cpp quickclientitemmodel.cpp quickitemdelegate.cpp quickitemtreewatcher.cpp annotatedscenepreview.cpp materialextension/materialextensionclient.cpp materialextension/materialtab.cpp geometryextension/sggeometryextensionclient.cpp geometryextension/sggeometrytab.cpp geometryextension/sgwireframewidget.cpp ) qt4_add_resources(gammaray_quickinspector_ui_srcs resources/quickinspector.qrc ) qt4_wrap_ui(gammaray_quickinspector_ui_srcs quickinspectorwidget.ui materialextension/materialtab.ui geometryextension/sggeometrytab.ui ) gammaray_add_plugin(gammaray_quickinspector_ui gammaray_quickinspector_ui.desktop ${gammaray_quickinspector_ui_srcs} ) target_link_libraries(gammaray_quickinspector_ui gammaray_quickinspector_shared gammaray_ui Qt5::Quick ) endif() endif() add_feature_info( "QtQuick 2 inspector" HAVE_QUICK_INSPECTOR "Requires private Qt5Quick headers and Qt >= 5.2.0 to be available." ) gammaray-2.3.0/plugins/quickinspector/annotatedscenepreview.cpp000066400000000000000000000251341255003167400251470ustar00rootroot00000000000000/* quickitemoverlay.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "annotatedscenepreview.h" #include #include using namespace GammaRay; AnnotatedScenePreview::AnnotatedScenePreview(QQuickItem *parent) : QQuickPaintedItem(parent), m_zoom(1), m_leftMargin(0), m_horizonalCenterOffset(0), m_rightMargin(0), m_topMargin(0), m_verticalCenterOffset(0), m_bottomMargin(0), m_baselineOffset(0), m_x(0), m_y(0) { } AnnotatedScenePreview::~AnnotatedScenePreview() { } void AnnotatedScenePreview::paint(QPainter *p) { if (m_previewData.isEmpty()) { return; } p->setTransform(QTransform::fromTranslate(m_margin.width() / 2, m_margin.height() / 2)); p->fillRect(QRect(QPoint(0, 0), m_image.size() * m_zoom), Qt::white); p->setRenderHint(QPainter::SmoothPixmapTransform); p->drawImage(QRect(QPoint(0, 0), m_image.size() * m_zoom), m_image.transformed(QTransform::fromScale(1, -1))); // bounding box p->setPen(QColor(232, 87, 82, 170)); p->setBrush(QBrush(QColor(232, 87, 82, 95))); p->drawRect(m_boundingRect); // original geometry if (m_itemRect != m_boundingRect) { p->setPen(Qt::gray); p->setBrush(QBrush(Qt::gray, Qt::BDiagPattern)); p->drawRect(m_itemRect); } // children rect if (m_itemRect != m_boundingRect && m_transform.isIdentity()) { // If this item is transformed the children rect will be painted wrongly, // so for now skip painting it. p->setPen(QColor(0, 99, 193, 170)); p->setBrush(QBrush(QColor(0, 99, 193, 95))); p->drawRect(m_childrenRect); } // transform origin if (m_itemRect != m_boundingRect) { p->setPen(QColor(156, 15, 86, 170)); p->drawEllipse(m_transformOriginPoint, 2.5, 2.5); p->drawLine(m_transformOriginPoint - QPointF(0, 6), m_transformOriginPoint + QPointF(0, 6)); p->drawLine(m_transformOriginPoint - QPointF(6, 0), m_transformOriginPoint + QPointF(6, 0)); } // x and y values p->setPen(QColor(136, 136, 136)); if (!m_previewData.value("left").toBool() && !m_previewData.value("horizontalCenter").toBool() && !m_previewData.value("right").toBool() && m_x != 0) { QPointF parentEnd = (QPointF(m_itemRect.x() - m_x, m_itemRect.y())); QPointF itemEnd = m_itemRect.topLeft(); drawArrow(p, parentEnd, itemEnd); p->drawText(QRectF(parentEnd.x(), parentEnd.y() + 10, itemEnd.x() - parentEnd.x(), 50), Qt::AlignHCenter | Qt::TextDontClip, QString("x: %1px").arg(m_x / m_zoom)); } if (!m_previewData.value("top").toBool() && !m_previewData.value("verticalCenter").toBool() && !m_previewData.value("bottom").toBool() && !m_previewData.value("baseline").toBool() && m_y != 0) { QPointF parentEnd = (QPointF(m_itemRect.x(), m_itemRect.y() - m_y)); QPointF itemEnd = m_itemRect.topLeft(); drawArrow(p, parentEnd, itemEnd); p->drawText(QRectF(parentEnd.x() + 10, parentEnd.y(), 100, itemEnd.y() - parentEnd.y()), Qt::AlignVCenter | Qt::TextDontClip, QString("y: %1px").arg(m_y / m_zoom)); } // anchors if (m_previewData.value("left").toBool()) { drawAnchor(p, Qt::Horizontal, m_itemRect.left(), m_leftMargin, QString("margin: %1px").arg(m_leftMargin / m_zoom)); } if (m_previewData.value("horizontalCenter").toBool()) { drawAnchor(p, Qt::Horizontal, (m_itemRect.left() + m_itemRect.right()) / 2, m_horizonalCenterOffset, QString("offset: %1px").arg(m_horizonalCenterOffset / m_zoom)); } if (m_previewData.value("right").toBool()) { drawAnchor(p, Qt::Horizontal, m_itemRect.right(), -m_rightMargin, QString("margin: %1px").arg(m_rightMargin / m_zoom)); } if (m_previewData.value("top").toBool()) { drawAnchor(p, Qt::Vertical, m_itemRect.top(), m_topMargin, QString("margin: %1px").arg(m_topMargin / m_zoom)); } if (m_previewData.value("verticalCenter").toBool()) { drawAnchor(p, Qt::Vertical, (m_itemRect.top() + m_itemRect.bottom()) / 2, m_verticalCenterOffset, QString("offset: %1px").arg(m_verticalCenterOffset / m_zoom)); } if (m_previewData.value("bottom").toBool()) { drawAnchor(p, Qt::Vertical, m_itemRect.bottom(), -m_bottomMargin, QString("margin: %1px").arg(m_bottomMargin / m_zoom)); } if (m_previewData.value("baseline").toBool()) { drawAnchor(p, Qt::Vertical, m_itemRect.top(), m_baselineOffset, QString("offset: %1px").arg(m_baselineOffset / m_zoom)); } } void AnnotatedScenePreview::drawArrow(QPainter *p, QPointF first, QPointF second) { p->drawLine(first, second); QPointF vector(second - first); QMatrix m; m.rotate(30); QVector2D v1 = QVector2D(m.map(vector)).normalized() * 10; m.rotate(-60); QVector2D v2 = QVector2D(m.map(vector)).normalized() * 10; p->drawLine(first, first + v1.toPointF()); p->drawLine(first, first + v2.toPointF()); p->drawLine(second, second - v1.toPointF()); p->drawLine(second, second - v2.toPointF()); } void AnnotatedScenePreview::drawAnchor(QPainter *p, Qt::Orientation orientation, qreal ownAnchorLine, qreal offset, const QString &label) { qreal foreignAnchorLine = ownAnchorLine - offset; QPen pen(QColor(139, 179, 0)); // Margin arrow if (offset) { p->setPen(pen); if (orientation == Qt::Horizontal) { drawArrow(p, QPointF(foreignAnchorLine, (m_itemRect.top() + m_itemRect.bottom()) / 2), QPointF(ownAnchorLine, (m_itemRect.top() + m_itemRect.bottom()) / 2)); } else { drawArrow(p, QPointF((m_itemRect.left() + m_itemRect.right()) / 2, foreignAnchorLine), QPointF((m_itemRect.left() + m_itemRect.right()) / 2, ownAnchorLine)); } // Margin text if (orientation == Qt::Horizontal) { p->drawText( QRectF(foreignAnchorLine, (m_itemRect.top() + m_itemRect.bottom()) / 2 + 10, offset, 50), Qt::AlignHCenter | Qt::TextDontClip, label); } else { p->drawText( QRectF((m_itemRect.left() + m_itemRect.right()) / 2 + 10, foreignAnchorLine, 100, offset), Qt::AlignVCenter | Qt::TextDontClip, label); } } // Own Anchor line pen.setWidth(2); p->setPen(pen); if (orientation == Qt::Horizontal) { p->drawLine(ownAnchorLine, m_itemRect.top(), ownAnchorLine, m_itemRect.bottom()); } else { p->drawLine(m_itemRect.left(), ownAnchorLine, m_itemRect.right(), ownAnchorLine); } // Foreign Anchor line pen.setStyle(Qt::DotLine); p->setPen(pen); if (orientation == Qt::Horizontal) { p->drawLine(foreignAnchorLine, 0, foreignAnchorLine, m_image.height() * m_zoom); } else { p->drawLine(0, foreignAnchorLine, m_image.width() * m_zoom, foreignAnchorLine); } } QVariantMap AnnotatedScenePreview::previewData() const { return m_previewData; } void AnnotatedScenePreview::setPreviewData(QVariantMap previewData) { m_previewData = previewData; updatePreviewData(); update(); emit previewDataChanged(); } void AnnotatedScenePreview::updatePreviewData() { QImage oldImage = m_image; m_image = m_previewData.value("image").value(); if (m_image.size() != oldImage.size()) { emit sourceSizeChanged(); setImplicitHeight(m_zoom * m_image.height() + m_margin.height()); setImplicitWidth(m_zoom * m_image.width() + m_margin.width()); } m_itemRect = m_previewData.value("itemRect").toRectF(); m_itemRect = QRectF(m_itemRect.topLeft() * m_zoom, m_itemRect.bottomRight() * m_zoom); m_boundingRect = m_previewData.value("boundingRect").toRectF(); m_boundingRect = QRectF(m_boundingRect.topLeft() * m_zoom, m_boundingRect.bottomRight() * m_zoom); m_childrenRect = m_previewData.value("childrenRect").toRectF(); m_childrenRect = QRectF(m_childrenRect.topLeft() * m_zoom, m_childrenRect.bottomRight() * m_zoom); m_transformOriginPoint = m_previewData.value("transformOriginPoint").toPointF() * m_zoom; m_transform = m_previewData.value("transform").value(); m_parentTransform = m_previewData.value("parentTransform").value(); m_leftMargin = m_previewData.value("leftMargin").toReal() * m_zoom; m_horizonalCenterOffset = m_previewData.value("horizontalCenterOffset").toReal() * m_zoom; m_rightMargin = m_previewData.value("rightMargin").toReal() * m_zoom; m_topMargin = m_previewData.value("topMargin").toReal() * m_zoom; m_verticalCenterOffset = m_previewData.value("verticalCenterOffset").toReal() * m_zoom; m_bottomMargin = m_previewData.value("bottomMargin").toReal() * m_zoom; m_baselineOffset = m_previewData.value("baselineOffset").toReal() * m_zoom; m_x = m_previewData.value("x").value() * m_zoom; m_y = m_previewData.value("y").value() * m_zoom; } qreal AnnotatedScenePreview::zoom() const { return m_zoom; } void AnnotatedScenePreview::setZoom(qreal zoom) { m_zoom = zoom; updatePreviewData(); update(); emit zoomChanged(); setImplicitHeight(m_zoom * m_image.height() + m_margin.height()); setImplicitWidth(m_zoom * m_image.width() + m_margin.width()); } QSize AnnotatedScenePreview::sourceSize() const { return m_image.size(); } QSize AnnotatedScenePreview::margin() const { return m_margin; } void AnnotatedScenePreview::setMargin(QSize margin) { m_margin = margin; setImplicitHeight(m_zoom * m_image.height() + m_margin.height()); setImplicitWidth(m_zoom * m_image.width() + m_margin.width()); emit marginChanged(); } gammaray-2.3.0/plugins/quickinspector/annotatedscenepreview.h000066400000000000000000000057601255003167400246170ustar00rootroot00000000000000/* quickitemoverlay.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_ANNOTATEDSCENEPREVIEW_H #define GAMMARAY_QUICKINSPECTOR_ANNOTATEDSCENEPREVIEW_H #include #include #include namespace GammaRay { class AnnotatedScenePreview : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(QVariantMap previewData READ previewData WRITE setPreviewData NOTIFY previewDataChanged) Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged) Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged) Q_PROPERTY(QSize margin READ margin WRITE setMargin NOTIFY marginChanged) public: explicit AnnotatedScenePreview(QQuickItem *parent = 0); virtual ~AnnotatedScenePreview(); void paint(QPainter *p) Q_DECL_OVERRIDE; QVariantMap previewData() const; qreal zoom() const; QSize sourceSize() const; QSize margin() const; void setMargin(QSize margin); Q_SIGNALS: void zoomChanged(); void sourceSizeChanged(); void previewDataChanged(); void marginChanged(); public Q_SLOTS: void setPreviewData(QVariantMap previewData); void setZoom(qreal zoom); private: void drawArrow(QPainter *p, QPointF first, QPointF second); void drawAnchor(QPainter *p, Qt::Orientation orientation, qreal ownAnchorLine, qreal offset, const QString &label); void updatePreviewData(); private: QVariantMap m_previewData; QImage m_image; QSize m_margin; qreal m_zoom; QRectF m_itemRect; QRectF m_boundingRect; QRectF m_childrenRect; QPointF m_transformOriginPoint; QTransform m_transform; QTransform m_parentTransform; qreal m_leftMargin; qreal m_horizonalCenterOffset; qreal m_rightMargin; qreal m_topMargin; qreal m_verticalCenterOffset; qreal m_bottomMargin; qreal m_baselineOffset; qreal m_x; qreal m_y; }; } #endif // ANNOTATEDSCENEPREVIEW_H gammaray-2.3.0/plugins/quickinspector/gammaray_quickinspector.desktop000066400000000000000000000002501255003167400263520ustar00rootroot00000000000000[Desktop Entry] Name=Quick Scenes X-GammaRay-Types="QQuickWindow;QQuickItem;QSGNode" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_quickinspector gammaray-2.3.0/plugins/quickinspector/gammaray_quickinspector.json000066400000000000000000000001761255003167400256610ustar00rootroot00000000000000{ "id": "gammaray_quickinspector", "name": "Quick Scenes", "types": [ "QQuickWindow", "QQuickItem", "QSGNode" ] } gammaray-2.3.0/plugins/quickinspector/gammaray_quickinspector_ui.desktop000066400000000000000000000002161255003167400270510ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_quickinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_quickinspector_ui gammaray-2.3.0/plugins/quickinspector/geometryextension/000077500000000000000000000000001255003167400236315ustar00rootroot00000000000000gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextension.cpp000066400000000000000000000043571255003167400304700ustar00rootroot00000000000000/* sggeometryextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sggeometryextension.h" #include "sggeometrymodel.h" #include #include #include #include using namespace GammaRay; SGGeometryExtension::SGGeometryExtension(PropertyController *controller) : SGGeometryExtensionInterface(controller->objectBaseName() + ".sgGeometry", controller), PropertyControllerExtension(controller->objectBaseName() + ".sgGeometry"), m_node(0), m_model(new SGGeometryModel(this)) { controller->registerModel(m_model, "sgGeometryModel"); } SGGeometryExtension::~SGGeometryExtension() { } bool SGGeometryExtension::setObject(void *object, const QString &typeName) { if (typeName == "QSGGeometryNode") { m_node = static_cast(object); m_model->setNode(m_node); QSGGeometry *geometry = m_node->geometry(); emit geometryChanged( geometry->drawingMode(), QByteArray::fromRawData(reinterpret_cast(geometry->indexData()), geometry->indexCount() * geometry->sizeOfIndex()), geometry->indexType()); return true; } return false; } gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextension.h000066400000000000000000000036061255003167400301310ustar00rootroot00000000000000/* sggeometryextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSION_H #define GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSION_H #include #include "sggeometryextensioninterface.h" class QSGGeometryNode; namespace GammaRay { class SGGeometryModel; class PropertyController; class SGGeometryModel; class SGGeometryExtension : public SGGeometryExtensionInterface, public PropertyControllerExtension { Q_OBJECT Q_INTERFACES(GammaRay::SGGeometryExtensionInterface) public: explicit SGGeometryExtension(PropertyController *controller); ~SGGeometryExtension(); bool setObject(void *object, const QString &typeName) Q_DECL_OVERRIDE; private: QSGGeometryNode *m_node; SGGeometryModel *m_model; }; } #endif // SGGEOMETRYEXTENSION_H gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextensionclient.cpp000066400000000000000000000027701255003167400316640ustar00rootroot00000000000000/* sggeometryextensionclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sggeometryextensionclient.h" #include #include #include using namespace GammaRay; SGGeometryExtensionClient::SGGeometryExtensionClient(const QString &name, QObject *parent) : SGGeometryExtensionInterface(name, parent) { } SGGeometryExtensionClient::~SGGeometryExtensionClient() { } gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextensionclient.h000066400000000000000000000032041255003167400313220ustar00rootroot00000000000000/* sggeometryextensionclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSIONCLIENT_H #define GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSIONCLIENT_H #include "sggeometryextensioninterface.h" namespace GammaRay { class SGGeometryExtensionClient : public SGGeometryExtensionInterface { Q_OBJECT Q_INTERFACES(GammaRay::SGGeometryExtensionInterface) public: explicit SGGeometryExtensionClient(const QString &name, QObject *parent = 0); virtual ~SGGeometryExtensionClient(); }; } #endif // GAMMARAY_SGGEOMETRYEXTENSIONCLIENT_H gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextensioninterface.cpp000066400000000000000000000030621255003167400323410ustar00rootroot00000000000000/* methodsextensioninterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sggeometryextensioninterface.h" #include using namespace GammaRay; SGGeometryExtensionInterface::SGGeometryExtensionInterface(const QString &name, QObject *parent) : QObject(parent), m_name(name) { ObjectBroker::registerObject(name, this); } SGGeometryExtensionInterface::~SGGeometryExtensionInterface() { } const QString &SGGeometryExtensionInterface::name() const { return m_name; } gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometryextensioninterface.h000066400000000000000000000036251255003167400320130ustar00rootroot00000000000000/* sggeometryextensioninterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSIONINTERFACE_H #define GAMMARAY_QUICKINSPECTOR_SGGEOMETRYEXTENSIONINTERFACE_H #include namespace GammaRay { /** @brief Client/Server interface of the sggeometry viewer. */ class SGGeometryExtensionInterface : public QObject { Q_OBJECT public: explicit SGGeometryExtensionInterface(const QString &name, QObject *parent = 0); virtual ~SGGeometryExtensionInterface(); const QString &name() const; signals: void geometryChanged(uint drawingMode, QByteArray indices, int indexType); private: QString m_name; }; } Q_DECLARE_INTERFACE(GammaRay::SGGeometryExtensionInterface, "com.kdab.GammaRay.SGGeometryExtensionInterface") #endif // GAMMARAY_SGGEOMETRYEXTENSIONINTERFACE_H gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometrymodel.cpp000066400000000000000000000164611255003167400275530ustar00rootroot00000000000000/* sggeometrymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sggeometrymodel.h" #include #include #include #include #include #include using namespace GammaRay; Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(QVector) GammaRay::SGGeometryModel::SGGeometryModel(QObject *parent) : QAbstractTableModel(parent), m_geometry(0), m_node(0) { } int SGGeometryModel::rowCount(const QModelIndex &parent) const { if (!m_geometry || parent.isValid()) { return 0; } return m_geometry->vertexCount(); } int GammaRay::SGGeometryModel::columnCount(const QModelIndex &parent) const { if (!m_geometry || parent.isValid()) { return 0; } return m_geometry->attributeCount(); } QVariant SGGeometryModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_geometry || !index.internalPointer() || index.row() >= m_geometry->vertexCount() || index.column() >= m_geometry->attributeCount()) { return QVariant(); } if (role == Qt::DisplayRole) { const QSGGeometry::Attribute *attrInfo = m_geometry->attributes(); attrInfo += index.column(); switch (attrInfo->type) { case GL_BYTE: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_UNSIGNED_BYTE: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_UNSIGNED_SHORT: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_SHORT: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_INT: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_UNSIGNED_INT: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); case GL_FLOAT: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); #if defined(GL_DOUBLE) && GL_DOUBLE != GL_FLOAT case GL_DOUBLE: return toStringList(index.internalPointer(), attrInfo->tupleSize).join(", "); #endif #ifndef QT_OPENGL_ES_2 case GL_2_BYTES: return "2Bytes"; case GL_3_BYTES: return "3Bytes"; case GL_4_BYTES: return "4Bytes"; #endif default: return QString("Unknown %1 byte data: 0x"). arg(attrInfo->tupleSize). append(QByteArray((char*)index.internalPointer(), attrInfo->tupleSize). toHex()); } } else if (role == IsCoordinateRole) { const QSGGeometry::Attribute *attrInfo = m_geometry->attributes(); attrInfo += index.column(); return (bool)attrInfo->isVertexCoordinate; } else if (role == RenderRole) { const QSGGeometry::Attribute *attrInfo = m_geometry->attributes(); attrInfo += index.column(); switch (attrInfo->type) { case GL_BYTE: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_UNSIGNED_BYTE: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_UNSIGNED_SHORT: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_SHORT: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_INT: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_UNSIGNED_INT: return toVariantList(index.internalPointer(), attrInfo->tupleSize); case GL_FLOAT: return toVariantList(index.internalPointer(), attrInfo->tupleSize); #if defined(GL_DOUBLE) && GL_DOUBLE != GL_FLOAT case GL_DOUBLE: return toVariantList(index.internalPointer(), attrInfo->tupleSize); #endif default: return QVariant(); } } return QVariant(); } QMap< int, QVariant > SGGeometryModel::itemData(const QModelIndex &index) const { QMap map = QAbstractItemModel::itemData(index); map.insert(IsCoordinateRole, data(index, IsCoordinateRole)); map.insert(RenderRole, data(index, RenderRole)); return map; } QVariant SGGeometryModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal && m_geometry) { const QSGGeometry::Attribute *attrInfo = m_geometry->attributes(); attrInfo += section; char const *const *attributeNames = m_node->material()->createShader()->attributeNames(); for (int i = 0; i <= section; i++) { if (!attributeNames[i]) { break; } if (i == section) { return attributeNames[section]; } } } return QAbstractItemModel::headerData(section, orientation, role); } void SGGeometryModel::setNode(QSGGeometryNode *node) { beginResetModel(); m_node = node; m_geometry = node->geometry(); endResetModel(); } QModelIndex GammaRay::SGGeometryModel::index(int row, int column, const QModelIndex &parent) const { if (!m_geometry || row >= m_geometry->vertexCount() || column >= m_geometry->attributeCount() || parent.isValid()) { return QModelIndex(); } char *attr = static_cast(m_geometry->vertexData()); attr += m_geometry->sizeOfVertex() * row; const QSGGeometry::Attribute *attrInfo = m_geometry->attributes(); int tupleItemSize = 0; switch (attrInfo->type) { case GL_BYTE: tupleItemSize = sizeof(char); break; case GL_UNSIGNED_BYTE: tupleItemSize = sizeof(unsigned char); break; case GL_UNSIGNED_SHORT: tupleItemSize = sizeof(unsigned short); break; case GL_SHORT: tupleItemSize = sizeof(short); break; case GL_INT: tupleItemSize = sizeof(int); break; case GL_UNSIGNED_INT: tupleItemSize = sizeof(unsigned int); break; case GL_FLOAT: tupleItemSize = sizeof(float); break; #if defined(GL_DOUBLE) && GL_DOUBLE != GL_FLOAT case GL_DOUBLE: tupleItemSize = sizeof(double); break; #endif default: return createIndex(row, column); } for (int i = 0; i < column; i++) { attr += tupleItemSize * attrInfo->tupleSize; attrInfo++; } return createIndex(row, column, attr); } gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometrymodel.h000066400000000000000000000054761255003167400272240ustar00rootroot00000000000000/* sggeometrymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGGEOMETRYMODEL_H #define GAMMARAY_QUICKINSPECTOR_SGGEOMETRYMODEL_H #include #include class QSGGeometryNode; class QSGGeometry; namespace GammaRay { class SGGeometryModel : public QAbstractTableModel { public: enum Role { IsCoordinateRole = 257, RenderRole = 258 }; explicit SGGeometryModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; void setNode(QSGGeometryNode *node); template static QStringList toStringList(void *data, int size) { QStringList list; T* typedData = static_cast(data); for (int i = 0; i < size; i++) { list << QString::number(*typedData); ++typedData; } return list; } template static QVariantList toVariantList(void *data, int size) { QVariantList list; T* typedData = static_cast(data); for (int i = 0; i < size; i++) { list << QVariant::fromValue(*typedData); ++typedData; } return list; } private: QSGGeometry *m_geometry; QSGGeometryNode *m_node; }; } #endif // GAMMARAY_SGGEOMETRYMODEL_H gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometrytab.cpp000066400000000000000000000046711255003167400272210ustar00rootroot00000000000000/* sggeometrytab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sggeometrytab.h" #include "sggeometryextensioninterface.h" #include "common/objectbroker.h" #include "ui/propertywidget.h" #include "ui_sggeometrytab.h" #include using namespace GammaRay; SGGeometryTab::SGGeometryTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_SGGeometryTab), m_interface(0), m_model(0) { m_ui->setupUi(this); setObjectBaseName(parent->objectBaseName()); } SGGeometryTab::~SGGeometryTab() { } void SGGeometryTab::setObjectBaseName(const QString &baseName) { if (m_interface) { disconnect(m_interface, 0, m_ui->wireframeWidget, 0); } m_model = ObjectBroker::model(baseName + '.' + "sgGeometryModel"); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(m_model); m_ui->tableView->setModel(proxy); QItemSelectionModel *selectionModel = new QItemSelectionModel(proxy); m_ui->tableView->setSelectionModel(selectionModel); m_interface = ObjectBroker::object(baseName + ".sgGeometry"); m_ui->wireframeWidget->setModel(m_model); m_ui->wireframeWidget->setHighlightModel(selectionModel); connect(m_interface, SIGNAL(geometryChanged(uint,QByteArray,int)), m_ui->wireframeWidget, SLOT(onGeometryChanged(uint,QByteArray,int))); } gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometrytab.h000066400000000000000000000033611255003167400266610ustar00rootroot00000000000000/* sggeometrytab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGGEOMETRYTAB_H #define GAMMARAY_QUICKINSPECTOR_SGGEOMETRYTAB_H #include #include class QAbstractItemModel; namespace GammaRay { class SGGeometryExtensionInterface; class Ui_SGGeometryTab; class PropertyWidget; class SGGeometryTab : public QWidget { Q_OBJECT public: explicit SGGeometryTab(PropertyWidget *parent); virtual ~SGGeometryTab(); private: void setObjectBaseName(const QString &baseName); private: Ui_SGGeometryTab *m_ui; SGGeometryExtensionInterface *m_interface; QAbstractItemModel *m_model; }; } #endif // SGGEOMETRYTAB_H gammaray-2.3.0/plugins/quickinspector/geometryextension/sggeometrytab.ui000066400000000000000000000036251255003167400270520ustar00rootroot00000000000000 GammaRay::SGGeometryTab 0 0 561 362 Qt::Horizontal Raw Vertex Data Preview 0 0 SGWireframeWidget QWidget
plugins/quickinspector/geometryextension/sgwireframewidget.h
1
gammaray-2.3.0/plugins/quickinspector/geometryextension/sgwireframewidget.cpp000066400000000000000000000310431255003167400300550ustar00rootroot00000000000000/* sgwireframewidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sgwireframewidget.h" #include "sggeometrymodel.h" #include #include #include #include using namespace GammaRay; SGWireframeWidget::SGWireframeWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), m_model(0), m_positionColumn(-1), m_drawingMode(0), m_indexType(0), m_highlightModel(0), m_geometryWidth(0), m_geometryHeight(0), m_zoom(1), m_offset(10, 10) { } SGWireframeWidget::~SGWireframeWidget() { } void SGWireframeWidget::paintEvent(QPaintEvent *) { if (!m_model || m_vertices.isEmpty() || m_positionColumn == -1 || !(m_indexType == GL_UNSIGNED_INT || m_indexType == GL_UNSIGNED_SHORT || m_indexType == GL_UNSIGNED_BYTE)) { return; } // Prepare painting m_zoom = qMin((width() - 20) / m_geometryWidth, (height() - 20) / m_geometryHeight); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(qApp->palette().color(QPalette::WindowText)); painter.setBrush(QBrush(Qt::black, Qt::SolidPattern)); // Paint int prevIndex1 = -1; // Magic value: The initial value should never used, we set it for int prevIndex2 = -1; // detection only, just in case something goes terribly wrong. int prevIndex3 = -1; int firstIndex; // Calculate the size of one VBO index int indexSize = 0; if (m_indexType == GL_UNSIGNED_INT) { indexSize = sizeof(quint32); } else if (m_indexType == GL_UNSIGNED_SHORT) { indexSize = sizeof(quint16); } else if (m_indexType == GL_UNSIGNED_BYTE) { indexSize = sizeof(quint8); } const int count = m_indexData.isEmpty() ? m_vertices.count() : m_indexData.size() / indexSize; for (int i = 0; i < count; i++) { // Calculate the index of the vertex we're supposed to draw a line from int index = i; if (!m_indexData.isEmpty()) { if (m_indexType == GL_UNSIGNED_INT) { index = *reinterpret_cast(m_indexData.constData() + i * indexSize); } else if (m_indexType == GL_UNSIGNED_SHORT) { index = *reinterpret_cast(m_indexData.constData() + i * indexSize); } else if (m_indexType == GL_UNSIGNED_BYTE) { index = *reinterpret_cast(m_indexData.constData() + i * indexSize); } } if (i == 0) { firstIndex = index; } if (index >= m_vertices.size()) { continue; } // Draw highlighted faces if ((m_drawingMode == GL_TRIANGLES && i % 3 == 2) || (m_drawingMode == GL_TRIANGLE_STRIP && i >= 2)) { drawHighlightedFace(&painter, QVector() << index << prevIndex1 << prevIndex2); } else if (m_drawingMode == GL_TRIANGLE_FAN && i >= 2) { drawHighlightedFace(&painter, QVector() << index << prevIndex1 << firstIndex); } #ifndef QT_OPENGL_ES_2 else if ((m_drawingMode == GL_QUADS || m_drawingMode == GL_QUAD_STRIP) && i % 4 == 3) { drawHighlightedFace(&painter, QVector() << index << prevIndex1 << prevIndex2 << prevIndex3); } else if (m_drawingMode == GL_POLYGON && i == count - 1) { QVector vertices; vertices.reserve(count); for (int j = 0; j < count; j++) { vertices << j; } drawHighlightedFace(&painter, vertices); } #endif // Draw wires // Draw a connection to the previous vertex if (((m_drawingMode == GL_LINES && i % 2) || m_drawingMode == GL_LINE_LOOP || m_drawingMode == GL_LINE_STRIP || (m_drawingMode == GL_TRIANGLES && i % 3) || m_drawingMode == GL_TRIANGLE_STRIP || m_drawingMode == GL_TRIANGLE_FAN #ifndef QT_OPENGL_ES_2 || (m_drawingMode == GL_QUADS && i % 4 != 0) || (m_drawingMode == GL_QUAD_STRIP && i % 2) || m_drawingMode == GL_POLYGON #endif ) && i > 0) { drawWire(&painter, index, prevIndex1); } // Draw a connection to the second previous vertex if ((m_drawingMode == GL_TRIANGLE_STRIP || (m_drawingMode == GL_TRIANGLES && i % 3 == 2) #ifndef QT_OPENGL_ES_2 || m_drawingMode == GL_QUAD_STRIP #endif ) && i > 1) { drawWire(&painter, index, prevIndex2); } // draw a connection to the third previous vertex #ifndef QT_OPENGL_ES_2 if (m_drawingMode == GL_QUADS && i % 4 == 3) { drawWire(&painter, index, prevIndex3); } #endif // Draw a connection to the very first vertex if ((m_drawingMode == GL_LINE_LOOP && i == count - 1) #ifndef QT_OPENGL_ES_2 || (m_drawingMode == GL_POLYGON && i == count - 1) #endif || m_drawingMode == GL_TRIANGLE_FAN) { drawWire(&painter, index, firstIndex); } prevIndex3 = prevIndex2; prevIndex2 = prevIndex1; prevIndex1 = index; } // Paint the vertices for (int i = 0; i < m_vertices.size(); ++i) { if (m_highlightedVertices.contains(i)) { painter.save(); // Glow QRadialGradient radialGrad(m_vertices[i] * m_zoom + m_offset, 6); radialGrad.setColorAt(0, qApp->palette().color(QPalette::Highlight)); radialGrad.setColorAt(1, Qt::transparent); painter.setBrush(QBrush(radialGrad)); painter.setPen(Qt::NoPen); painter.drawEllipse(m_vertices[i] * m_zoom + m_offset, 12, 12); // Highlighted point painter.setBrush(QBrush(qApp->palette().color(QPalette::Highlight))); painter.drawEllipse(m_vertices[i] * m_zoom + m_offset, 3, 3); painter.restore(); } else { // Normal unhighlighted point painter.drawEllipse(m_vertices[i] * m_zoom + m_offset, 3, 3); } } // Paint hint about which draw mode is used QString drawingMode = m_drawingMode == GL_POINTS ? "GL_POINTS" : m_drawingMode == GL_LINES ? "GL_LINES" : m_drawingMode == GL_LINE_STRIP ? "GL_LINE_STRIP" : m_drawingMode == GL_LINE_LOOP ? "GL_LINE_LOOP" : #ifndef QT_OPENGL_ES_2 m_drawingMode == GL_POLYGON ? "GL_POLYGON" : m_drawingMode == GL_QUADS ? "GL_QUADS" : m_drawingMode == GL_QUAD_STRIP ? "GL_QUAD_STRIP" : #endif m_drawingMode == GL_TRIANGLES ? "GL_TRIANGLES" : m_drawingMode == GL_TRIANGLE_STRIP ? "GL_TRIANGLE_STRIP" : m_drawingMode == GL_TRIANGLE_FAN ? "GL_TRIANGLE_FAN" : "Unknown"; QString text = QObject::tr("Drawing mode: %1").arg(drawingMode); painter.drawText(contentsRect().width() - painter.fontMetrics().width(text), contentsRect().height() - painter.fontMetrics().height(), text); } void SGWireframeWidget::drawWire(QPainter *painter, int vertexIndex1, int vertexIndex2) { // Draw wire if (m_highlightedVertices.contains(vertexIndex1) && m_highlightedVertices.contains(vertexIndex2)) { painter->save(); painter->setPen(qApp->palette().color(QPalette::Highlight)); painter->drawLine(m_vertices[vertexIndex1] * m_zoom + m_offset, m_vertices[vertexIndex2] * m_zoom + m_offset); painter->restore(); } else if (vertexIndex1 != -1 && vertexIndex2 != -1) { painter->drawLine(m_vertices[vertexIndex1] * m_zoom + m_offset, m_vertices[vertexIndex2] * m_zoom + m_offset); } } void SGWireframeWidget::drawHighlightedFace(QPainter *painter, QVector vertexIndices) { QVector vertices; foreach (int index, vertexIndices) { if (!m_highlightedVertices.contains(index)) { return; // There is one vertex that is not highlighted. Don't highlight the face. } vertices << m_vertices[index] * m_zoom + m_offset; } painter->save(); QColor color = qApp->palette().color(QPalette::Highlight).lighter(); color.setAlphaF(0.8); painter->setBrush(QBrush(color)); painter->setPen(Qt::NoPen); painter->drawPolygon(QPolygonF(vertices)); painter->restore(); } QAbstractItemModel *SGWireframeWidget::model() const { return m_model; } void SGWireframeWidget::setModel(QAbstractItemModel *model) { if (m_model) { disconnect(m_model, 0, this, 0); } m_model = model; connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onModelDataChanged(QModelIndex,QModelIndex))); } void SGWireframeWidget::setHighlightModel(QItemSelectionModel *selectionModel) { if (m_highlightModel) { disconnect(m_highlightModel, 0, this, 0); } m_highlightModel = selectionModel; connect(m_highlightModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(onHighlightDataChanged(QItemSelection,QItemSelection))); } void SGWireframeWidget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (!topLeft.isValid() || !bottomRight.isValid() || m_positionColumn == -1 || (topLeft.column() <= m_positionColumn && bottomRight.column() >= m_positionColumn)) { // Get the column in which the vertex position data is stored in if (m_positionColumn == -1) { for (int j = 0; j < m_model->columnCount(); j++) { if (m_model->data(m_model->index(0, j), SGGeometryModel::IsCoordinateRole).toBool()) { m_positionColumn = j; break; } } } // Get all the vertices m_vertices.clear(); m_geometryWidth = 0; m_geometryHeight = 0; for (int i = 0; i < m_model->rowCount(); i++) { const QModelIndex index = m_model->index(i, m_positionColumn); const QVariantList data = m_model->data(index, SGGeometryModel::RenderRole).toList(); if (data.isEmpty()) { // Data is incomplete, so no need to render the wireframe yet. // It will be repainted as soon as the data is available. return; } if (data.size() >= 2) { const qreal x = data[0].toReal(); const qreal y = data[1].toReal(); m_vertices << QPointF(x, y); if (x > m_geometryWidth) { m_geometryWidth = x; } if (y > m_geometryHeight) { m_geometryHeight = y; } } } update(); } } void SGWireframeWidget::onHighlightDataChanged(const QItemSelection &selected, const QItemSelection &deselected) { foreach (const QModelIndex &index, deselected.indexes()) { int i = m_highlightedVertices.indexOf(index.row()); if (i != -1) { m_highlightedVertices.remove(i); } } foreach (const QModelIndex &index, selected.indexes()) { if (!m_highlightedVertices.contains(index.row())) { m_highlightedVertices << index.row(); } } update(); } void SGWireframeWidget::onGeometryChanged(uint drawingMode, QByteArray indexData, int indexType) { m_drawingMode = drawingMode; m_indexData = indexData; m_indexType = indexType; m_vertices.clear(); m_highlightedVertices.clear(); m_highlightModel->clear(); } void SGWireframeWidget::mouseReleaseEvent(QMouseEvent *e) { if (~e->modifiers() & Qt::ControlModifier) { m_highlightModel->clear(); } for (int i = 0; i < m_vertices.size(); i++) { int distance = QLineF(e->pos(), m_vertices[i] * m_zoom + m_offset).length(); if (distance <= 5) { if (e->modifiers() & Qt::ControlModifier) { m_highlightModel->select(m_model->index(i, m_positionColumn), QItemSelectionModel::Toggle); } else { m_highlightModel->select(m_model->index(i, m_positionColumn), QItemSelectionModel::Select); } } } QWidget::mouseReleaseEvent(e); } gammaray-2.3.0/plugins/quickinspector/geometryextension/sgwireframewidget.h000066400000000000000000000052641255003167400275300ustar00rootroot00000000000000/* sgwireframewidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_SGWIREFRAMEWIDGET_H #define GAMMARAY_QUICKINSPECTOR_SGWIREFRAMEWIDGET_H #include #include class QItemSelection; class QPainter; class QItemSelectionModel; class QAbstractItemModel; class QModelIndex; namespace GammaRay { class SGWireframeWidget : public QWidget { Q_OBJECT public: explicit SGWireframeWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); ~SGWireframeWidget(); QAbstractItemModel *model() const; void setModel(QAbstractItemModel *m_model); void setHighlightModel(QItemSelectionModel *selectionModel); public slots: void onGeometryChanged(uint drawingMode, QByteArray indexData, int indexType); protected: void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent*) Q_DECL_OVERRIDE; private slots: void onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void onHighlightDataChanged(const QItemSelection &selected, const QItemSelection &deselected); private: void drawWire(QPainter *painter, int vertexIndex1, int vertexIndex2); void drawHighlightedFace(QPainter *painter, QVector< int > vertexIndices); private: QAbstractItemModel *m_model; int m_positionColumn; GLenum m_drawingMode; QByteArray m_indexData; int m_indexType; QItemSelectionModel *m_highlightModel; QVector m_vertices; QVector m_highlightedVertices; qreal m_geometryWidth; qreal m_geometryHeight; qreal m_zoom; const QPointF m_offset; }; } #endif // SGWIREFRAMEWIDGET_H gammaray-2.3.0/plugins/quickinspector/materialextension/000077500000000000000000000000001255003167400235745ustar00rootroot00000000000000gammaray-2.3.0/plugins/quickinspector/materialextension/materialextension.cpp000066400000000000000000000076451255003167400300470ustar00rootroot00000000000000/* materialextension.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "materialextension.h" #include "core/metapropertymodel.h" #include "core/propertycontroller.h" #include "core/varianthandler.h" #include "common/metatypedeclarations.h" #include #include #include #include #include #include #include #include using namespace GammaRay; class SGMaterialShaderThief : public QSGMaterialShader { public: QHash getShaderSources() { return d_func()->m_sourceFiles; } }; MaterialExtension::MaterialExtension(PropertyController *controller) : MaterialExtensionInterface(controller->objectBaseName() + ".material", controller), PropertyControllerExtension(controller->objectBaseName() + ".material"), m_node(0), m_materialPropertyModel(new MetaPropertyModel(this)), m_shaderModel(new QStandardItemModel(this)) { controller->registerModel(m_materialPropertyModel, "materialPropertyModel"); controller->registerModel(m_shaderModel, "shaderModel"); } MaterialExtension::~MaterialExtension() { } #include static const char* typeForMaterial(QSGMaterial *material) { #define MT(type) if (dynamic_cast(material)) return #type; MT(QSGFlatColorMaterial) MT(QSGTextureMaterial) MT(QSGOpaqueTextureMaterial) MT(QSGVertexColorMaterial) #undef MT return "QSGMaterial"; } bool MaterialExtension::setObject(void *object, const QString &typeName) { if (typeName == "QSGGeometryNode") { m_node = static_cast(object); m_materialPropertyModel->setObject(m_node->material(), typeForMaterial(m_node->material())); QSGMaterialShader *materialShader = m_node->material()->createShader(); SGMaterialShaderThief *thief = reinterpret_cast(materialShader); const QHash shaderSources = thief->getShaderSources(); m_shaderModel->clear(); m_shaderModel->setHorizontalHeaderLabels(QStringList() << "Shader"); for (auto it = shaderSources.constBegin(); it != shaderSources.constEnd(); ++it) { foreach (const QString &source, it.value()) { auto *item = new QStandardItem(source); item->setEditable(false); item->setToolTip(tr("Shader type: %1").arg(VariantHandler::displayString(it.key()))); m_shaderModel->appendRow(item); } } return true; } m_materialPropertyModel->setObject(0); return false; } void MaterialExtension::getShader(const QString &fileName) { QFile shaderFile(fileName); if (!shaderFile.open(QIODevice::ReadOnly | QIODevice::Text)) { return; } QString source(shaderFile.readAll()); if (!source.isEmpty()) { emit gotShader(source); } } gammaray-2.3.0/plugins/quickinspector/materialextension/materialextension.h000066400000000000000000000040241255003167400275000ustar00rootroot00000000000000/* materialextension.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSION_H #define GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSION_H #include #include "materialextensioninterface.h" class QSGGeometryNode; class QStandardItemModel; namespace GammaRay { class MetaPropertyModel; class PropertyController; class ObjectEnumModel; class MaterialExtension : public MaterialExtensionInterface, public PropertyControllerExtension { Q_OBJECT Q_INTERFACES(GammaRay::MaterialExtensionInterface) public: explicit MaterialExtension(PropertyController *controller); ~MaterialExtension(); bool setObject(void *object, const QString &typeName) Q_DECL_OVERRIDE; public slots: void getShader(const QString &fileName) Q_DECL_OVERRIDE; private: QSGGeometryNode *m_node; MetaPropertyModel *m_materialPropertyModel; QStandardItemModel *m_shaderModel; }; } #endif // MATERIALEXTENSION_H gammaray-2.3.0/plugins/quickinspector/materialextension/materialextensionclient.cpp000066400000000000000000000031241255003167400312320ustar00rootroot00000000000000/* materialextensionclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "materialextensionclient.h" #include using namespace GammaRay; MaterialExtensionClient::MaterialExtensionClient(const QString &name, QObject *parent) : MaterialExtensionInterface(name, parent) { } MaterialExtensionClient::~MaterialExtensionClient() { } void MaterialExtensionClient::getShader(const QString &fileName) { Endpoint::instance()->invokeObject( name(), "getShader", QVariantList() << QVariant::fromValue(fileName)); } gammaray-2.3.0/plugins/quickinspector/materialextension/materialextensionclient.h000066400000000000000000000032761255003167400307070ustar00rootroot00000000000000/* materialextensionclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSIONCLIENT_H #define GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSIONCLIENT_H #include "materialextensioninterface.h" namespace GammaRay { class MaterialExtensionClient : public MaterialExtensionInterface { Q_OBJECT Q_INTERFACES(GammaRay::MaterialExtensionInterface) public: explicit MaterialExtensionClient(const QString &name, QObject *parent = 0); virtual ~MaterialExtensionClient(); public slots: void getShader(const QString &fileName) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_MATERIALEXTENSIONCLIENT_H gammaray-2.3.0/plugins/quickinspector/materialextension/materialextensioninterface.cpp000066400000000000000000000030461255003167400317170ustar00rootroot00000000000000/* methodsextensioninterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "materialextensioninterface.h" #include using namespace GammaRay; MaterialExtensionInterface::MaterialExtensionInterface(const QString &name, QObject *parent) : QObject(parent), m_name(name) { ObjectBroker::registerObject(name, this); } MaterialExtensionInterface::~MaterialExtensionInterface() { } const QString &MaterialExtensionInterface::name() const { return m_name; } gammaray-2.3.0/plugins/quickinspector/materialextension/materialextensioninterface.h000066400000000000000000000036551255003167400313720ustar00rootroot00000000000000/* materialextensioninterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSIONINTERFACE_H #define GAMMARAY_QUICKINSPECTOR_MATERIALEXTENSIONINTERFACE_H #include namespace GammaRay { /** @brief Client/Server interface of the material viewer. */ class MaterialExtensionInterface : public QObject { Q_OBJECT public: explicit MaterialExtensionInterface(const QString &name, QObject *parent = 0); virtual ~MaterialExtensionInterface(); const QString &name() const; signals: void gotShader(const QString &shaderSource); public slots: virtual void getShader(const QString &fileName) = 0; private: QString m_name; }; } Q_DECLARE_INTERFACE(GammaRay::MaterialExtensionInterface, "com.kdab.GammaRay.MaterialExtensionInterface") #endif // GAMMARAY_MATERIALEXTENSIONINTERFACE_H gammaray-2.3.0/plugins/quickinspector/materialextension/materialtab.cpp000066400000000000000000000052161255003167400265710ustar00rootroot00000000000000/* materialtab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "materialtab.h" #include "materialextensioninterface.h" #include "ui_materialtab.h" #include #include "common/objectbroker.h" using namespace GammaRay; MaterialTab::MaterialTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_MaterialTab), m_interface(0) { m_ui->setupUi(this); setObjectBaseName(parent->objectBaseName()); connect(m_ui->shaderList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(shaderSelectionChanged(QItemSelection))); m_ui->splitter->setStretchFactor(0, 1); m_ui->splitter->setStretchFactor(1, 3); } MaterialTab::~MaterialTab() { } void MaterialTab::setObjectBaseName(const QString &baseName) { if (m_interface) { disconnect(m_interface, 0, this, 0); } m_interface = ObjectBroker::object(baseName + ".material"); connect(m_interface, SIGNAL(gotShader(QString)), this, SLOT(showShader(QString))); m_ui->materialPropertyView->setModel(ObjectBroker::model(baseName + ".materialPropertyModel")); m_ui->shaderList->setModel(ObjectBroker::model(baseName + ".shaderModel")); } void MaterialTab::shaderSelectionChanged(const QItemSelection& selection) { m_ui->shaderEdit->clear(); if (selection.isEmpty()) return; const QModelIndex index = selection.first().topLeft(); if (!index.isValid()) return; m_interface->getShader(index.data(Qt::DisplayRole).toString()); } void MaterialTab::showShader(const QString &shaderSource) { m_ui->shaderEdit->setText(shaderSource); } gammaray-2.3.0/plugins/quickinspector/materialextension/materialtab.h000066400000000000000000000034631255003167400262400ustar00rootroot00000000000000/* materialtab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_MATERIALTAB_H #define GAMMARAY_QUICKINSPECTOR_MATERIALTAB_H #include class QItemSelection; namespace GammaRay { class MaterialExtensionInterface; class Ui_MaterialTab; class PropertyWidget; class MaterialTab : public QWidget { Q_OBJECT public: explicit MaterialTab(PropertyWidget *parent); virtual ~MaterialTab(); private: void setObjectBaseName(const QString &baseName); private slots: void shaderSelectionChanged(const QItemSelection &selection); void showShader(const QString &shaderSource); private: QScopedPointer m_ui; MaterialExtensionInterface *m_interface; }; } #endif // MATERIALTAB_H gammaray-2.3.0/plugins/quickinspector/materialextension/materialtab.ui000066400000000000000000000033051255003167400264210ustar00rootroot00000000000000 GammaRay::MaterialTab 0 0 561 362 Qt::Vertical false false 0 0 false true true true gammaray-2.3.0/plugins/quickinspector/quickclientitemmodel.cpp000066400000000000000000000076701255003167400247720ustar00rootroot00000000000000/* quickclientitemmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickclientitemmodel.h" #include "quickitemmodelroles.h" #include #include #include #include using namespace GammaRay; QuickClientItemModel::QuickClientItemModel(QObject *parent) : KRecursiveFilterProxyModel(parent) { } QuickClientItemModel::~QuickClientItemModel() { } QVariant QuickClientItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role & (Qt::ForegroundRole | Qt::ToolTipRole)) { int flags = QSortFilterProxyModel::data(index, QuickItemModelRole::ItemFlags).value(); // Grey out invisible items if (role == Qt::ForegroundRole && (flags & (QuickItemModelRole::Invisible | QuickItemModelRole::ZeroSize))) { return qApp->palette().color(QPalette::Disabled, QPalette::Text); } // Adjust tooltip to show information about items if (role == Qt::ToolTipRole && flags) { QString tooltip = QSortFilterProxyModel::data(index, role).toString(); tooltip.append("

"); if ((flags & QuickItemModelRole::OutOfView) && (~flags & QuickItemModelRole::Invisible)) { QByteArray byteArray; QBuffer buffer(&byteArray); QIcon::fromTheme("dialog-warning").pixmap(16, 16).save(&buffer, "PNG"); tooltip.append(" Item is visible, but out of view."); flags &= ~QuickItemModelRole::OutOfView; if (flags) { tooltip.append("\n"); } } if (flags) { QStringList flagStrings; if (flags & QuickItemModelRole::Invisible) { flagStrings << tr("is invisible"); } if (flags & QuickItemModelRole::ZeroSize) { flagStrings << tr("has a size of zero"); } if (flags & QuickItemModelRole::OutOfView) { flagStrings << tr("is out of view"); } if (flags & QuickItemModelRole::HasFocus && ~flags & QuickItemModelRole::HasActiveFocus) { flagStrings << tr("has inactive focus"); } if (flags & QuickItemModelRole::HasActiveFocus) { flagStrings << tr("has active focus"); } if (flags & QuickItemModelRole::JustRecievedEvent) { flagStrings << tr("just received an event"); } QByteArray byteArray; QBuffer buffer(&byteArray); QIcon::fromTheme("dialog-information").pixmap(16, 16).save(&buffer, "PNG"); tooltip.append(QString(" Item %1.").arg(flagStrings.join(", "))); } tooltip.append("

"); return tooltip; } } return KRecursiveFilterProxyModel::data(index, role); } gammaray-2.3.0/plugins/quickinspector/quickclientitemmodel.h000066400000000000000000000032601255003167400244260ustar00rootroot00000000000000/* quickclientitemmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKCLIENTITEMMODEL_H #define GAMMARAY_QUICKINSPECTOR_QUICKCLIENTITEMMODEL_H #include namespace GammaRay { /** UI-dependent (and thus client-side) bits of the item tree model. */ class QuickClientItemModel : public KRecursiveFilterProxyModel { Q_OBJECT public: explicit QuickClientItemModel(QObject *parent = 0); ~QuickClientItemModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_QUICKCLIENTITEMMODEL_H gammaray-2.3.0/plugins/quickinspector/quickinspector.cpp000066400000000000000000000721501255003167400236150ustar00rootroot00000000000000/* qmlsupport.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickinspector.h" #include "quickitemmodel.h" #include "quickscenegraphmodel.h" #include "transferimage.h" #include "geometryextension/sggeometryextension.h" #include "materialextension/materialextension.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QQmlError) Q_DECLARE_METATYPE(QSGNode *) Q_DECLARE_METATYPE(QSGBasicGeometryNode *) Q_DECLARE_METATYPE(QSGGeometryNode *) Q_DECLARE_METATYPE(QSGClipNode *) Q_DECLARE_METATYPE(QSGTransformNode *) Q_DECLARE_METATYPE(QSGRootNode *) Q_DECLARE_METATYPE(QSGOpacityNode *) Q_DECLARE_METATYPE(QSGNode::Flags) Q_DECLARE_METATYPE(QSGNode::DirtyState) Q_DECLARE_METATYPE(QSGGeometry *) Q_DECLARE_METATYPE(QMatrix4x4 *) Q_DECLARE_METATYPE(const QMatrix4x4 *) Q_DECLARE_METATYPE(const QSGClipNode *) Q_DECLARE_METATYPE(const QSGGeometry *) Q_DECLARE_METATYPE(QSGMaterial *) Q_DECLARE_METATYPE(QSGMaterial::Flags) Q_DECLARE_METATYPE(QSGTexture::WrapMode) Q_DECLARE_METATYPE(QSGTexture::Filtering) using namespace GammaRay; static QString qSGNodeFlagsToString(QSGNode::Flags flags) { QStringList list; if (flags & QSGNode::OwnedByParent) { list << "OwnedByParent"; } if (flags & QSGNode::UsePreprocess) { list << "UsePreprocess"; } if (flags & QSGNode::OwnsGeometry) { list << "OwnsGeometry"; } if (flags & QSGNode::OwnsMaterial) { list << "OwnsMaterial"; } if (flags & QSGNode::OwnsOpaqueMaterial) { list << "OwnsOpaqueMaterial"; } if (list.isEmpty()) return ""; return list.join(" | "); } static QString qSGNodeDirtyStateToString(QSGNode::DirtyState flags) { QStringList list; #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (flags & QSGNode::DirtySubtreeBlocked) { list << "DirtySubtreeBlocked"; } #endif if (flags & QSGNode::DirtyMatrix) { list << "DirtyMatrix"; } if (flags & QSGNode::DirtyNodeAdded) { list << "DirtyNodeAdded"; } if (flags & QSGNode::DirtyNodeRemoved) { list << "DirtyNodeRemoved"; } if (flags & QSGNode::DirtyGeometry) { list << "DirtyGeometry"; } if (flags & QSGNode::DirtyMaterial) { list << "DirtyMaterial"; } if (flags & QSGNode::DirtyOpacity) { list << "DirtyOpacity"; } if (flags & QSGNode::DirtyForceUpdate) { list << "DirtyForceUpdate"; } if (flags & QSGNode::DirtyUsePreprocess) { list << "DirtyUsePreprocess"; } if (flags & QSGNode::DirtyPropagationMask) { list << "DirtyPropagationMask"; } if (list.isEmpty()) return "Clean"; return list.join(" | "); } static QString qsgMaterialFlagsToString(QSGMaterial::Flags flags) { QStringList list; #define F(f) if (flags & QSGMaterial::f) list.push_back(#f); F(Blending) F(RequiresDeterminant) F(RequiresFullMatrixExceptTranslate) F(RequiresFullMatrix) F(CustomCompileStep) #undef F if (list.isEmpty()) return ""; return list.join(" | "); } static QString qsgTextureFilteringToString(QSGTexture::Filtering filtering) { switch (filtering) { case QSGTexture::None: return "None"; case QSGTexture::Nearest: return "Nearest"; case QSGTexture::Linear: return "Linear"; } return QString("Unknown: %1").arg(filtering); } static QString qsgTextureWrapModeToString(QSGTexture::WrapMode wrapMode) { switch (wrapMode) { case QSGTexture::Repeat: return "Repeat"; case QSGTexture::ClampToEdge: return "ClampToEdge"; } return QString("Unknown: %1").arg(wrapMode); } QuickInspector::QuickInspector(ProbeInterface *probe, QObject *parent) : QuickInspectorInterface(parent), m_source(0), m_probe(probe), m_currentSgNode(0), m_itemModel(new QuickItemModel(this)), m_sgModel(new QuickSceneGraphModel(this)), m_itemPropertyController(new PropertyController("com.kdab.GammaRay.QuickItem", this)), m_sgPropertyController(new PropertyController("com.kdab.GammaRay.QuickSceneGraph", this)), m_clientViewActive(false), m_needsNewFrame(false) { registerPCExtensions(); Server::instance()->registerMonitorNotifier( Endpoint::instance()->objectAddress(objectName()), this, "clientConnectedChanged"); registerMetaTypes(); registerVariantHandlers(); probe->installGlobalEventFilter(this); QAbstractProxyModel *windowModel = new ObjectTypeFilterProxyModel(this); windowModel->setSourceModel(probe->objectListModel()); QAbstractProxyModel * proxy = new SingleColumnObjectProxyModel(this); proxy->setSourceModel(windowModel); m_windowModel = proxy; probe->registerModel("com.kdab.GammaRay.QuickWindowModel", m_windowModel); probe->registerModel("com.kdab.GammaRay.QuickItemModel", m_itemModel); connect(probe->probe(), SIGNAL(objectCreated(QObject*)), m_itemModel, SLOT(objectAdded(QObject*))); connect(probe->probe(), SIGNAL(objectDestroyed(QObject*)), m_itemModel, SLOT(objectRemoved(QObject*))); connect(probe->probe(), SIGNAL(objectSelected(QObject*,QPoint)), SLOT(objectSelected(QObject*))); connect(probe->probe(), SIGNAL(nonQObjectSelected(void*,QString)), SLOT(objectSelected(void*,QString))); m_itemSelectionModel = ObjectBroker::selectionModel(m_itemModel); connect(m_itemSelectionModel, &QItemSelectionModel::selectionChanged, this, &QuickInspector::itemSelectionChanged); probe->registerModel("com.kdab.GammaRay.QuickSceneGraphModel", m_sgModel); m_sgSelectionModel = ObjectBroker::selectionModel(m_sgModel); connect(m_sgSelectionModel, &QItemSelectionModel::selectionChanged, this, &QuickInspector::sgSelectionChanged); connect(m_sgModel, &QuickSceneGraphModel::nodeDeleted, this, &QuickInspector::sgNodeDeleted); } QuickInspector::~QuickInspector() { } void QuickInspector::selectWindow(int index) { const QModelIndex mi = m_windowModel->index(index, 0); QQuickWindow *window = mi.data(ObjectModel::ObjectRole).value(); selectWindow(window); } void QuickInspector::selectWindow(QQuickWindow *window) { if (m_window) { disconnect(m_window, 0, this, 0); } m_window = window; m_itemModel->setWindow(window); m_sgModel->setWindow(window); if (m_window) { // make sure we have selected something for the property editor to not be entirely empty selectItem(m_window->contentItem()); // Insert a ShaderEffectSource to the scene, with the contentItem as its source, in // order to use it to generate a preview of the window as QImage to show on the client. QQuickItem *contentItem = m_window->contentItem(); #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) // working around the 0-sized contentItem in older Qt if (contentItem->height() == 0 && contentItem->width() == 0) { contentItem->setWidth(contentItem->childrenRect().width()); contentItem->setHeight(contentItem->childrenRect().height()); } #endif delete m_source; m_source = new QQuickShaderEffectSource(contentItem); m_source->setParent(this); // hides the item in the object tree (note: parent != parentItem) QQuickItemPrivate::get(m_source)->anchors()->setFill(contentItem); m_source->setScale(0); // The item shouldn't be visible in the original scene, but it still // needs to be rendered. (i.e. setVisible(false) would cause it to // not be rendered anymore) setupPreviewSource(); connect(window, &QQuickWindow::afterRendering, this, &QuickInspector::slotSceneChanged, Qt::DirectConnection); m_window->update(); } } void QuickInspector::setupPreviewSource() { Q_ASSERT(m_window); QQuickItem *contentItem = m_window->contentItem(); const QList children = contentItem->childItems(); if (children.size() == 2) { // prefer non-recursive shader sources, then we don't re-render all the time m_source->setSourceItem(children.at(children.indexOf(m_source) == 1 ? 0 : 1)); } else { m_source->setRecursive(true); m_source->setSourceItem(contentItem); } } void QuickInspector::selectItem(QQuickItem *item) { const QAbstractItemModel *model = m_itemModel; const QModelIndexList indexList = model->match(model->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(item), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_itemSelectionModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } void QuickInspector::selectSGNode(QSGNode *node) { const QAbstractItemModel *model = m_sgModel; const QModelIndexList indexList = model->match(model->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(node), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_sgSelectionModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } void QuickInspector::objectSelected(QObject *object) { QQuickItem *item = qobject_cast(object); if (item) { selectItem(item); } } void QuickInspector::objectSelected(void *object, const QString &typeName) { if (MetaObjectRepository::instance()->metaObject(typeName)->inherits("QSGNode")) { selectSGNode(reinterpret_cast(object)); } } void QuickInspector::renderScene() { if (!m_clientViewActive || !m_window) { return; } m_needsNewFrame = true; m_window->update(); } void QuickInspector::sendRenderedScene() { QVariantMap previewData; previewData.insert("rawImage", QVariant::fromValue(TransferImage(m_currentFrame))); // wrap to allow bypassing expensive PNG compression if (m_currentItem) { QQuickItem *parent = m_currentItem->parentItem(); if (parent) { previewData.insert("itemRect", m_currentItem->parentItem()->mapRectToScene( QRectF(m_currentItem->x(), m_currentItem->y(), m_currentItem->width(), m_currentItem->height()))); } else { previewData.insert("itemRect", QRectF(0, 0, m_currentItem->width(), m_currentItem->height())); } previewData.insert("boundingRect", m_currentItem->mapRectToScene(m_currentItem->boundingRect())); previewData.insert("childrenRect", m_currentItem->mapRectToScene(m_currentItem->childrenRect())); previewData.insert("transformOriginPoint", m_currentItem->mapToScene(m_currentItem->transformOriginPoint())); QQuickAnchors *anchors = m_currentItem->property("anchors").value(); if (anchors) { QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors(); previewData.insert("left", (bool)(usedAnchors & QQuickAnchors::LeftAnchor) || anchors->fill()); previewData.insert("right", (bool)(usedAnchors & QQuickAnchors::RightAnchor) || anchors->fill()); previewData.insert("top", (bool)(usedAnchors & QQuickAnchors::TopAnchor) || anchors->fill()); previewData.insert("bottom", (bool)(usedAnchors & QQuickAnchors::BottomAnchor) || anchors->fill()); previewData.insert("baseline", (bool)(usedAnchors & QQuickAnchors::BaselineAnchor)); previewData.insert("horizontalCenter", (bool)(usedAnchors & QQuickAnchors::HCenterAnchor) || anchors->centerIn()); previewData.insert("verticalCenter", (bool)(usedAnchors & QQuickAnchors::VCenterAnchor) || anchors->centerIn()); previewData.insert("leftMargin", anchors->leftMargin()); previewData.insert("rightMargin", anchors->rightMargin()); previewData.insert("topMargin", anchors->topMargin()); previewData.insert("bottomMargin", anchors->bottomMargin()); previewData.insert("horizontalCenterOffset", anchors->horizontalCenterOffset()); previewData.insert("verticalCenterOffset", anchors->verticalCenterOffset()); previewData.insert("baselineOffset", anchors->baselineOffset()); previewData.insert("margins", anchors->margins()); } previewData.insert("x", m_currentItem->x()); previewData.insert("y", m_currentItem->y()); QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(m_currentItem); previewData.insert("transform", itemPriv->itemToWindowTransform()); if (parent) { QQuickItemPrivate *parentPriv = QQuickItemPrivate::get(parent); previewData.insert("parentTransform", parentPriv->itemToWindowTransform()); } } emit sceneRendered(previewData); } void QuickInspector::slotSceneChanged() { if (!m_clientViewActive || !m_window) { return; } if (!m_needsNewFrame) { emit sceneChanged(); return; } const QSGTextureProvider *provider = m_source->textureProvider(); Q_ASSERT(provider); #if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) const QQuickShaderEffectTexture *texture = qobject_cast(provider->texture()); Q_ASSERT(texture); #else const QSGLayer *texture = qobject_cast(provider->texture()); Q_ASSERT(texture); #endif QOpenGLContext *ctx = QQuickItemPrivate::get(m_source)->sceneGraphRenderContext()->openglContext(); if (ctx->makeCurrent(ctx->surface())) { m_currentFrame = texture->toImage(); } m_needsNewFrame = false; QMetaObject::invokeMethod(this, "sendRenderedScene", Qt::AutoConnection); // we are in the render thread here } void QuickInspector::sendKeyEvent(int type, int key, int modifiers, const QString &text, bool autorep, ushort count) { if (!m_window) { return; } QCoreApplication::sendEvent(m_window, new QKeyEvent((QEvent::Type)type, key, (Qt::KeyboardModifiers)modifiers, text, autorep, count)); } void QuickInspector::sendMouseEvent(int type, const QPointF &localPos, int button, int buttons, int modifiers) { if (!m_window) { return; } QCoreApplication::sendEvent(m_window, new QMouseEvent((QEvent::Type)type, localPos, (Qt::MouseButton)button, (Qt::MouseButtons)buttons, (Qt::KeyboardModifiers)modifiers)); } void QuickInspector::sendWheelEvent(const QPointF &localPos, QPoint pixelDelta, QPoint angleDelta, int buttons, int modifiers) { if (!m_window) { return; } QCoreApplication::sendEvent(m_window, new QWheelEvent(localPos, m_window->mapToGlobal(localPos.toPoint()), pixelDelta, angleDelta, 0, /*not used*/ Qt::Vertical, /*not used*/ (Qt::MouseButtons)buttons, (Qt::KeyboardModifiers)modifiers)); } void QuickInspector::setCustomRenderMode( GammaRay::QuickInspectorInterface::RenderMode customRenderMode) { #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(m_window); winPriv->customRenderMode = customRenderMode == VisualizeClipping ? "clip" : customRenderMode == VisualizeOverdraw ? "overdraw" : customRenderMode == VisualizeBatches ? "batches" : customRenderMode == VisualizeChanges ? "changes" : ""; m_window->update(); #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) if (customRenderMode == VisualizeBatches) { // Work around a performance optimization done in Qt 5.5, that breaks batch // visualization completely. Because it breaks batch visualization, // QSGBatchRenderer will only apply it if no batch visualization is applied. // This workaround forces the batch renderer to reevaluate that, so that it // recognizes it now is applied. QQuickItemPrivate *contentPriv = QQuickItemPrivate::get(m_window->contentItem()); QSGNode *rootNode = contentPriv->itemNode(); while(rootNode->type() != QSGNode::RootNodeType) rootNode = rootNode->parent(); winPriv->renderer->nodeChanged(rootNode, QSGNode::DirtyNodeRemoved); winPriv->renderer->nodeChanged(rootNode, QSGNode::DirtyNodeAdded); } #endif #else Q_UNUSED(customRenderMode); #endif } void QuickInspector::checkFeatures() { emit features( Features( #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) CustomRenderModes #endif ) ); } void QuickInspector::itemSelectionChanged(const QItemSelection &selection) { if (selection.isEmpty()) { return; } const QModelIndex index = selection.first().topLeft(); m_currentItem = index.data(ObjectModel::ObjectRole).value(); m_itemPropertyController->setObject(m_currentItem); // It might be that a sg-node is already selected that belongs to this item, but isn't the root // node of the Item. In this case we don't want to overwrite that selection. if (m_sgModel->itemForSgNode(m_currentSgNode) != m_currentItem) { m_currentSgNode = m_sgModel->sgNodeForItem(m_currentItem); m_sgSelectionModel->select(m_sgModel->indexForNode(m_currentSgNode), QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } if (m_window) { m_window->update(); } } void QuickInspector::sgSelectionChanged(const QItemSelection &selection) { if (selection.isEmpty()) { return; } const QModelIndex index = selection.first().topLeft(); m_currentSgNode = index.data(ObjectModel::ObjectRole).value(); if (!m_sgModel->verifyNodeValidity(m_currentSgNode)) { return; // Apparently the node has been deleted meanwhile, so don't access it. } m_sgPropertyController->setObject(m_currentSgNode, findSGNodeType(m_currentSgNode)); m_currentItem = m_sgModel->itemForSgNode(m_currentSgNode); selectItem(m_currentItem); } void QuickInspector::sgNodeDeleted(QSGNode *node) { if (m_currentSgNode == node) { m_sgPropertyController->setObject(0); } } void QuickInspector::clientConnectedChanged(bool connected) { if (!connected) setSceneViewActive(false); } void QuickInspector::setSceneViewActive(bool active) { m_clientViewActive = active; if (active && m_window) { if (m_source) setupPreviewSource(); m_window->update(); } if (!active && m_source) m_source->setSourceItem(0); // no need to render the screenshot as well if nobody is watching } QQuickItem *QuickInspector::recursiveChiltAt(QQuickItem *parent, const QPointF &pos) const { Q_ASSERT(parent); // we can't use childAt() as that will find m_source, but that's not what we are looking for QQuickItem *child = Q_NULLPTR; auto children = parent->childItems(); std::stable_sort(children.begin(), children.end(), [](QQuickItem *lhs, QQuickItem *rhs) { return lhs->z() < rhs->z(); }); std::reverse(children.begin(), children.end()); foreach (QQuickItem *c, children) { const QPointF p = parent->mapToItem(c, pos); if (c != m_source && c->isVisible() && p.x() >= 0 && c->width() >= p.x() && p.y() >= 0 && c->height() >= p.y()) { child = c; break; } } if (child) { return recursiveChiltAt(child, parent->mapToItem(child, pos)); } return parent; } bool QuickInspector::eventFilter(QObject *receiver, QEvent *event) { if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEv = static_cast(event); if (mouseEv->button() == Qt::LeftButton && mouseEv->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { QQuickWindow *window = qobject_cast(receiver); if (window && window->contentItem()) { QQuickItem *item = recursiveChiltAt(window->contentItem(), mouseEv->pos()); m_probe->selectObject(item); } } } return QObject::eventFilter(receiver, event); } void QuickInspector::registerMetaTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT1(QQuickWindow, QWindow); MO_ADD_PROPERTY (QQuickWindow, bool, clearBeforeRendering, setClearBeforeRendering); MO_ADD_PROPERTY (QQuickWindow, bool, isPersistentOpenGLContext, setPersistentOpenGLContext); MO_ADD_PROPERTY (QQuickWindow, bool, isPersistentSceneGraph, setPersistentSceneGraph); MO_ADD_PROPERTY_RO(QQuickWindow, QQuickItem *, mouseGrabberItem); MO_ADD_PROPERTY_RO(QQuickWindow, QOpenGLContext *, openglContext); MO_ADD_PROPERTY_RO(QQuickWindow, uint, renderTargetId); MO_ADD_METAOBJECT1(QQuickView, QQuickWindow); MO_ADD_PROPERTY_RO(QQuickView, QQmlEngine *, engine); MO_ADD_PROPERTY_RO(QQuickView, QList, errors); MO_ADD_PROPERTY_RO(QQuickView, QSize, initialSize); MO_ADD_PROPERTY_RO(QQuickView, QQmlContext *, rootContext); MO_ADD_PROPERTY_RO(QQuickView, QQuickItem *, rootObject); MO_ADD_METAOBJECT1(QSGTexture, QObject); MO_ADD_PROPERTY (QSGTexture, QSGTexture::Filtering, filtering, setFiltering); MO_ADD_PROPERTY_RO(QSGTexture, bool, hasAlphaChannel); MO_ADD_PROPERTY_RO(QSGTexture, bool, hasMipmaps); MO_ADD_PROPERTY (QSGTexture, QSGTexture::WrapMode, horizontalWrapMode, setHorizontalWrapMode); MO_ADD_PROPERTY_RO(QSGTexture, bool, isAtlasTexture); MO_ADD_PROPERTY (QSGTexture, QSGTexture::Filtering, mipmapFiltering, setMipmapFiltering); MO_ADD_PROPERTY_RO(QSGTexture, QRectF, normalizedTextureSubRect); MO_ADD_PROPERTY_RO(QSGTexture, int, textureId); MO_ADD_PROPERTY_RO(QSGTexture, QSize, textureSize); MO_ADD_PROPERTY (QSGTexture, QSGTexture::WrapMode, verticalWrapMode, setVerticalWrapMode); MO_ADD_METAOBJECT0(QSGNode); MO_ADD_PROPERTY_RO(QSGNode, QSGNode *, parent); MO_ADD_PROPERTY_RO(QSGNode, int, childCount); MO_ADD_PROPERTY_RO(QSGNode, QSGNode::Flags, flags); MO_ADD_PROPERTY_RO(QSGNode, bool, isSubtreeBlocked); MO_ADD_PROPERTY (QSGNode, QSGNode::DirtyState, dirtyState, markDirty); MO_ADD_METAOBJECT1(QSGBasicGeometryNode, QSGNode); MO_ADD_PROPERTY_RO(QSGBasicGeometryNode, const QSGGeometry *, geometry); MO_ADD_PROPERTY_RO(QSGBasicGeometryNode, const QMatrix4x4 *, matrix); MO_ADD_PROPERTY_RO(QSGBasicGeometryNode, const QSGClipNode *, clipList); MO_ADD_METAOBJECT1(QSGGeometryNode, QSGBasicGeometryNode); MO_ADD_PROPERTY (QSGGeometryNode, QSGMaterial *, material, setMaterial); MO_ADD_PROPERTY (QSGGeometryNode, QSGMaterial *, opaqueMaterial, setOpaqueMaterial); MO_ADD_PROPERTY_RO(QSGGeometryNode, QSGMaterial *, activeMaterial); MO_ADD_PROPERTY (QSGGeometryNode, int, renderOrder, setRenderOrder); MO_ADD_PROPERTY (QSGGeometryNode, qreal, inheritedOpacity, setInheritedOpacity); MO_ADD_METAOBJECT1(QSGClipNode, QSGBasicGeometryNode); MO_ADD_PROPERTY (QSGClipNode, bool, isRectangular, setIsRectangular); MO_ADD_PROPERTY_CR(QSGClipNode, QRectF, clipRect, setClipRect); MO_ADD_PROPERTY_RO(QSGClipNode, const QMatrix4x4 *, matrix); MO_ADD_PROPERTY_RO(QSGClipNode, const QSGClipNode *, clipList); MO_ADD_METAOBJECT1(QSGTransformNode, QSGNode); MO_ADD_PROPERTY (QSGTransformNode, const QMatrix4x4&, matrix, setMatrix); MO_ADD_PROPERTY (QSGTransformNode, const QMatrix4x4&, combinedMatrix, setCombinedMatrix); MO_ADD_METAOBJECT1(QSGRootNode, QSGNode); MO_ADD_METAOBJECT1(QSGOpacityNode, QSGNode); MO_ADD_PROPERTY (QSGOpacityNode, qreal, opacity, setOpacity); MO_ADD_PROPERTY (QSGOpacityNode, qreal, combinedOpacity, setCombinedOpacity); MO_ADD_METAOBJECT0(QSGMaterial); MO_ADD_PROPERTY_RO(QSGMaterial, QSGMaterial::Flags, flags); MO_ADD_METAOBJECT1(QSGFlatColorMaterial, QSGMaterial); MO_ADD_PROPERTY (QSGFlatColorMaterial, const QColor&, color, setColor); MO_ADD_METAOBJECT1(QSGOpaqueTextureMaterial, QSGMaterial); MO_ADD_PROPERTY (QSGOpaqueTextureMaterial, QSGTexture::Filtering, filtering, setFiltering); MO_ADD_PROPERTY (QSGOpaqueTextureMaterial, QSGTexture::WrapMode, horizontalWrapMode, setHorizontalWrapMode); MO_ADD_PROPERTY (QSGOpaqueTextureMaterial, QSGTexture::Filtering, mipmapFiltering, setMipmapFiltering); MO_ADD_PROPERTY (QSGOpaqueTextureMaterial, QSGTexture*, texture, setTexture); MO_ADD_PROPERTY (QSGOpaqueTextureMaterial, QSGTexture::WrapMode, verticalWrapMode, setVerticalWrapMode); MO_ADD_METAOBJECT1(QSGTextureMaterial, QSGOpaqueTextureMaterial); MO_ADD_METAOBJECT1(QSGVertexColorMaterial, QSGMaterial); } void QuickInspector::registerVariantHandlers() { VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(qSGNodeFlagsToString); VariantHandler::registerStringConverter(qSGNodeDirtyStateToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(qsgMaterialFlagsToString); VariantHandler::registerStringConverter(qsgTextureFilteringToString); VariantHandler::registerStringConverter(qsgTextureWrapModeToString); } void QuickInspector::registerPCExtensions() { PropertyController::registerExtension(); PropertyController::registerExtension(); } #define QSG_CHECK_TYPE(Class) \ if(dynamic_cast(node) && MetaObjectRepository::instance()->hasMetaObject(#Class)) \ return QLatin1String(#Class) QString QuickInspector::findSGNodeType(QSGNode *node) const { // keep this in reverse topological order of the class hierarchy! QSG_CHECK_TYPE(QSGClipNode); QSG_CHECK_TYPE(QSGGeometryNode); QSG_CHECK_TYPE(QSGBasicGeometryNode); QSG_CHECK_TYPE(QSGTransformNode); QSG_CHECK_TYPE(QSGRootNode); QSG_CHECK_TYPE(QSGOpacityNode); return QLatin1String("QSGNode"); } QString QuickInspectorFactory::name() const { return tr("Quick Scenes"); } gammaray-2.3.0/plugins/quickinspector/quickinspector.h000066400000000000000000000110131255003167400232510ustar00rootroot00000000000000/* qmlsupport.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKINSPECTOR_H #define GAMMARAY_QUICKINSPECTOR_QUICKINSPECTOR_H #include "quickinspectorinterface.h" #include #include #include class QQuickShaderEffectSource; class QAbstractItemModel; class QItemSelection; class QItemSelectionModel; class QSGNode; //class QSGBasicGeometryNode; //class QSGGeometryNode; //class QSGClipNode; //class QSGTransformNode; //class QSGRootNode; //class QSGOpacityNode; namespace GammaRay { class PropertyController; class QuickItemModel; class QuickSceneGraphModel; class QuickInspector : public QuickInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::QuickInspectorInterface) public: explicit QuickInspector(ProbeInterface *probe, QObject *parent = 0); ~QuickInspector(); public slots: void selectWindow(int index) Q_DECL_OVERRIDE; void renderScene() Q_DECL_OVERRIDE; void sendKeyEvent(int type, int key, int modifiers, const QString &text = QString(), bool autorep = false, ushort count = 1) Q_DECL_OVERRIDE; void sendMouseEvent(int type, const QPointF &localPos, int button, int buttons, int modifiers) Q_DECL_OVERRIDE; void sendWheelEvent(const QPointF &localPos, QPoint pixelDelta, QPoint angleDelta, int buttons, int modifiers) Q_DECL_OVERRIDE; void setCustomRenderMode(GammaRay::QuickInspectorInterface::RenderMode customRenderMode) Q_DECL_OVERRIDE; void checkFeatures() Q_DECL_OVERRIDE; void setSceneViewActive(bool active) Q_DECL_OVERRIDE; protected: bool eventFilter(QObject *receiver, QEvent *event) Q_DECL_OVERRIDE; private slots: void slotSceneChanged(); void sendRenderedScene(); void itemSelectionChanged(const QItemSelection &selection); void sgSelectionChanged(const QItemSelection &selection); void clientConnectedChanged(bool connected); void sgNodeDeleted(QSGNode *node); void objectSelected(QObject *object); void objectSelected(void *object, const QString &typeName); private: void selectWindow(QQuickWindow *window); void selectItem(QQuickItem *item); void selectSGNode(QSGNode *node); void registerMetaTypes(); void registerVariantHandlers(); void registerPCExtensions(); QString findSGNodeType(QSGNode *node) const; void setupPreviewSource(); QQuickItem *recursiveChiltAt(QQuickItem *parent, const QPointF &pos) const; QQuickShaderEffectSource *m_source; ProbeInterface *m_probe; QPointer m_window; QPointer m_currentItem; QSGNode *m_currentSgNode; QAbstractItemModel *m_windowModel; QuickItemModel *m_itemModel; QItemSelectionModel *m_itemSelectionModel; QuickSceneGraphModel *m_sgModel; QItemSelectionModel *m_sgSelectionModel; PropertyController *m_itemPropertyController; PropertyController *m_sgPropertyController; QImage m_currentFrame; bool m_clientViewActive; bool m_needsNewFrame; }; class QuickInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_quickinspector.json") public: explicit QuickInspectorFactory(QObject *parent = 0) : QObject(parent) { } QString name() const Q_DECL_OVERRIDE; }; } #endif gammaray-2.3.0/plugins/quickinspector/quickinspectorclient.cpp000066400000000000000000000105611255003167400250120ustar00rootroot00000000000000/* quickinspectorclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickinspectorclient.h" #include #include using namespace GammaRay; QuickInspectorClient::QuickInspectorClient(QObject *parent) : QuickInspectorInterface(parent) { } QuickInspectorClient::~QuickInspectorClient() { } void QuickInspectorClient::selectWindow(int index) { Endpoint::instance()->invokeObject(objectName(), "selectWindow", QVariantList() << index); } void QuickInspectorClient::renderScene() { Endpoint::instance()->invokeObject(objectName(), "renderScene"); } void QuickInspectorClient::sendKeyEvent(int type, int key, int modifiers, const QString &text, bool autorep, ushort count) { Endpoint::instance()->invokeObject(objectName(), "sendKeyEvent", QVariantList() << QVariant::fromValue(type) << QVariant::fromValue(key) << QVariant::fromValue(modifiers) << QVariant::fromValue(text) << QVariant::fromValue(autorep) << QVariant::fromValue(count)); } void QuickInspectorClient::sendMouseEvent(int type, const QPointF &localPos, int button, int buttons, int modifiers) { Endpoint::instance()->invokeObject(objectName(), "sendMouseEvent", QVariantList() << QVariant::fromValue(type) << QVariant::fromValue(localPos) << QVariant::fromValue(button) << QVariant::fromValue(buttons) << QVariant::fromValue(modifiers)); } void QuickInspectorClient::sendWheelEvent(const QPointF &localPos, QPoint pixelDelta, QPoint angleDelta, int buttons, int modifiers) { Endpoint::instance()->invokeObject(objectName(), "sendWheelEvent", QVariantList() << QVariant::fromValue(localPos) << QVariant::fromValue(pixelDelta) << QVariant::fromValue(angleDelta) << QVariant::fromValue(buttons) << QVariant::fromValue(modifiers)); } void QuickInspectorClient::setCustomRenderMode( GammaRay::QuickInspectorInterface::RenderMode customRenderMode) { Endpoint::instance()->invokeObject(objectName(), "setCustomRenderMode", QVariantList() << QVariant::fromValue(customRenderMode)); } void QuickInspectorClient::checkFeatures() { Endpoint::instance()->invokeObject(objectName(), "checkFeatures"); } void QuickInspectorClient::setSceneViewActive(bool active) { Endpoint::instance()->invokeObject(objectName(), "setSceneViewActive", QVariantList() << QVariant::fromValue(active)); } gammaray-2.3.0/plugins/quickinspector/quickinspectorclient.h000066400000000000000000000044341255003167400244610ustar00rootroot00000000000000/* quickinspectorclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORCLIENT_H #define GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORCLIENT_H #include "quickinspectorinterface.h" class QEvent; namespace GammaRay { class QuickInspectorClient : public QuickInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::QuickInspectorInterface) public: explicit QuickInspectorClient(QObject *parent = 0); ~QuickInspectorClient(); public slots: void selectWindow(int index) Q_DECL_OVERRIDE; void renderScene() Q_DECL_OVERRIDE; void sendKeyEvent(int type, int key, int modifiers, const QString &text, bool autorep, ushort count) Q_DECL_OVERRIDE; void sendMouseEvent(int type, const QPointF &localPos, int button, int buttons, int modifiers) Q_DECL_OVERRIDE; void sendWheelEvent(const QPointF &localPos, QPoint pixelDelta, QPoint angleDelta, int buttons, int modifiers) Q_DECL_OVERRIDE; void setCustomRenderMode(GammaRay::QuickInspectorInterface::RenderMode customRenderMode) Q_DECL_OVERRIDE; void checkFeatures() Q_DECL_OVERRIDE; void setSceneViewActive(bool active) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_QUICKINSPECTORCLIENT_H gammaray-2.3.0/plugins/quickinspector/quickinspectorinterface.cpp000066400000000000000000000043621255003167400254760ustar00rootroot00000000000000/* quickinspectorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickinspectorinterface.h" #include "transferimage.h" #include #include using namespace GammaRay; QDataStream &operator<<(QDataStream &out, QuickInspectorInterface::Features value) { out << qint32(value); return out; } QDataStream &operator>>(QDataStream &in, QuickInspectorInterface::Features &value) { qint32 t; in >> t; value = static_cast(t); return in; } QDataStream &operator<<(QDataStream &out, QuickInspectorInterface::RenderMode value) { out << qint32(value); return out; } QDataStream &operator>>(QDataStream &in, QuickInspectorInterface::RenderMode &value) { qint32 t; in >> t; value = static_cast(t); return in; } QuickInspectorInterface::QuickInspectorInterface(QObject * parent) : QObject(parent) { ObjectBroker::registerObject(this); qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); qRegisterMetaTypeStreamOperators(); } QuickInspectorInterface::~QuickInspectorInterface() { } gammaray-2.3.0/plugins/quickinspector/quickinspectorinterface.h000066400000000000000000000063171255003167400251450ustar00rootroot00000000000000/* quickinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORINTERFACE_H #define GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORINTERFACE_H #include #include #include #include #include class QImage; namespace GammaRay { class QuickInspectorInterface : public QObject { Q_OBJECT public: enum Feature { CustomRenderModes = 1 }; enum RenderMode { NormalRendering, VisualizeClipping, VisualizeOverdraw, VisualizeBatches, VisualizeChanges }; Q_ENUMS(RenderMode) Q_DECLARE_FLAGS(Features, Feature) explicit QuickInspectorInterface(QObject *parent = 0); ~QuickInspectorInterface(); public slots: virtual void selectWindow(int index) = 0; /// Ask for a new screenshot of the scene. virtual void renderScene() = 0; virtual void sendKeyEvent(int type, int key, int modifiers, const QString &text = QString(), bool autorep = false, ushort count = 1) = 0; virtual void sendMouseEvent(int type, const QPointF &localPos, int button, int buttons, int modifiers) = 0; virtual void sendWheelEvent(const QPointF &localPos, QPoint pixelDelta, QPoint angleDelta, int buttons, int modifiers) = 0; virtual void setCustomRenderMode( GammaRay::QuickInspectorInterface::RenderMode customRenderMode) = 0; virtual void checkFeatures() = 0; virtual void setSceneViewActive(bool active) = 0; signals: /// Emitted when the view has been newly rendered, for the client to request an update. void sceneChanged(); void sceneRendered(const QVariantMap &previewData); void features(GammaRay::QuickInspectorInterface::Features features); }; } Q_DECLARE_METATYPE(GammaRay::QuickInspectorInterface::Features) Q_DECLARE_METATYPE(GammaRay::QuickInspectorInterface::RenderMode) Q_DECLARE_INTERFACE(GammaRay::QuickInspectorInterface, "com.kdab.GammaRay.QuickInspectorInterface/1.0") #endif // GAMMARAY_QUICKINSPECTORINTERFACE_H gammaray-2.3.0/plugins/quickinspector/quickinspectorwidget.cpp000066400000000000000000000247011255003167400250200ustar00rootroot00000000000000/* quickinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickinspectorwidget.h" #include "quickinspectorclient.h" #include "quickclientitemmodel.h" #include "quickitemtreewatcher.h" #include "geometryextension/sggeometryextensionclient.h" #include "geometryextension/sggeometrytab.h" #include "materialextension/materialextensionclient.h" #include "materialextension/materialtab.h" #include "annotatedscenepreview.h" #include "quickitemdelegate.h" #include "transferimage.h" #include "ui_quickinspectorwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace GammaRay { class QuickSceneImageProvider : public QQuickImageProvider { public: explicit QuickSceneImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} ~QuickSceneImageProvider() {} QPixmap requestPixmap(const QString & id, QSize * size, const QSize & requestedSize) { Q_UNUSED(requestedSize); if (id == "background") { QPixmap bgPattern(20, 20); bgPattern.fill(Qt::lightGray); QPainter bgPainter(&bgPattern); bgPainter.fillRect(10, 0, 10, 10, Qt::gray); bgPainter.fillRect(0, 10, 10, 10, Qt::gray); *size = QSize(20, 20); return bgPattern; } *size = m_pixmap.size(); return m_pixmap; } void setPixmap(QPixmap pixmap) { m_pixmap = pixmap; } private: QPixmap m_pixmap; }; } using namespace GammaRay; static QObject *createQuickInspectorClient(const QString &/*name*/, QObject *parent) { return new QuickInspectorClient(parent); } static QObject *createMaterialExtension(const QString &name, QObject *parent) { return new MaterialExtensionClient(name, parent); } static QObject *createSGGeometryExtension(const QString &name, QObject *parent) { return new SGGeometryExtensionClient(name, parent); } QuickInspectorWidget::QuickInspectorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::QuickInspectorWidget), m_renderTimer(new QTimer(this)), m_sceneChangedSinceLastRequest(false), m_waitingForImage(false), m_imageProvider(new QuickSceneImageProvider), m_preview(new QQuickView) { ui->setupUi(this); ObjectBroker::registerClientObjectFactoryCallback( createQuickInspectorClient); m_interface = ObjectBroker::object(); connect(m_interface, SIGNAL(sceneChanged()), this, SLOT(sceneChanged())); connect(m_interface, SIGNAL(sceneRendered(QVariantMap)), this, SLOT(sceneRendered(QVariantMap))); ui->windowComboBox->setModel(ObjectBroker::model("com.kdab.GammaRay.QuickWindowModel")); connect(ui->windowComboBox, SIGNAL(currentIndexChanged(int)), m_interface, SLOT(selectWindow(int))); if (ui->windowComboBox->currentIndex() >= 0) { m_interface->selectWindow(ui->windowComboBox->currentIndex()); } QSortFilterProxyModel *proxy = new QuickClientItemModel(this); proxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.QuickItemModel")); proxy->setDynamicSortFilter(true); ui->itemTreeView->setModel(proxy); ui->itemTreeSearchLine->setProxy(proxy); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(proxy); ui->itemTreeView->setSelectionModel(selectionModel); ui->itemTreeView->setItemDelegate(new QuickItemDelegate(ui->itemTreeView)); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(itemSelectionChanged(QItemSelection))); connect(proxy, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex))); QSortFilterProxyModel *sgProxy = new KRecursiveFilterProxyModel(this); sgProxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.QuickSceneGraphModel")); sgProxy->setDynamicSortFilter(true); ui->sgTreeView->setModel(sgProxy); ui->sgTreeSearchLine->setProxy(sgProxy); QItemSelectionModel *sgSelectionModel = ObjectBroker::selectionModel(sgProxy); ui->sgTreeView->setSelectionModel(sgSelectionModel); connect(sgSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(itemSelectionChanged(QItemSelection))); new QuickItemTreeWatcher(ui->itemTreeView, ui->sgTreeView, this); new DeferredResizeModeSetter(ui->itemTreeView->header(), 0, QHeaderView::ResizeToContents); ui->itemPropertyWidget->setObjectBaseName("com.kdab.GammaRay.QuickItem"); ui->sgPropertyWidget->setObjectBaseName("com.kdab.GammaRay.QuickSceneGraph"); qmlRegisterType("com.kdab.GammaRay", 1, 0, "AnnotatedScenePreview"); QWidget *previewContainter = QWidget::createWindowContainer(m_preview, ui->previewTreeSplitter); previewContainter->setFocusPolicy(Qt::StrongFocus); m_preview->setResizeMode(QQuickView::SizeRootObjectToView); m_preview->engine()->addImageProvider("quicksceneprovider", m_imageProvider); m_preview->setSource(QUrl("qrc:/gammaray/plugins/quickinspector/quickpreview.qml")); m_rootItem = qobject_cast< QQuickItem *>(m_preview->rootObject()); qmlRegisterUncreatableType( "com.kdab.GammaRay", 1, 0, "QuickInspectorInterface", "Can't create. Only for enums."); m_preview->engine()->rootContext()->setContextProperty("inspectorInterface", m_interface); QTimer::singleShot(0, this, SLOT(setSplitterSizes())); m_renderTimer->setInterval(100); m_renderTimer->setSingleShot(true); connect(m_renderTimer, SIGNAL(timeout()), this, SLOT(requestRender())); connect(m_interface, SIGNAL(features(GammaRay::QuickInspectorInterface::Features)), this, SLOT(setFeatures(GammaRay::QuickInspectorInterface::Features))); m_interface->checkFeatures(); } QuickInspectorWidget::~QuickInspectorWidget() { } void QuickInspectorWidget::setSplitterSizes() { ui->previewTreeSplitter->setSizes( QList() << (ui->previewTreeSplitter->height() - ui->previewTreeSplitter->handleWidth()) / 2 << (ui->previewTreeSplitter->height() - ui->previewTreeSplitter->handleWidth()) / 2); } void QuickInspectorWidget::sceneChanged() { if (!m_renderTimer->isActive()) { m_renderTimer->start(); } } void QuickInspectorWidget::sceneRendered(const QVariantMap &previewData) { m_waitingForImage = false; if (m_rootItem) { QVariantMap data(previewData); const TransferImage transfer = data.value("rawImage").value(); data.remove("rawImage"); data.insert("image", QVariant::fromValue(transfer.image())); // unwrap for usage in QML m_rootItem->setProperty("previewData", data); } if (m_sceneChangedSinceLastRequest) { m_sceneChangedSinceLastRequest = false; sceneChanged(); } } void QuickInspectorWidget::requestRender() { if (!m_waitingForImage) { m_waitingForImage = true; m_interface->renderScene(); } else { m_sceneChangedSinceLastRequest = true; } } void QuickInspectorWidget::setFeatures(QuickInspectorInterface::Features features) { m_rootItem->setProperty("supportsCustomRenderModes", (bool)(features & QuickInspectorInterface::CustomRenderModes)); } void QuickInspectorWidget::itemSelectionChanged(const QItemSelection &selection) { if (selection.isEmpty()) { return; } const QModelIndex &index = selection.first().topLeft(); ui->itemTreeView->scrollTo(index); } void QuickInspectorWidget::itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { for (int i = topLeft.row(); i <= bottomRight.row(); i++) { const QModelIndex index = ui->itemTreeView->model()->index(i, 0, topLeft.parent()); RemoteModel::NodeStates state = index.data(RemoteModel::LoadingState).value(); if (state & RemoteModel::Empty || ~state & RemoteModel::Outdated) { continue; } QVariantAnimation *colorAnimation = new QVariantAnimation(this); colorAnimation->setProperty("index", QVariant::fromValue(QPersistentModelIndex(index))); connect(colorAnimation, SIGNAL(valueChanged(QVariant)), ui->itemTreeView->itemDelegate(), SLOT(setTextColor(QVariant))); colorAnimation->setStartValue(QColor(129, 0, 129)); colorAnimation->setEndValue(QColor(129, 0, 129, 0)); colorAnimation->setDuration(2000); colorAnimation->start(QAbstractAnimation::DeleteWhenStopped); } } void QuickInspectorUiFactory::initUi() { ObjectBroker::registerClientObjectFactoryCallback( createMaterialExtension); PropertyWidget::registerTab("material", QObject::tr("Material")); ObjectBroker::registerClientObjectFactoryCallback( createSGGeometryExtension); PropertyWidget::registerTab("sgGeometry", QObject::tr("Geometry")); } void QuickInspectorWidget::showEvent(QShowEvent* event) { QWidget::showEvent(event); m_waitingForImage = false; m_sceneChangedSinceLastRequest = true; m_interface->setSceneViewActive(true); } void QuickInspectorWidget::hideEvent(QHideEvent* event) { if (Endpoint::isConnected()) m_interface->setSceneViewActive(false); QWidget::hideEvent(event); } gammaray-2.3.0/plugins/quickinspector/quickinspectorwidget.h000066400000000000000000000055111255003167400244630ustar00rootroot00000000000000/* quickinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORWIDGET_H #define GAMMARAY_QUICKINSPECTOR_QUICKINSPECTORWIDGET_H #include #include #include #include "quickinspectorinterface.h" #include #include class QQuickItem; class QQuickView; class QTimer; class QLabel; class QImage; class QItemSelection; namespace GammaRay { class QuickSceneImageProvider; namespace Ui { class QuickInspectorWidget; } class QuickInspectorWidget : public QWidget { Q_OBJECT public: explicit QuickInspectorWidget(QWidget *parent = 0); ~QuickInspectorWidget(); private: void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; private slots: void sceneChanged(); void sceneRendered(const QVariantMap &previewData); void itemSelectionChanged(const QItemSelection &selection); void requestRender(); void setFeatures(GammaRay::QuickInspectorInterface::Features features); void setSplitterSizes(); void itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); private: QScopedPointer ui; QuickInspectorInterface *m_interface; QTimer *m_renderTimer; bool m_sceneChangedSinceLastRequest; bool m_waitingForImage; QuickSceneImageProvider *m_imageProvider; QQuickItem *m_rootItem; QQuickView *m_preview; }; class QuickInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_quickinspector.json") void initUi() Q_DECL_OVERRIDE; }; } #endif gammaray-2.3.0/plugins/quickinspector/quickinspectorwidget.ui000066400000000000000000000075141255003167400246560ustar00rootroot00000000000000 GammaRay::QuickInspectorWidget 0 0 400 300 Qt::Horizontal Qt::Vertical QTabWidget::South 0 Items 10 true Scene Graph 10 true 0 0 KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
GammaRay::PropertyWidget QWidget
ui/propertywidget.h
1
tabWidget currentChanged(int) stackedWidget setCurrentIndex(int) 188 122 381 163
gammaray-2.3.0/plugins/quickinspector/quickitemdelegate.cpp000066400000000000000000000112121255003167400242300ustar00rootroot00000000000000/* quickitemdelegate.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickitemdelegate.h" #include "quickitemmodelroles.h" #include #include #include #include #include using namespace GammaRay; QuickItemDelegate::QuickItemDelegate(QTreeView *view) : QStyledItemDelegate(view), m_view(view) { } void QuickItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { int flags = index.data(QuickItemModelRole::ItemFlags).value(); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // Disable foreground painting so we can do ourself opt.text = ""; opt.icon = QIcon(); QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter); QRect drawRect = option.rect; QColor base = option.state & QStyle::State_Selected ? option.palette.highlightedText().color() : index.data(Qt::ForegroundRole).value(); if (m_colors.contains(index.sibling(index.row(), 0))) { QColor blend = m_colors.value(index.sibling(index.row(), 0)); QColor blended = QColor::fromRgbF(base.redF() * (1 - blend.alphaF()) + blend.redF() * blend.alphaF(), base.greenF() * (1 - blend.alphaF()) + blend.greenF() * blend.alphaF(), base.blueF() * (1 - blend.alphaF()) + blend.blueF() * blend.alphaF()); painter->setPen(blended); } else { painter->setPen(base); } if (index.column() == 0) { QVector icons; icons << index.data(Qt::DecorationRole).value(); if ((flags & QuickItemModelRole::OutOfView) && (~flags & QuickItemModelRole::Invisible)) { icons << QIcon(":/gammaray/plugins/quickinspector/warning.png").pixmap(16, 16); } if (flags & QuickItemModelRole::HasActiveFocus) { icons << QIcon(":/gammaray/plugins/quickinspector/active-focus.png").pixmap(16, 16); } if (flags & QuickItemModelRole::HasFocus && ~flags & QuickItemModelRole::HasActiveFocus) { icons << QIcon(":/gammaray/plugins/quickinspector/focus.png").pixmap(16, 16); } for (int i = 0; i < icons.size(); i++) { painter->drawPixmap(drawRect.topLeft(), icons.at(i)); drawRect.setTopLeft(drawRect.topLeft() + QPoint(20, 0)); } } painter->drawText(drawRect, Qt::AlignVCenter, index.data(Qt::DisplayRole).toString()); } QSize QuickItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); QSize textSize = m_view->fontMetrics().size(Qt::TextSingleLine, index.data(Qt::DisplayRole).toString()); QSize decorationSize; if (index.column() == 0) { int flags = index.data(QuickItemModelRole::ItemFlags).value(); int icons = 1; if ((flags & QuickItemModelRole::OutOfView) && (~flags & QuickItemModelRole::Invisible)) { icons++; } if (flags & (QuickItemModelRole::HasFocus | QuickItemModelRole::HasActiveFocus)) { icons++; } decorationSize = QSize(icons * 20, 16); } return QSize(textSize.width() + decorationSize.width() + 5, qMax(textSize.height(), decorationSize.height())); } void QuickItemDelegate::setTextColor(const QVariant &textColor) { const QPersistentModelIndex index = sender()->property("index").value(); if (!index.isValid()) { return; } m_colors[index] = textColor.value(); for (int i = 0; i < m_view->model()->columnCount(); i++) { m_view->update(index.sibling(index.row(), i)); } } gammaray-2.3.0/plugins/quickinspector/quickitemdelegate.h000066400000000000000000000036371255003167400237110ustar00rootroot00000000000000/* quickitemdelegate.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKITEMDELEGATE_H #define GAMMARAY_QUICKINSPECTOR_QUICKITEMDELEGATE_H #include #include class QTreeView; namespace GammaRay { class QuickItemDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit QuickItemDelegate(QTreeView *view); public Q_SLOTS: void setTextColor(const QVariant &textColor); protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; private: QHash m_colors; QTreeView *m_view; }; } Q_DECLARE_METATYPE(QPersistentModelIndex) #endif // QUICKITEMDELEGATE_H gammaray-2.3.0/plugins/quickinspector/quickitemmodel.cpp000066400000000000000000000274401255003167400235700ustar00rootroot00000000000000/* quickitemmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickitemmodel.h" #include "quickitemmodelroles.h" #include #include #include #include #include #include #include using namespace GammaRay; QuickItemModel::QuickItemModel(QObject *parent) : ObjectModelBase(parent) { } QuickItemModel::~QuickItemModel() { } void QuickItemModel::setWindow(QQuickWindow *window) { beginResetModel(); clear(); m_window = window; populateFromItem(window->contentItem()); endResetModel(); } QVariant QuickItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QQuickItem *item = reinterpret_cast(index.internalPointer()); if (role == QuickItemModelRole::ItemFlags) { return m_itemFlags[item]; } if (role == Qt::DisplayRole && index.column() == 0) { QQmlContext *ctx = QQmlEngine::contextForObject(item); QString id = ctx ? ctx->nameForObject(item) : ""; if (!id.isEmpty()) { return id; } } return dataForObject(item, index, role); } int QuickItemModel::rowCount(const QModelIndex &parent) const { if (parent.column() == 1) { return 0; } QQuickItem *parentItem = reinterpret_cast(parent.internalPointer()); return m_parentChildMap.value(parentItem).size(); } QModelIndex QuickItemModel::parent(const QModelIndex &child) const { QQuickItem *childItem = reinterpret_cast(child.internalPointer()); return indexForItem(m_childParentMap.value(childItem)); } QModelIndex QuickItemModel::index(int row, int column, const QModelIndex &parent) const { QQuickItem *parentItem = reinterpret_cast(parent.internalPointer()); const QVector children = m_parentChildMap.value(parentItem); if (row < 0 || column < 0 || row >= children.size() || column >= columnCount()) { return QModelIndex(); } return createIndex(row, column, children.at(row)); } QMap QuickItemModel::itemData(const QModelIndex &index) const { QMap d = QAbstractItemModel::itemData(index); d.insert(QuickItemModelRole::ItemFlags, data(index, QuickItemModelRole::ItemFlags)); return d; } void QuickItemModel::clear() { for (QHash::const_iterator it = m_childParentMap.constBegin(); it != m_childParentMap.constEnd(); ++it) { disconnect(it.key(), 0, this, 0); } m_childParentMap.clear(); m_parentChildMap.clear(); } void QuickItemModel::populateFromItem(QQuickItem *item) { if (!item) { return; } connectItem(item); updateItemFlags(item); m_childParentMap[item] = item->parentItem(); m_parentChildMap[item->parentItem()].push_back(item); foreach (QQuickItem *child, item->childItems()) { populateFromItem(child); } QVector &children = m_parentChildMap[item->parentItem()]; std::sort(children.begin(), children.end()); } void QuickItemModel::connectItem(QQuickItem *item) { connect(item, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(itemReparented())); connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(itemWindowChanged())); connect(item, SIGNAL(visibleChanged()), this, SLOT(itemUpdated())); connect(item, SIGNAL(focusChanged(bool)), this, SLOT(itemUpdated())); connect(item, SIGNAL(activeFocusChanged(bool)), this, SLOT(itemUpdated())); connect(item, SIGNAL(widthChanged()), this, SLOT(itemUpdated())); connect(item, SIGNAL(heightChanged()), this, SLOT(itemUpdated())); connect(item, SIGNAL(xChanged()), this, SLOT(itemUpdated())); connect(item, SIGNAL(yChanged()), this, SLOT(itemUpdated())); item->installEventFilter(new QuickEventMonitor(this)); } void QuickItemModel::disconnectItem(QQuickItem *item) { disconnect(item, 0, this, 0); } QModelIndex QuickItemModel::indexForItem(QQuickItem *item) const { if (!item) { return QModelIndex(); } QQuickItem *parent = m_childParentMap.value(item); const QModelIndex parentIndex = indexForItem(parent); if (!parentIndex.isValid() && parent) { return QModelIndex(); } const QVector &siblings = m_parentChildMap[parent]; QVector::const_iterator it = std::lower_bound(siblings.constBegin(), siblings.constEnd(), item); if (it == siblings.constEnd() || *it != item) { return QModelIndex(); } const int row = std::distance(siblings.constBegin(), it); return index(row, 0, parentIndex); } void QuickItemModel::objectAdded(QObject *obj) { Q_ASSERT(thread() == QThread::currentThread()); QQuickItem *item = qobject_cast(obj); addItem(item); } void QuickItemModel::addItem(QQuickItem *item) { if (!item) { return; } if (!item->window()) { return; // item not (yet) added to a scene } if (item->window() != m_window) { return; // item for a different scene } if (m_childParentMap.contains(item)) { return; // already known } QQuickItem *parentItem = item->parentItem(); if (parentItem) { // add parent first, if we don't know that yet if (!m_childParentMap.contains(parentItem)) { objectAdded(parentItem); } } connectItem(item); const QModelIndex index = indexForItem(parentItem); Q_ASSERT(index.isValid() || !parentItem); QVector &children = m_parentChildMap[parentItem]; QVector::iterator it = std::lower_bound(children.begin(), children.end(), item); const int row = std::distance(children.begin(), it); beginInsertRows(index, row, row); children.insert(it, item); m_childParentMap.insert(item, parentItem); endInsertRows(); } void QuickItemModel::objectRemoved(QObject *obj) { Q_ASSERT(thread() == QThread::currentThread()); QQuickItem *item = static_cast(obj); // this is fine, we must not deref // obj/item at this point anyway removeItem(item, true); } void QuickItemModel::removeItem(QQuickItem *item, bool danglingPointer) { if (!m_childParentMap.contains(item)) { // not an item of our current scene Q_ASSERT(!m_parentChildMap.contains(item)); return; } if (item && !danglingPointer) { disconnectItem(item); } QQuickItem *parentItem = m_childParentMap[item]; const QModelIndex parentIndex = indexForItem(parentItem); if (parentItem && !parentIndex.isValid()) { return; } QVector &siblings = m_parentChildMap[parentItem]; QVector::iterator it = std::lower_bound(siblings.begin(), siblings.end(), item); if (it == siblings.end() || *it != item) { return; } const int row = std::distance(siblings.begin(), it); beginRemoveRows(parentIndex, row, row); siblings.erase(it); doRemoveSubtree(item, danglingPointer); endRemoveRows(); } void QuickItemModel::doRemoveSubtree(QQuickItem *item, bool danglingPointer) { m_childParentMap.remove(item); m_parentChildMap.remove(item); if (!danglingPointer) { foreach (QQuickItem *child, item->childItems()) { doRemoveSubtree(child, false); } } } void QuickItemModel::itemReparented() { QQuickItem *item = qobject_cast(sender()); if (!item->parentItem()) { // Item was not deleted, but removed from the scene. removeItem(item, false); return; } Q_ASSERT(item && item->window() == m_window); QQuickItem *sourceParent = m_childParentMap.value(item); Q_ASSERT(sourceParent); const QModelIndex sourceParentIndex = indexForItem(sourceParent); QVector &sourceSiblings = m_parentChildMap[sourceParent]; QVector::iterator sit = std::lower_bound(sourceSiblings.begin(), sourceSiblings.end(), item); Q_ASSERT(sit != sourceSiblings.end() && *sit == item); const int sourceRow = std::distance(sourceSiblings.begin(), sit); QQuickItem *destParent = item->parentItem(); Q_ASSERT(destParent); const QModelIndex destParentIndex = indexForItem(destParent); QVector &destSiblings = m_parentChildMap[destParent]; QVector::iterator dit = std::lower_bound(destSiblings.begin(), destSiblings.end(), item); const int destRow = std::distance(destSiblings.begin(), dit); beginMoveRows(sourceParentIndex, sourceRow, sourceRow, destParentIndex, destRow); destSiblings.insert(dit, item); sourceSiblings.erase(sit); m_childParentMap.insert(item, destParent); endMoveRows(); } void QuickItemModel::itemWindowChanged() { QQuickItem *item = qobject_cast(sender()); Q_ASSERT(item && (!item->window() || item->window() != m_window)); removeItem(item); } void QuickItemModel::itemUpdated() { QQuickItem *item = qobject_cast(sender()); recursivelyUpdateItem(item); } void QuickItemModel::recursivelyUpdateItem(QQuickItem *item) { int oldFlags = m_itemFlags[item]; updateItemFlags(item); if (oldFlags != m_itemFlags[item]) { updateItem(item); } foreach (QQuickItem *child, item->childItems()) { recursivelyUpdateItem(child); } } void QuickItemModel::updateItem(QQuickItem *item) { if (!item || item->window() != m_window) { return; } const QModelIndex left = indexForItem(item); const QModelIndex right = left.sibling(left.row(), columnCount() - 1); emit dataChanged(left, right); } void QuickItemModel::updateItemFlags(QQuickItem *item) { QQuickItem *ancestor = item->parentItem(); bool outOfView = false; while (ancestor && ancestor != m_window->contentItem()) { QPointF pos = ancestor->mapFromItem(item, QPointF(0, 0)); if ((ancestor->parentItem() == m_window->contentItem() || ancestor->clip()) && (-pos.x() > item->width() || -pos.y() > item->height() || pos.x() > ancestor->width() || pos.y() > ancestor->height())) { outOfView = true; break; } ancestor = ancestor->parentItem(); } m_itemFlags[item] = (!item->isVisible() || item->opacity() == 0 ? QuickItemModelRole::Invisible : QuickItemModelRole::None) | (item->width() == 0 || item->height() == 0 ? QuickItemModelRole::ZeroSize : QuickItemModelRole::None) | (outOfView ? QuickItemModelRole::OutOfView : QuickItemModelRole::None) | (item->hasFocus() ? QuickItemModelRole::HasFocus : QuickItemModelRole::None) | (item->hasActiveFocus() ? QuickItemModelRole::HasActiveFocus : QuickItemModelRole::None); } QuickEventMonitor::QuickEventMonitor(QuickItemModel *parent) : QObject(parent), m_model(parent) { } bool QuickEventMonitor::eventFilter(QObject *obj, QEvent *event) { if (event->type() != QEvent::DeferredDelete && event->type() != QEvent::Destroy) { // exclude some unsafe event types m_model->updateItem(qobject_cast(obj)); } return false; } gammaray-2.3.0/plugins/quickinspector/quickitemmodel.h000066400000000000000000000073211255003167400232310ustar00rootroot00000000000000/* quickitemmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKITEMMODEL_H #define GAMMARAY_QUICKINSPECTOR_QUICKITEMMODEL_H #include #include #include #include class QSignalMapper; class QQuickItem; class QQuickWindow; namespace GammaRay { /** QQ2 item tree model. */ class QuickItemModel : public ObjectModelBase { Q_OBJECT public: explicit QuickItemModel(QObject *parent = 0); ~QuickItemModel(); void setWindow(QQuickWindow *window); QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE; QMap< int, QVariant > itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; public slots: void objectAdded(QObject *obj); void objectRemoved(QObject *obj); private slots: void itemReparented(); void itemWindowChanged(); void itemUpdated(); private: friend class QuickEventMonitor; void updateItem(QQuickItem *item); void recursivelyUpdateItem(QQuickItem *item); void updateItemFlags(QQuickItem *item); void clear(); void populateFromItem(QQuickItem *item); /// Track all changes to item @p item in this model (parentChanged, windowChanged, ...) void connectItem(QQuickItem *item); /// Untrack item @p item void disconnectItem(QQuickItem *item); QModelIndex indexForItem(QQuickItem *item) const; /// Add item @p item to this model void addItem(QQuickItem *item); /// Remove item @p item from this model. /// Set @p danglingPointer to true if the item has already been destructed void removeItem(QQuickItem *item, bool danglingPointer = false); /** * Remove item @p item from the internal data set. * This function won't cause rowsRemoved to be emitted. * Set @p danglingPointer to true if the item has already been destructed. */ void doRemoveSubtree(QQuickItem *item, bool danglingPointer = false); QPointer m_window; QHash m_childParentMap; QHash > m_parentChildMap; QHash m_itemFlags; }; class QuickEventMonitor : public QObject { Q_OBJECT public: explicit QuickEventMonitor(QuickItemModel *parent); protected: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; private: QuickItemModel *m_model; }; } #endif // GAMMARAY_QUICKITEMMODEL_H gammaray-2.3.0/plugins/quickinspector/quickitemmodelroles.h000066400000000000000000000032301255003167400242710ustar00rootroot00000000000000/* quickitemmodelroles.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKITEMMODELROLES_H #define GAMMARAY_QUICKINSPECTOR_QUICKITEMMODELROLES_H #include namespace GammaRay { /** Model roles shared between client and server. */ namespace QuickItemModelRole { enum Roles { ItemFlags = ObjectModel::UserRole }; enum ItemFlag { None = 0, Invisible = 1, ZeroSize = 2, OutOfView = 4, HasFocus = 8, HasActiveFocus = 16, JustRecievedEvent = 32 }; } } Q_DECLARE_METATYPE(GammaRay::QuickItemModelRole::ItemFlag) #endif gammaray-2.3.0/plugins/quickinspector/quickitemtreewatcher.cpp000066400000000000000000000053411255003167400250010ustar00rootroot00000000000000/* quickitemtreewatcher.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickitemtreewatcher.h" #include "quickitemmodelroles.h" #include #include #include using namespace GammaRay; QuickItemTreeWatcher::QuickItemTreeWatcher(QTreeView *itemView, QTreeView *sgView, QObject *parent) : QObject(parent), m_itemView(itemView), m_sgView(sgView) { connect(itemView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(itemModelRowsInserted(QModelIndex,int,int))); connect(sgView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sgModelRowsInserted(QModelIndex,int,int))); } QuickItemTreeWatcher::~QuickItemTreeWatcher() { } void QuickItemTreeWatcher::itemModelRowsInserted(const QModelIndex &parent, int start, int end) { for (int row = start; row <= end; ++row) { const QModelIndex index = m_itemView->model()->index(row, 0, parent); const bool invisible = index.data(QuickItemModelRole::ItemFlags).value() & (QuickItemModelRole::Invisible | QuickItemModelRole::ZeroSize); const int siblingCount = m_itemView->model()->rowCount(parent); if (!invisible && siblingCount < 5) { m_itemView->setExpanded(index, true); } } } void QuickItemTreeWatcher::sgModelRowsInserted(const QModelIndex &parent, int start, int end) { for (int row = start; row <= end; ++row) { const QModelIndex index = m_sgView->model()->index(row, 0, parent); const int siblingCount = m_sgView->model()->rowCount(parent); if (siblingCount < 5) { m_sgView->setExpanded(index, true); } } m_sgView->resizeColumnToContents(0); } gammaray-2.3.0/plugins/quickinspector/quickitemtreewatcher.h000066400000000000000000000035021255003167400244430ustar00rootroot00000000000000/* quickitemtreewatcher.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKITEMTREEWATCHER_H #define GAMMARAY_QUICKINSPECTOR_QUICKITEMTREEWATCHER_H #include class QModelIndex; class QTreeView; namespace GammaRay { /** Auto-expand the visible item sub-tree. */ class QuickItemTreeWatcher : public QObject { Q_OBJECT public: explicit QuickItemTreeWatcher(QTreeView *view, QTreeView *sgView, QObject *parent = 0); ~QuickItemTreeWatcher(); private slots: void itemModelRowsInserted(const QModelIndex &parent, int start, int end); void sgModelRowsInserted(const QModelIndex &parent, int start, int end); private: QTreeView *m_itemView; QTreeView *m_sgView; }; } #endif // GAMMARAY_QUICKITEMTREEWATCHER_H gammaray-2.3.0/plugins/quickinspector/quickscenegraphmodel.cpp000066400000000000000000000223651255003167400247520ustar00rootroot00000000000000/* quickscenegraphmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quickscenegraphmodel.h" #include #include "quickitemmodelroles.h" #include #include #include #include Q_DECLARE_METATYPE(QSGNode*) using namespace GammaRay; QuickSceneGraphModel::QuickSceneGraphModel(QObject *parent) : ObjectModelBase(parent), m_rootNode(0) { } QuickSceneGraphModel::~QuickSceneGraphModel() { } void QuickSceneGraphModel::setWindow(QQuickWindow *window) { beginResetModel(); clear(); if (m_window) { disconnect(window, SIGNAL(beforeRendering()), this, SLOT(updateSGTree())); } m_window = window; QQuickItem *item = window->contentItem(); QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); m_rootNode = itemPriv->itemNode(); while (m_rootNode->parent()) { // Ensure that we really get the very root node. m_rootNode = m_rootNode->parent(); } updateSGTree(); connect(window, SIGNAL(beforeRendering()), this, SLOT(updateSGTree())); endResetModel(); } void QuickSceneGraphModel::updateSGTree() { QQuickItem *item = m_window->contentItem(); QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); QSGNode *rootNode = itemPriv->itemNode(); while (rootNode->parent()) { // Ensure that we really get the very root node. rootNode = rootNode->parent(); } m_oldChildParentMap = m_childParentMap; m_oldParentChildMap = m_parentChildMap; m_childParentMap = QHash(); m_parentChildMap = QHash >(); m_childParentMap[m_rootNode] = 0; m_parentChildMap[0].append(m_rootNode); populateFromNode(m_rootNode); collectItemNodes(m_window->contentItem()); } QVariant QuickSceneGraphModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QSGNode *node = reinterpret_cast(index.internalPointer()); if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::addressToString(node); } else if (index.column() == 1) { switch (node->type()) { case QSGNode::BasicNodeType: return "Node"; case QSGNode::GeometryNodeType: return "Geometry Node"; case QSGNode::TransformNodeType: return "Transform Node"; case QSGNode::ClipNodeType: return "Clip Node"; case QSGNode::OpacityNodeType: return "Opacity Node"; case QSGNode::RootNodeType: return "Root Node"; case QSGNode::RenderNodeType: return "Render Node"; } } } else if (role == ObjectModel::ObjectRole) { return QVariant::fromValue(node); } return QVariant(); } int QuickSceneGraphModel::rowCount(const QModelIndex &parent) const { if (parent.column() == 1) { return 0; } QSGNode *parentNode = reinterpret_cast(parent.internalPointer()); return m_parentChildMap.value(parentNode).size(); } QModelIndex QuickSceneGraphModel::parent(const QModelIndex &child) const { QSGNode *childNode = reinterpret_cast(child.internalPointer()); return indexForNode(m_childParentMap.value(childNode)); } QModelIndex QuickSceneGraphModel::index(int row, int column, const QModelIndex &parent) const { QSGNode *parentNode = reinterpret_cast(parent.internalPointer()); const QVector children = m_parentChildMap.value(parentNode); if (row < 0 || column < 0 || row >= children.size() || column >= columnCount()) { return QModelIndex(); } return createIndex(row, column, children.at(row)); } void QuickSceneGraphModel::clear() { m_childParentMap.clear(); m_parentChildMap.clear(); } // indexForNode() is expensive, so only use it when really needed #define GET_INDEX if (!hasMyIndex) { myIndex = indexForNode(node); hasMyIndex = true; } void QuickSceneGraphModel::populateFromNode(QSGNode *node) { if (!node) { return; } QVector &childList = m_parentChildMap[node]; QVector &oldChildList = m_oldParentChildMap[node]; QVector newChildList; newChildList.reserve(node->childCount()); for (QSGNode *childNode = node->firstChild(); childNode; childNode = childNode->nextSibling()) { newChildList.append(childNode); } QModelIndex myIndex; // don't call indexForNode(node) here yet, in the common case of few changes we waste a lot of time here bool hasMyIndex = false; std::sort(newChildList.begin(), newChildList.end()); QVector::iterator i = oldChildList.begin(); QVector::const_iterator j = newChildList.constBegin(); while (i != oldChildList.end() && j != newChildList.constEnd()) { if (*i < *j) { // We don't have to do anything but inform the client about the change GET_INDEX beginRemoveRows(myIndex, childList.size(), childList.size()); endRemoveRows(); emit nodeDeleted(*i); ++i; } else if (*i > *j) { // Add to new list and inform the client about the change GET_INDEX beginInsertRows(myIndex, childList.size(), childList.size()); m_childParentMap.insert(*j, node); childList.append(*j); endInsertRows(); populateFromNode(*j); ++j; } else { // Adopt to new list, without informing the client (as nothing really changed) m_childParentMap.insert(*j, node); childList.append(*j); populateFromNode(*j); ++j; ++i; } } if (i == oldChildList.end() && j != newChildList.constEnd()) { // Add remaining new items to list and inform the client GET_INDEX beginInsertRows(myIndex, childList.size(), childList.size() + std::distance(j, newChildList.constEnd()) - 1); for (;j != newChildList.constEnd(); ++j) { m_childParentMap.insert(*j, node); childList.append(*j); populateFromNode(*j); } endInsertRows(); } else if (i != oldChildList.end()) { // Inform the client about the removed rows GET_INDEX beginRemoveRows(myIndex, childList.size(), childList.size() + std::distance(i, oldChildList.end()) - 1); endRemoveRows(); for (; i != oldChildList.end(); ++i) { emit nodeDeleted(*i); } } } #undef GET_INDEX void QuickSceneGraphModel::collectItemNodes(QQuickItem *item) { if (!item) { return; } QSGNode *itemNode = QQuickItemPrivate::get(item)->itemNode(); m_itemItemNodeMap[item] = itemNode; m_itemNodeItemMap[itemNode] = item; foreach (QQuickItem *child, item->childItems()) { collectItemNodes(child); } } QModelIndex QuickSceneGraphModel::indexForNode(QSGNode *node) const { if (!node) { return QModelIndex(); } QSGNode *parent = m_childParentMap.value(node); const QModelIndex parentIndex = indexForNode(parent); if (!parentIndex.isValid() && parent) { return QModelIndex(); } const QVector &siblings = m_parentChildMap[parent]; QVector::const_iterator it = std::lower_bound(siblings.constBegin(), siblings.constEnd(), node); if (it == siblings.constEnd() || *it != node) { return QModelIndex(); } const int row = std::distance(siblings.constBegin(), it); return index(row, 0, parentIndex); } QSGNode *QuickSceneGraphModel::sgNodeForItem(QQuickItem *item) const { return m_itemItemNodeMap[item]; } QQuickItem *QuickSceneGraphModel::itemForSgNode(QSGNode *node) const { while (node && !m_itemNodeItemMap.contains(node)) { // If there's no entry for node, take its parent node = m_childParentMap[node]; } return m_itemNodeItemMap[node]; } bool QuickSceneGraphModel::verifyNodeValidity(QSGNode *node) { if (node == m_rootNode) return true; QQuickItem *item = itemForSgNode(node); QSGNode *itemNode = QQuickItemPrivate::get(item)->itemNode(); bool valid = itemNode == node || recursivelyFindChild(itemNode, node); if (!valid) { // The tree got dirty without us noticing. Expecting more to be invalid, // so update the whole tree to ensure it's current. setWindow(m_window); } return valid; } bool QuickSceneGraphModel::recursivelyFindChild(QSGNode *root, QSGNode *child) const { for (QSGNode *childNode = root->firstChild(); childNode; childNode = childNode->nextSibling()) { if (childNode == child || recursivelyFindChild(childNode, child)) { return true; } } return false; } gammaray-2.3.0/plugins/quickinspector/quickscenegraphmodel.h000066400000000000000000000056051255003167400244150ustar00rootroot00000000000000/* quickscenegraphmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_QUICKINSPECTOR_QUICKSCENEGRAPHMODEL_H #define GAMMARAY_QUICKINSPECTOR_QUICKSCENEGRAPHMODEL_H #include #include "core/objectmodelbase.h" #include #include #include class QSGNode; class QQuickItem; class QQuickWindow; namespace GammaRay { /** QQ2 scene graph model. */ class QuickSceneGraphModel : public ObjectModelBase { Q_OBJECT public: explicit QuickSceneGraphModel(QObject *parent = 0); ~QuickSceneGraphModel(); void setWindow(QQuickWindow *window); QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE; QModelIndex indexForNode(QSGNode *node) const; QSGNode *sgNodeForItem(QQuickItem *item) const; QQuickItem *itemForSgNode(QSGNode *node) const; bool verifyNodeValidity(QSGNode *node); signals: void nodeDeleted(QSGNode *node); private slots: void updateSGTree(); private: void clear(); void populateFromNode(QSGNode *node); void collectItemNodes(QQuickItem *item); bool recursivelyFindChild(QSGNode *root, QSGNode *child) const; QPointer m_window; QSGNode *m_rootNode; QHash m_childParentMap; QHash > m_parentChildMap; QHash m_oldChildParentMap; QHash > m_oldParentChildMap; QHash m_itemItemNodeMap; QHash m_itemNodeItemMap; }; } #endif // GAMMARAY_QUICKSCENEGRAPHMODEL_H gammaray-2.3.0/plugins/quickinspector/resources/000077500000000000000000000000001255003167400220535ustar00rootroot00000000000000gammaray-2.3.0/plugins/quickinspector/resources/active-focus.png000066400000000000000000000013711255003167400251530ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<vIDAT8Ť•RKhQ=ďe’ţ’ŤÄŽ•* ’&”4Ó`Z©hÍ®ÄVÜua!˛(ŕ•;Q±¤.B v“nŞR¬ݦC)JĹM*Q“LL?“ĐtćąŔ-Řgsď=÷Î{„1FpLMMµfłŮ/Ś1Ką\ö“Ă,đz˝§AXłŮlrGGÇn2™PĄKUŐűMčĹŞŞÎ †ńh4šŻ×űÚl6SJ/ő÷÷ż0żşşúHż€kŘfŚÍ †ńéééµFłR©Üt8?fff&q(DŁŃ!äĽ^ ڱËFŁqţ qcü‹ˇPČ^Ôođ7e]]ç‡Í-gIEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/active-focus.svg000066400000000000000000000471671255003167400252030ustar00rootroot00000000000000 image/svg+xml gammaray-2.3.0/plugins/quickinspector/resources/focus.png000066400000000000000000000013261255003167400237020ustar00rootroot00000000000000‰PNG  IHDRó˙abKGD˙˙˙ ˝§“ pHYs × ×B(›xtIMEŢÂVŐcIDAT8Ëť’˝kŰPĹďÓ‡ĄĘ`2Ô‘1©;´1ŮȦB†Ą)tHI·â5ÂSţ•@čŇ­-CˇŇ%›SCU»M‘‹cY&Ž0–Ëúş]#ĄMďx¸żĂ9÷=wśťťĆ0Ś×ł,ë=}x}}}eٲ,ËŢňň˛3 ňԿ’$Ąyž•Éd\QŻMÓĽ7™L†$ş´±±ÁÚ¶ý‚ă¸!}ß=ĎóĂ0&‰Ĺ­­­źŽă˝^o©Ýn“ĂĂĂ7LÔŕęęę9ÇqCDteYöVWWm۶]×’$5 !pyyžžž˘ oć (Š˘jµÚG×uźv:ťĄÍÍÍ~.—łúý>w||ü`:ťľ;99ńćŽ(ŠâŁt:m™¦yÝív»‚ \7Ťl6›ťÄb1¬V«©‹‹‹¦¦i­[†ŘŢŢfWVV,Ëúîy^imm­qvv†¦iăńx§Őjĺ‹ĹâŘqZ×ő¸iš?f©Ea1†N©Tš"˘z~~ţěvˇ^ŻGŁŃ磣Łű™LfDQÔB45òl°»»;ŽhÍBˇđ¸P(ČŞŞ~¨ŐjmBČb˝^OŇ4=w7şZ­Î˝·˘(<Ďó Ë˛Š˘(>‘$I×u=4 ŁË˛¬äű~Ě0 mV! W*‚^2™dUUýŔ0Ě7˲^ćóů‡ăń8îűţ—ą ‚hš†ýý} \.{˝^ÓuÝb*•*AđKÓ´9Yźěíí…·Ú`0 są|úÓźU@DŚÂ7Z@Ó´˙3•J%®( ˙·˝ßă”0(yÓ‰ĺIEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/focus.svg000066400000000000000000000474531255003167400237300ustar00rootroot00000000000000 image/svg+xml gammaray-2.3.0/plugins/quickinspector/resources/measure-pixels.png000066400000000000000000000005641255003167400255310ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<ńIDAT8ŤĄ“MjĂ0…ż‘mü·i Á %ɲ)ä&=GĎŇ®COă…Ź*K]dĽ¨i‰Zš÷ŢüIŚ‘5áäŤHŠŕ'ţVU/Ŕh‰1˛<€X~gü- ˘Ş—iš\–e`Ç׾ď?—•‡a¨ş®{ůEQ<śĽ÷Ŕ8Ő/T–?˙dw quickpreview.qml focus.png warning.png active-focus.png visualize-clipping.png visualize-overdraw.png visualize-batches.png visualize-changes.png measure-pixels.png redirect-input.png move-preview.png gammaray-2.3.0/plugins/quickinspector/resources/quickpreview.qml000066400000000000000000000506121255003167400253100ustar00rootroot00000000000000/* quickpreview.qml This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 import com.kdab.GammaRay 1.0 Image { id: root source: "image://quicksceneprovider/background" fillMode: Image.Tile property alias previewData: image.previewData property bool isFirstFrame: true property bool supportsCustomRenderModes: true focus: true Keys.onPressed: { // event-forwarding if (mouseToolGroup.current == moveModeButton && event.modifiers == Qt.ControlModifier) { mouseToolGroup.current = measureModeButton; mouseToolGroup.modifierDriven = true; } else if (mouseToolGroup.current == moveModeButton && event.modifiers == Qt.ShiftModifier) { mouseToolGroup.current = redirectInputModeButton; mouseToolGroup.modifierDriven = true; } else { inspectorInterface.sendKeyEvent(6, event.key, event.modifiers, event.text, event.isAutoRepeat, event.count); } } Keys.onReleased: { // event-forwarding if (mouseToolGroup.modifierDriven == true && mouseToolGroup.current == measureModeButton && event.key == Qt.Key_Control || mouseToolGroup.modifierDriven == true && mouseToolGroup.current == redirectInputModeButton && event.key == Qt.Key_Shift || event.key == Qt.Key_Escape) { mouseToolGroup.current = moveModeButton; mouseToolGroup.modifierDriven = false; } else { inspectorInterface.sendKeyEvent(7, event.key, event.modifiers, event.text, event.isAutoRepeat, event.count); } } Component { id: buttonStyle ButtonStyle { id: styleEl background: Rectangle { color: styleEl.control.hovered ? "#22ffffff" : "transparent" border.color: "grey" } label: Text { color: "grey" text: styleEl.control.text horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } // Toolbar (top-left) Rectangle { color: "#aa333333" border.color: "grey" width: toolbarRow.width + 8; height: toolbarRow.height x: 5; y: 5; z: 1 radius: 4 visible: toolbarRow.width Row { id: toolbarRow x: 4 ExclusiveGroup { id: renderModeGroup property QtObject oldCurrent } ExclusiveGroup { id: mouseToolGroup property bool modifierDriven: false } ToolButton { id: clippingButton height: 20 visible: supportsCustomRenderModes exclusiveGroup: renderModeGroup checkable: true iconSource: "qrc:///gammaray/plugins/quickinspector/visualize-clipping.png" tooltip: qsTr("Visualize Clipping
" + "Items with the property clip set to true, will cut off their and their " + "children's rendering at the items' bounds. While this is a handy feature it " + "comes with quite some cost, like disabling some performance optimizations.
" + "With this tool enabled the QtQuick renderer highlights items, that have clipping " + "enabled, so you can check for items, that have clipping enabled unnecessarily. " + "

Note: The visualization happens on the application, not in the " + "GammaRay preview panel.") onClicked: { if (renderModeGroup.oldCurrent == clippingButton) renderModeGroup.current = null; inspectorInterface.setCustomRenderMode(checked ? QuickInspectorInterface.VisualizeClipping : QuickInspectorInterface.NormalRendering); renderModeGroup.oldCurrent = renderModeGroup.current; } } ToolButton { id: overdrawButton height: 20 visible: supportsCustomRenderModes exclusiveGroup: renderModeGroup checkable: true iconSource: "qrc:///gammaray/plugins/quickinspector/visualize-overdraw.png" tooltip: qsTr("Visualize Overdraw
" + "The QtQuick renderer doesn't detect if an item is obscured by another " + "opaque item, is completely outside the scene or outside a clipped ancestor and " + "thus doesn't need to be rendered. You thus need to take care of setting " + "visible: false for hidden items, yourself.
" + "With this tool enabled the QtQuick renderer draws a 3D-Box visualizing the " + "layers of items that are drawn." + "

Note: The visualization happens on the application, not in the " + "GammaRay preview panel.") onClicked: { if (renderModeGroup.oldCurrent == overdrawButton) renderModeGroup.current = null; inspectorInterface.setCustomRenderMode(checked ? QuickInspectorInterface.VisualizeOverdraw : QuickInspectorInterface.NormalRendering); renderModeGroup.oldCurrent = renderModeGroup.current; } } ToolButton { id: batchesButton height: 20 visible: supportsCustomRenderModes exclusiveGroup: renderModeGroup checkable: true iconSource: "qrc:///gammaray/plugins/quickinspector/visualize-batches.png" tooltip: qsTr("Visualize Batches
" + "Where a traditional 2D API, such as QPainter, Cairo or Context2D, is written to " + "handle thousands of individual draw calls per frame, OpenGL is a pure hardware " + "API and performs best when the number of draw calls is very low and state " + "changes are kept to a minimum. Therefore the QtQuick renderer combines the " + "rendering of similar items into single batches.
" + "Some settings (like clip: true) will cause the batching to fail, though, " + "causing items to be rendered separately. With this tool enabled the QtQuick " + "renderer visualizes those batches, by drawing all items that are batched using " + "the same color. The fewer colors you see in this mode the better." + "

Note: The visualization happens on the application, not in the " + "GammaRay preview panel.") onClicked: { if (renderModeGroup.oldCurrent == batchesButton) renderModeGroup.current = null; inspectorInterface.setCustomRenderMode(checked ? QuickInspectorInterface.VisualizeBatches : QuickInspectorInterface.NormalRendering); renderModeGroup.oldCurrent = renderModeGroup.current; } } ToolButton { id: changesButton height: 20 visible: supportsCustomRenderModes exclusiveGroup: renderModeGroup checkable: true iconSource: "qrc:///gammaray/plugins/quickinspector/visualize-changes.png" tooltip: qsTr("Visualize Changes
" + "The QtQuick scene is only repainted, if some item changes in a visual manner. " + "Unnecessary repaints can have a bad impact on the performance. With this tool " + "enabled, the QtQuick renderer will thus on each repaint highlight the item(s), " + "that caused the repaint." + "

Note: The visualization happens on the application, not in the " + "GammaRay preview panel.") onClicked: { if (renderModeGroup.oldCurrent == changesButton) renderModeGroup.current = null; inspectorInterface.setCustomRenderMode(checked ? QuickInspectorInterface.VisualizeChanges : QuickInspectorInterface.NormalRendering); renderModeGroup.oldCurrent = renderModeGroup.current; } } Item { width: 5; height: parent.height - 4 anchors.verticalCenter: parent.verticalCenter Rectangle { width: 1; height: parent.height anchors.horizontalCenter: parent.horizontalCenter color: "grey" } } ToolButton { id: moveModeButton height: 20 checkable: true checked: true exclusiveGroup: mouseToolGroup iconSource: "qrc:///gammaray/plugins/quickinspector/move-preview.png" tooltip: qsTr("Move preview
" + "Default mode. Click and drag to move the preview. Won't impact the original " + "application in any way. ") } ToolButton { id: measureModeButton height: 20 checkable: true exclusiveGroup: mouseToolGroup iconSource: "qrc:///gammaray/plugins/quickinspector/measure-pixels.png" tooltip: qsTr("Measure pixel-sizes (Ctrl)
" + "Choose this mode, click somewhere and drag to measure the distance between the " + "point you clicked and the point where your mouse pointer is. (Measured in scene " + "coordinates).") } ToolButton { id: redirectInputModeButton height: 20 checkable: true exclusiveGroup: mouseToolGroup iconSource: "qrc:///gammaray/plugins/quickinspector/redirect-input.png" tooltip: qsTr("Redirect Input (Shift)
" + "In this mode all mouse input is redirected directly to the original application," + "so you can control the application directly from within GammaRay.") } } } // Text item (top-right) Rectangle { color: "#aa333333" width: overlayText.width; height: overlayText.height anchors { top: parent.top; right: rightRuler.left; margins: 5 } radius: 3 z: 1 Text { id: overlayText color: "lightgrey" } } // Scene preview Flickable { id: sceneFlickable anchors.fill: parent contentWidth: image.width contentHeight: image.height boundsBehavior: Flickable.StopAtBounds AnnotatedScenePreview { id: image anchors.centerIn: parent margin { width: root.width; height: root.height } onPreviewDataChanged: { // Align image to center if (isFirstFrame) { sceneFlickable.contentX = -(root.width - sceneFlickable.contentWidth - rightRuler.width) / 2; sceneFlickable.contentY = -(root.height - sceneFlickable.contentHeight - bottomRuler.height) / 2; isFirstFrame = false; } } function zoomIn(zoomToX, zoomToY) { var oldZoom = zoom; zoom = zoom < 1 ? 1 / (1 / zoom - 1) : zoom + 1; sceneFlickable.contentX -= zoomToX * (1 - zoom / oldZoom); sceneFlickable.contentY -= zoomToY * (1 - zoom / oldZoom); } function zoomOut(zoomToX, zoomToY) { var oldZoom = zoom; zoom = zoom <= 1 ? 1 / (1 / zoom + 1) : zoom - 1; sceneFlickable.contentX -= zoomToX * (1 - zoom / oldZoom); sceneFlickable.contentY -= zoomToY * (1 - zoom / oldZoom); } Canvas { id: canvas anchors.centerIn: parent width: parent.width - parent.margin.width height: parent.height - parent.margin.height property point start property point end onPaint: { var ctx = getContext("2d"); ctx.reset(); if (start == end) return; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(start.x - 5, start.y); ctx.lineTo(start.x + 5, start.y); ctx.moveTo(start.x, start.y - 5); ctx.lineTo(start.x, start.y + 5); ctx.moveTo(start.x, start.y); ctx.lineTo(end.x, end.y); ctx.moveTo(end.x - 5, end.y); ctx.lineTo(end.x + 5, end.y); ctx.moveTo(end.x, end.y - 5); ctx.lineTo(end.x, end.y + 5); ctx.stroke(); ctx.closePath(); } } MouseArea { id: imageMA anchors.fill: parent hoverEnabled: true preventStealing: true onReleased: { // event-forwarding canvas.start = canvas.end = Qt.point(0,0); canvas.requestPaint(); if (mouseToolGroup.current == redirectInputModeButton) inspectorInterface.sendMouseEvent(3, Qt.point((mouse.x - image.margin.width / 2) / image.zoom, (mouse.y - image.margin.height / 2) / image.zoom), mouse.button, mouse.buttons, mouseToolGroup.modifierDriven ? mouse.modifiers & ~Qt.ShiftModifier : mouse.modifiers); else mouse.accepted = false; } onPressed: { // event-forwarding / measure if (mouseToolGroup.current == redirectInputModeButton) inspectorInterface.sendMouseEvent(2, Qt.point((mouse.x - image.margin.width / 2) / image.zoom, (mouse.y - image.margin.height / 2) / image.zoom), mouse.button, mouse.buttons, mouseToolGroup.modifierDriven ? mouse.modifiers & ~Qt.ShiftModifier : mouse.modifiers); else if (mouseToolGroup.current == measureModeButton) canvas.start = Qt.point(Math.round((mouse.x - image.margin.width / 2) / image.zoom) * image.zoom, Math.round((mouse.y - image.margin.height / 2) / image.zoom) * image.zoom); else mouse.accepted = false; } onPositionChanged: { // event-forwarding / measure if (mouseToolGroup.current == redirectInputModeButton) { inspectorInterface.sendMouseEvent(5, Qt.point((mouse.x - image.margin.width / 2) / image.zoom, (mouse.y - image.margin.height / 2) / image.zoom), mouse.button, mouse.buttons, mouseToolGroup.modifierDriven ? mouse.modifiers & ~Qt.ShiftModifier : mouse.modifiers); } else if (pressed && mouseToolGroup.current == measureModeButton) { canvas.end = Qt.point(Math.round((mouse.x - image.margin.width / 2) / image.zoom) * image.zoom, Math.round((mouse.y - image.margin.height / 2) / image.zoom) * image.zoom); overlayText.text = "(" + Math.floor(canvas.start.x / image.zoom) + ", " + Math.floor(canvas.start.y / image.zoom) + ") - (" + Math.floor(canvas.end.x / image.zoom) + ", " + Math.floor(canvas.end.y / image.zoom) + ") -> " + (Math.sqrt( Math.pow(canvas.end.x - canvas.start.x, 2) + Math.pow(canvas.end.y - canvas.start.y, 2) ) / image.zoom).toFixed(3) + "px"; canvas.requestPaint(); } else { overlayText.text = Math.floor((mouse.x - image.margin.width / 2) / image.zoom) + ", " + Math.floor((mouse.y - image.margin.height / 2) / image.zoom); mouse.accepted = false; } } onDoubleClicked: { // event-forwarding if (mouseToolGroup.current == redirectInputModeButton) inspectorInterface.sendMouseEvent(4, Qt.point((mouse.x - image.margin.width / 2) / image.zoom, (mouse.y - image.margin.height / 2) / image.zoom), mouse.button, mouse.buttons, mouseToolGroup.modifierDriven ? mouse.modifiers & ~Qt.ShiftModifier : mouse.modifiers); else mouse.accepted = false; } onWheel: { // event-forwarding / zoom if (mouseToolGroup.current == redirectInputModeButton) inspectorInterface.sendWheelEvent(Qt.point((wheel.x - image.margin.width / 2) / image.zoom, (wheel.y - image.margin.height / 2) / image.zoom), wheel.pixelDelta, wheel.angleDelta, wheel.buttons, mouseToolGroup.modifierDriven ? wheel.modifiers & ~Qt.ShiftModifier : wheel.modifiers); else if (wheel.angleDelta.y > 0) { var point = mapToItem(image, (wheel.x - image.margin.width / 2), (wheel.y - image.margin.height / 2)); image.zoomIn(point.x, point.y); } else if (wheel.angleDelta.y < 0) { var point = mapToItem(image, (wheel.x - image.margin.width / 2), (wheel.y - image.margin.height / 2)); image.zoomOut(point.x, point.y); } else wheel.accepted = false; } } } } // Rulers Rectangle { id: bottomRuler height: 25 width: parent.width color: "#aa333333" anchors.bottom: parent.bottom Item { width: parent.width - rightRuler.width height: parent.height clip: true Row { x: sceneFlickable.width / 2 - sceneFlickable.contentX spacing: image.zoom > 1 ? image.zoom - 1 : 1 Repeater { // We always create as many elements as the image has pixels. We *could* change it according to // the zoom value, but that would mean recreating all elements on zooming, which is too expensive. model: image.sourceSize.width delegate: Rectangle { color: "#aaffffff" width: 1 height: index % 10 == 0 ? 10 : 5 visible: pixelNumber <= image.sourceSize.width // Don't draw the ruler bigger than the image // states which pixel of the original scene this bar indicates property int pixelNumber: image.zoom > 1 ? index : index * 2 / image.zoom Text { color: "#aaffffff" anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.bottom visible: index % (image.zoom <= 2 ? 20 : 10) == 0 text: pixelNumber } } } } } } Rectangle { id: rightRuler width: 40 height: parent.height color: "#aa333333" anchors.right: parent.right Item { width: parent.width height: parent.height - bottomRuler.height clip: true Column { y: sceneFlickable.height / 2 - sceneFlickable.contentY spacing: image.zoom > 1 ? image.zoom - 1 : 1 Repeater { // We always create as many elements as the image has pixels. We *could* change it according to // the zoom value, but that would mean recreating all elements on zooming, which is too expensive. model: image.sourceSize.height delegate: Rectangle { color: "#aaffffff" height: 1 width: index % 10 == 0 ? 10 : 5 visible: pixelNumber <= image.sourceSize.height // Don't draw the ruler bigger than the image // states which pixel of the original scene this bar indicates property int pixelNumber: image.zoom > 1 ? index : index * 2 / image.zoom Text { color: "#aaffffff" anchors.verticalCenter: parent.verticalCenter anchors.left: parent.right visible: index % 10 == 0 text: pixelNumber } } } } } } // Zoom buttons Row { anchors { right: parent.right; top: bottomRuler.top } ToolButton { width: 20; height: width style: buttonStyle text: "-" onPressedChanged: { if (pressed) decrementZoomTimer.start(); else decrementZoomTimer.stop(); } } ToolButton { width: 20; height: width style: buttonStyle text: "+" onPressedChanged: { if (pressed) incrementZoomTimer.start(); else incrementZoomTimer.stop(); } } } Timer { id: incrementZoomTimer interval: 100 repeat: true triggeredOnStart: true onTriggered: image.zoomIn(image.width / 2, image.height / 2); } Timer { id: decrementZoomTimer interval: 100 repeat: true triggeredOnStart: true onTriggered: image.zoomOut(image.width / 2, image.height / 2); } } gammaray-2.3.0/plugins/quickinspector/resources/redirect-input.png000066400000000000000000000007241255003167400255220ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<QIDAT8Ťť“1OÂ`†ź*5ŕDÄĐŐČîŕěÄlRÂÂęÂę`!q0Îţ‚čD¨şéPÓɆBJéą ©đ!ę%oîî˝Ë{oľäCDPŔZÁ/a…Đ4­–ĚëB‘EÎJÔÇëT®’ůWvO€ű$!"·+<ĎsÖ]ĘçóEź2 cĎuÝ€ŃhäO§Ó°Ńh¶Z-;ťNëş®ďärą۶%…R©t*"u©ĎjDĶVĚľ!E‘eQY“Éd\.—‹Á`i¦|Ĺčv»7ĂáđŁZ­>:Žă_KcŕUDâů˛Ę–išgťNç:‚ç~żoűľ˙îşî[»Ýľ3Mó<ą«t iÚ6p)€L&Ł5›ÍýJĄ’/ ?:PŘĚfł—q?µ9˙[! ç^Żç$?Űźf—­;HĚűO0I“fďé IEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/visualize-batches.png000066400000000000000000000012551255003167400262060ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<*IDAT8Ť}’=hSQÇ7>‘`hÁH‹ ¦¦S2ЏÔ)D-m&!.üŔĄ KĐ1S;8ء随!„BRşIA+b1¦€‚Ńľ4ÉuđU^ă«8.çÜßýß{®FţŻ–”˛iTP€)e­Z­Ś<ĎM!„8@µZ-x˝Ţµa`¨\.[‡ÂĐ™˘_ĄÓé[@ §ĺ×[[[OEé...†\.×}ďÔÔÔ%·Űýđ ätyluuőM8ŤĹbŻ€şľwmm Ó }žźź3ň­×1Ŕ€‰DÝhÓ‰#RĘŁľSŔ?/©ŔźQU**•J X,Nt»Ýł.—ËŚç€O@Pő€–6g˝N7ü~˙ăŮŮŮo©TęžB¨ŞŞnllÔ“Éd˛Ýn+€@Jy,4čőH$˛—Ëĺş333M«ŐúŮb±|÷z˝ăńx{ssó`aaá-pÍ0<77·˝łłóÓd2=·Z­ĎVVV~d2™Cżß_îGŁŃ˝őőőŕÜ,€ńR©ôuzz:LDŁŃíN§#;ťŽĚçóM`Ěl6?ŞŐjżśNçeŕî&ŕBŻ×3---] OwwwÍGĹFŁŃ_^^ONNŢVUµgłŮ. íäżB w}>ßťP(tŐáp Ůívł‚ýý}µ^Ż·S©Ô»l6›ď÷ű/Ť8ŁĹyŕ"ŕÔţÁ{ŕ6Îŕŕ7‹Ľű‰Ň× !IEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/visualize-changes.png000066400000000000000000000011271255003167400262030ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<ÔIDAT8ŤĄ’;‹a†ź/Îćâ‚uă%™Ć čŠd …8‚‚¤r,RY؆ů©ŚélS,hRYů/l‚EHŞ%SM˛aăG‘o.ÇÂVČ §9śóĽΫD„}”Ůk°”Ryŕ6p¬ ŕđlŰż–Ŕ; Ś€®Ś2J©Ľçy´Ö%cĚU­uÉuÝÍfóýjµ:‰˘¨Řď÷źűľ˙ÍăĄizbŚyŰjµľ+ĄNpGk]šL&„amŰ´ŰíW˝^ďxą\.głívűÍh4ş?Ź%ǡV«©l6;ȇ…B0 Ă­ő‘Ěf3ćóů-˲N§A€eY3ŔzłŮ`Ű6¶mS,/•RQĄR \.˙Śăjµ €ă8Äq đ ďyŢ#­uÝS×Z×]×}Ýl6?¬V«NEť~ż˙Ů÷}cŚ‘4MĹ#­Vk ś*Ůë jß Y» )Ą¬íuż#˙¸îšÄŁápxć8ÎSŕćřW"ňßÚšÔŇ4M‹ĹŻN§ó ¸ ČN p“$IDD’$IşÝîGŕxW@xÇqr~~~Ůh4ľ/k;¶{Áŕk.—ó'ŔuŕŠđ\0HČ·wGIEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/visualize-clipping.png000066400000000000000000000012541255003167400264010ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<)IDAT8Ť…“żK[QÇ?ǤCš©CP“ç >íb']3 B†ö(Á­ĐŞŕ‚C bA‡LŽ•Š'íđ6!Kp¨âŇB)öůH<ÚrďíĐDŇŰ/|ą—óă{8çÜ‹1†nŔ"˝üťěŁ7FÂ0üŚ<ŕżCTD&€‰.{˘u>ďů'Yß÷µďű:źĎß÷uĄRŃ[[[şZ­ę zňęęJY˛ů|ţ}ˇP(¶t†/”eY¦WéŃŃŃH<źíX\\4Ŕ‰1fĂł|ý_ďm<4Äj±XT=«ßX[[“.ű“ůůůëşbŚA)EłŮlŻřľ@«…ż ”˘V«qyyÉńń±”ËeńĹ®®.0|k·Ű]†aX¤”;333źűűűß !6Ą”†ů瀦i‡ŔŁH$ň1‹­777Ç÷Ŕ§Ó9‰D˛ŞŞfÝn÷M@1eŔł|>ŘŇŇťťť-*Šňş®®în4ý1==ý«µµő%pgppđçäääŕ<´KńxĽâ@íĐĐи®ëR×u©ŞjpŰl¶'Édň·Ďç{nî@ľ;RĘ‘ľľľÚůůůW™LćĘц••ËŔŔ@{CCĂýýý}ĂápřĹ?~Ł xŕ÷űĂápř¶×ë­®©©)X]]=ČĺrÚÄÄÄňÔÔTĚ0ŚŃż€"J…–•FwđŔ22Ŕ°÷1űu÷Ö»ő˝IEND®B`‚gammaray-2.3.0/plugins/quickinspector/resources/warning.png000066400000000000000000000010551255003167400242270ustar00rootroot00000000000000‰PNG  IHDRó˙asBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<ŞIDAT8ŤĄ“=Q…Ď}E° šYVl&"nˇ0/!Č$)ĆE´¶¶¬"Ť­Ąe°AÄ?»ŚËL°±’­’NZČf`ä!ĚS8™čŠ^ó¸÷;÷Ľ!)ř+Ű ‚@M&“]ą €$ßµŰíý~˙G±V•¦Óé#ĄÔ'-˲”RçĆăńÓ˛Z)Fp]÷„1ć«4â8ŢĎóÖćóůIJ¬ő(ŠţÁóŔ‡8Ž÷}ß?€Ńh¤ŤĆűŮlö€ż2B·Ű]p ŔV\«Őn*Ą6=Ď[[ Č˛ě €·I’|)˘(: ą“¦é«R@«Őş@W«ŐíbóB¶mß"Ůr]÷ě Ďóמ ‡Ăď«ÁŔ|fŚyůŔqś+$Ďض}wUóBőzý€Ť_$EkýYk}ʤei­8Žó‰¤HłŮÜÎóüa’$§Šn‹k ĂpéÁi­ż‘Ľ®ň<ż-"Ź˙6zŮ‘(Ąî+)ÉËA,ą„a¨ĘÜ{˝Ţq—H¦ŇétNgY¶'"çIŃ]řX©TüĄżđŻú R]ÇŢłKĂeIEND®B`‚gammaray-2.3.0/plugins/quickinspector/transferimage.cpp000066400000000000000000000057201255003167400234000ustar00rootroot00000000000000/* transferimage.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "transferimage.h" #include using namespace GammaRay; TransferImage::TransferImage() { } TransferImage::TransferImage(const QImage& image) : m_image(image) { } QImage TransferImage::image() const { return m_image; } void TransferImage::setImage(const QImage& image) { m_image = image; } QDataStream& operator<<(QDataStream& stream, const GammaRay::TransferImage& image) { static const TransferImage::Format format = TransferImage::RawFormat; const QImage &img = image.image(); stream << (quint32)(format); switch (format) { case TransferImage::QImageFormat: stream << img; break; case TransferImage::RawFormat: { stream << (quint32)img.format() << (quint32)img.width() << (quint32)img.height(); for (int i = 0; i < img.height(); ++i) { stream.device()->write((const char*)img.scanLine(i), img.bytesPerLine()); } break; } } return stream; } QDataStream& operator>>(QDataStream& stream, TransferImage& image) { quint32 i; stream >> i; const TransferImage::Format format = static_cast(i); switch (format) { case TransferImage::QImageFormat: { QImage img; stream >> img; image.setImage(img); break; } case TransferImage::RawFormat: { quint32 f, w, h; stream >> f >> w >> h; QImage img(w, h, static_cast(f)); for (int i = 0; i < img.height(); ++i) { const QByteArray buffer = stream.device()->read(img.bytesPerLine()); qMemCopy(img.scanLine(i), buffer.constData(), img.bytesPerLine()); } image.setImage(img); break; } } return stream; } gammaray-2.3.0/plugins/quickinspector/transferimage.h000066400000000000000000000035731255003167400230510ustar00rootroot00000000000000/* transferimage.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TRANSFERIMAGE_H #define GAMMARAY_TRANSFERIMAGE_H #include #include #include namespace GammaRay { /** Wrapper class for a QImage to allow raw data transfer over a QDataStream, bypassing the usuale PNG encoding. */ class TransferImage { public: TransferImage(); explicit TransferImage(const QImage &image); QImage image() const; void setImage(const QImage &image); enum Format { QImageFormat, RawFormat }; private: QImage m_image; }; } QDataStream& operator<<(QDataStream &stream, const GammaRay::TransferImage &image); QDataStream& operator>>(QDataStream &stream, GammaRay::TransferImage &image); Q_DECLARE_METATYPE(GammaRay::TransferImage) #endif // GAMMARAY_TRANSFERIMAGE_H gammaray-2.3.0/plugins/sceneinspector/000077500000000000000000000000001255003167400200225ustar00rootroot00000000000000gammaray-2.3.0/plugins/sceneinspector/CMakeLists.txt000066400000000000000000000016511255003167400225650ustar00rootroot00000000000000# probe part set(gammaray_sceneinspector_plugin_srcs scenemodel.cpp sceneinspectorinterface.cpp sceneinspector.cpp ) gammaray_add_plugin(gammaray_sceneinspector_plugin gammaray_sceneinspector.desktop ${gammaray_sceneinspector_plugin_srcs} ) target_link_libraries(gammaray_sceneinspector_plugin ${QT_QTGUI_LIBRARIES} gammaray_core ) # ui part if(GAMMARAY_BUILD_UI) set(gammaray_sceneinspector_ui_plugin_srcs graphicsview.cpp graphicssceneview.cpp sceneinspectorinterface.cpp sceneinspectorclient.cpp sceneinspectorwidget.cpp ) qt4_wrap_ui(gammaray_sceneinspector_ui_plugin_srcs graphicssceneview.ui sceneinspectorwidget.ui ) gammaray_add_plugin(gammaray_sceneinspector_ui_plugin gammaray_sceneinspector_ui.desktop ${gammaray_sceneinspector_ui_plugin_srcs} ) target_link_libraries(gammaray_sceneinspector_ui_plugin ${QT_QTGUI_LIBRARIES} gammaray_ui ) endif() gammaray-2.3.0/plugins/sceneinspector/gammaray_sceneinspector.desktop000066400000000000000000000002401255003167400263130ustar00rootroot00000000000000[Desktop Entry] Name=Graphics Scenes X-GammaRay-Types=QGraphicsScene; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_sceneinspector_plugin gammaray-2.3.0/plugins/sceneinspector/gammaray_sceneinspector.json000066400000000000000000000001521255003167400256150ustar00rootroot00000000000000{ "id": "gammaray_sceneinspector", "name": "Graphics Scenes", "types": [ "QGraphicsScene" ] } gammaray-2.3.0/plugins/sceneinspector/gammaray_sceneinspector_ui.desktop000066400000000000000000000002251255003167400270130ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_sceneinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_sceneinspector_ui_plugin gammaray-2.3.0/plugins/sceneinspector/graphicssceneview.cpp000066400000000000000000000051371255003167400242450ustar00rootroot00000000000000/* graphicssceneview.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "graphicssceneview.h" #include "ui_graphicssceneview.h" using namespace GammaRay; GraphicsSceneView::GraphicsSceneView(QWidget *parent) : QWidget(parent), ui(new Ui::GraphicsSceneView) { ui->setupUi(this); QFontMetrics fm(ui->sceneCoordLabel->font()); ui->sceneCoordLabel->setFixedWidth(fm.width("00000.00 x 00000.00")); ui->itemCoordLabel->setFixedWidth(fm.width("00000.00 x 00000.00")); connect(ui->graphicsView, SIGNAL(sceneCoordinatesChanged(QPointF)), SLOT(sceneCoordinatesChanged(QPointF))); connect(ui->graphicsView, SIGNAL(itemCoordinatesChanged(QPointF)), SLOT(itemCoordinatesChanged(QPointF))); } GraphicsSceneView::~GraphicsSceneView() { delete ui; } GraphicsView * GraphicsSceneView::view() const { return ui->graphicsView; } void GraphicsSceneView::showGraphicsItem(QGraphicsItem *item) { ui->graphicsView->showItem(item); } void GraphicsSceneView::setGraphicsScene(QGraphicsScene *scene) { ui->graphicsView->setScene(scene); } void GraphicsSceneView::sceneCoordinatesChanged(const QPointF &coord) { ui->sceneCoordLabel->setText(QString::fromLatin1("%1 x %2"). arg(coord.x(), 0, 'f', 2). arg(coord.y(), 0, 'f', 2)); } void GraphicsSceneView::itemCoordinatesChanged(const QPointF &coord) { ui->itemCoordLabel->setText(QString::fromLatin1("%1 x %2"). arg(coord.x(), 0, 'f', 2). arg(coord.y(), 0, 'f', 2)); } gammaray-2.3.0/plugins/sceneinspector/graphicssceneview.h000066400000000000000000000035451255003167400237130ustar00rootroot00000000000000/* graphicssceneview.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_GRAPHICSSCENEVIEW_H #define GAMMARAY_SCENEINSPECTOR_GRAPHICSSCENEVIEW_H #include class QGraphicsScene; class QGraphicsItem; namespace GammaRay { class GraphicsView; namespace Ui { class GraphicsSceneView; } class GraphicsSceneView : public QWidget { Q_OBJECT public: explicit GraphicsSceneView(QWidget *parent = 0); ~GraphicsSceneView(); GraphicsView* view() const; void showGraphicsItem(QGraphicsItem *item); void setGraphicsScene(QGraphicsScene *scene); private slots: void sceneCoordinatesChanged(const QPointF &coord); void itemCoordinatesChanged(const QPointF &coord); private: Ui::GraphicsSceneView *ui; }; } #endif // GAMMARAY_GRAPHICSSCENEVIEW_H gammaray-2.3.0/plugins/sceneinspector/graphicssceneview.ui000066400000000000000000000032751255003167400241010ustar00rootroot00000000000000 GammaRay::GraphicsSceneView 0 0 400 300 0 Scene Coordinates: 0x0 Item Coordinates: 0x0 false QGraphicsView::ScrollHandDrag GammaRay::GraphicsView QGraphicsView
graphicsview.h
gammaray-2.3.0/plugins/sceneinspector/graphicsview.cpp000066400000000000000000000053211255003167400232220ustar00rootroot00000000000000/* graphicsview.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "graphicsview.h" #include "sceneinspectorinterface.h" #include #include using namespace GammaRay; GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent), m_currentItem(0) { setMouseTracking(true); } void GraphicsView::showItem(QGraphicsItem *item) { m_currentItem = item; if (!item) return; fitInView(item, Qt::KeepAspectRatio); scale(0.8f, 0.8f); emit transformChanged(); } void GraphicsView::keyPressEvent(QKeyEvent *event) { if (event->modifiers() == Qt::CTRL) { switch (event->key()) { case Qt::Key_Plus: scale(1.2, 1.2); emit transformChanged(); event->accept(); return; case Qt::Key_Minus: scale(0.8, 0.8); emit transformChanged(); event->accept(); return; case Qt::Key_Left: rotate(-5); emit transformChanged(); event->accept(); break; case Qt::Key_Right: rotate(5); emit transformChanged(); event->accept(); break; } } QGraphicsView::keyPressEvent(event); } void GraphicsView::mouseMoveEvent(QMouseEvent *event) { emit sceneCoordinatesChanged(mapToScene(event->pos())); if (m_currentItem) { emit itemCoordinatesChanged(m_currentItem->mapFromScene(mapToScene(event->pos()))); } QGraphicsView::mouseMoveEvent(event); } void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect) { QGraphicsView::drawForeground(painter, rect); if (m_currentItem) { SceneInspectorInterface::paintItemDecoration(m_currentItem, transform(), painter); } } gammaray-2.3.0/plugins/sceneinspector/graphicsview.h000066400000000000000000000036271255003167400226760ustar00rootroot00000000000000/* graphicsview.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_GRAPHICSVIEW_H #define GAMMARAY_SCENEINSPECTOR_GRAPHICSVIEW_H #include namespace GammaRay { class GraphicsView : public QGraphicsView { Q_OBJECT public: explicit GraphicsView(QWidget *parent = 0); void showItem(QGraphicsItem *item); signals: void sceneCoordinatesChanged(const QPointF &sceneCoord); void itemCoordinatesChanged(const QPointF &itemCoord); void transformChanged(); protected: void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void drawForeground(QPainter *painter, const QRectF &rect) Q_DECL_OVERRIDE; private: QGraphicsItem *m_currentItem; }; } #endif // GAMMARAY_GRAPHICSVIEW_H gammaray-2.3.0/plugins/sceneinspector/sceneinspector.cpp000066400000000000000000000420461255003167400235600ustar00rootroot00000000000000/* sceneinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sceneinspector.h" #include "scenemodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; using namespace std; Q_DECLARE_METATYPE(QGraphicsEffect *) Q_DECLARE_METATYPE(QGraphicsItemGroup *) Q_DECLARE_METATYPE(QGraphicsObject *) Q_DECLARE_METATYPE(QGraphicsWidget *) Q_DECLARE_METATYPE(QGraphicsItem::CacheMode) Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlags) Q_DECLARE_METATYPE(QGraphicsItem::PanelModality) Q_DECLARE_METATYPE(QGraphicsPixmapItem::ShapeMode) SceneInspector::SceneInspector(ProbeInterface *probe, QObject *parent) : SceneInspectorInterface(parent), m_propertyController(new PropertyController("com.kdab.GammaRay.SceneInspector", this)), m_clientConnected(false) { Server::instance()->registerMonitorNotifier(Endpoint::instance()->objectAddress(objectName()), this, "clientConnectedChanged"); registerGraphicsViewMetaTypes(); registerVariantHandlers(); connect(probe->probe(), SIGNAL(objectSelected(QObject*,QPoint)), SLOT(objectSelected(QObject*,QPoint))); ObjectTypeFilterProxyModel *sceneFilterProxy = new ObjectTypeFilterProxyModel(this); sceneFilterProxy->setSourceModel(probe->objectListModel()); SingleColumnObjectProxyModel *singleColumnProxy = new SingleColumnObjectProxyModel(this); singleColumnProxy->setSourceModel(sceneFilterProxy); probe->registerModel("com.kdab.GammaRay.SceneList", singleColumnProxy); QItemSelectionModel* sceneSelection = ObjectBroker::selectionModel(singleColumnProxy); connect(sceneSelection, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(sceneSelected(QItemSelection))); m_sceneModel = new SceneModel(this); probe->registerModel("com.kdab.GammaRay.SceneGraphModel", m_sceneModel); m_itemSelectionModel = ObjectBroker::selectionModel(m_sceneModel); connect(m_itemSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(sceneItemSelected(QItemSelection))); if (singleColumnProxy->rowCount()) { sceneSelection->setCurrentIndex(singleColumnProxy->index(0, 0), QItemSelectionModel::ClearAndSelect); } } void SceneInspector::sceneSelected(const QItemSelection& selection) { if (selection.isEmpty()) return; const QModelIndex index = selection.first().topLeft(); QObject *obj = index.data(ObjectModel::ObjectRole).value(); QGraphicsScene *scene = qobject_cast(obj); if (m_sceneModel->scene()) { disconnect(m_sceneModel->scene(), 0, this, 0); } m_sceneModel->setScene(scene); connectToScene(); // TODO remote support when a different graphics scene was selected // ui->graphicsSceneView->setGraphicsScene(scene); } void SceneInspector::connectToScene() { QGraphicsScene *scene = m_sceneModel->scene(); if (!scene || !m_clientConnected) { return; } connect(scene, SIGNAL(sceneRectChanged(QRectF)), this, SIGNAL(sceneRectChanged(QRectF))); connect(scene, SIGNAL(changed(QList)), this, SIGNAL(sceneChanged())); initializeGui(); } void SceneInspector::initializeGui() { if (!Endpoint::isConnected()) { // only do something if we are connected to a remote client return; } QGraphicsScene *scene = m_sceneModel->scene(); if (!scene) { return; } emit sceneRectChanged(scene->sceneRect()); } void SceneInspector::clientConnectedChanged(bool clientConnected) { m_clientConnected = clientConnected; connectToScene(); } void SceneInspector::renderScene(const QTransform &transform, const QSize &size) { if (!Endpoint::isConnected()) { // only do something if we are connected to a remote client return; } QGraphicsScene *scene = m_sceneModel->scene(); if (!scene) { return; } // initialize transparent pixmap QPixmap view(size); view.fill(Qt::transparent); // setup painter and apply transformation of client view QPainter painter(&view); painter.setWorldTransform(transform); // the area we want to paint has the size of the client's viewport _after_ applying // the transformation. Thus first apply the inverse to yield the desired area afterwards QRectF area(QPointF(0, 0), size); area = transform.inverted().mapRect(area); scene->render(&painter, area, area, Qt::IgnoreAspectRatio); QGraphicsItem *currentItem = m_itemSelectionModel->currentIndex().data(SceneModel::SceneItemRole).value(); if (currentItem) { paintItemDecoration(currentItem, transform, &painter); } emit sceneRendered(view); } void SceneInspector::sceneItemSelected(const QItemSelection& selection) { QModelIndex index; if (!selection.isEmpty()) index = selection.first().topLeft(); if (index.isValid()) { QGraphicsItem *item = index.data(SceneModel::SceneItemRole).value(); QGraphicsObject *obj = item->toGraphicsObject(); if (obj) { m_propertyController->setObject(obj); } else { m_propertyController->setObject(item, findBestType(item)); } emit itemSelected(item->mapRectToScene(item->boundingRect())); } else { m_propertyController->setObject(0); emit sceneChanged(); } } void SceneInspector::objectSelected(QObject *object, const QPoint &pos) { QWidget *widget = qobject_cast(object); QGraphicsView *qgv = Util::findParentOfType(object); if (qgv) { // TODO: select qgv->scene() first, right now this only works for a single scene QGraphicsItem *item = qgv->itemAt(widget ? widget->mapTo(qgv, pos) : pos); if (item) { sceneItemSelected(item); } } } void SceneInspector::sceneItemSelected(QGraphicsItem *item) { const QModelIndexList indexList = m_sceneModel->match(m_sceneModel->index(0, 0), SceneModel::SceneItemRole, QVariant::fromValue(item), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_itemSelectionModel->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } void SceneInspector::sceneClicked(const QPointF &pos) { QGraphicsItem *item = m_sceneModel->scene()->itemAt(pos); if (item) { sceneItemSelected(item); } } #define QGV_CHECK_TYPE(Class) \ if (dynamic_cast(item) && MetaObjectRepository::instance()->hasMetaObject(#Class)) \ return QLatin1String(#Class) QString SceneInspector::findBestType(QGraphicsItem *item) { // keep this in reverse topological order of the class hierarchy! // QObject-based types are covered elsewhere, so we don't need those here QGV_CHECK_TYPE(QGraphicsEllipseItem); QGV_CHECK_TYPE(QGraphicsPathItem); QGV_CHECK_TYPE(QGraphicsPolygonItem); QGV_CHECK_TYPE(QGraphicsSimpleTextItem); QGV_CHECK_TYPE(QGraphicsRectItem); QGV_CHECK_TYPE(QAbstractGraphicsShapeItem); QGV_CHECK_TYPE(QGraphicsLineItem); QGV_CHECK_TYPE(QGraphicsItemGroup); QGV_CHECK_TYPE(QGraphicsPixmapItem); return QLatin1String("QGraphicsItem"); } void SceneInspector::registerGraphicsViewMetaTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT0(QGraphicsItem); MO_ADD_PROPERTY (QGraphicsItem, bool, acceptDrops, setAcceptDrops); MO_ADD_PROPERTY (QGraphicsItem, bool, acceptHoverEvents, setAcceptHoverEvents); MO_ADD_PROPERTY (QGraphicsItem, bool, acceptTouchEvents, setAcceptTouchEvents); MO_ADD_PROPERTY (QGraphicsItem, Qt::MouseButtons, acceptedMouseButtons, setAcceptedMouseButtons); MO_ADD_PROPERTY_RO(QGraphicsItem, QRectF, boundingRect); MO_ADD_PROPERTY (QGraphicsItem, qreal, boundingRegionGranularity, setBoundingRegionGranularity); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem::CacheMode, cacheMode); MO_ADD_PROPERTY_RO(QGraphicsItem, QRectF, childrenBoundingRect); MO_ADD_PROPERTY_RO(QGraphicsItem, QPainterPath, clipPath); MO_ADD_PROPERTY_CR(QGraphicsItem, QCursor, cursor, setCursor); MO_ADD_PROPERTY_RO(QGraphicsItem, qreal, effectiveOpacity); MO_ADD_PROPERTY (QGraphicsItem, bool, filtersChildEvents, setFiltersChildEvents); MO_ADD_PROPERTY (QGraphicsItem, QGraphicsItem::GraphicsItemFlags, flags, setFlags); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem*, focusItem); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem*, focusProxy); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsEffect*, graphicsEffect); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItemGroup*, group); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, hasCursor); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, hasFocus); MO_ADD_PROPERTY (QGraphicsItem, Qt::InputMethodHints, inputMethodHints, setInputMethodHints); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isActive); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isClipped); MO_ADD_PROPERTY (QGraphicsItem, bool, isEnabled, setEnabled); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isObscured); #endif MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isPanel); MO_ADD_PROPERTY (QGraphicsItem, bool, isSelected, setSelected); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isUnderMouse); MO_ADD_PROPERTY (QGraphicsItem, bool, isVisible, setVisible); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isWidget); MO_ADD_PROPERTY_RO(QGraphicsItem, bool, isWindow); MO_ADD_PROPERTY (QGraphicsItem, qreal, opacity, setOpacity); MO_ADD_PROPERTY_RO(QGraphicsItem, QPainterPath, opaqueArea); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem*, panel); MO_ADD_PROPERTY (QGraphicsItem, QGraphicsItem::PanelModality, panelModality, setPanelModality); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem*, parentItem); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsObject*, parentObject); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsWidget*, parentWidget); MO_ADD_PROPERTY_CR(QGraphicsItem, QPointF, pos, setPos); MO_ADD_PROPERTY (QGraphicsItem, qreal, rotation, setRotation); MO_ADD_PROPERTY (QGraphicsItem, qreal, scale, setScale); MO_ADD_PROPERTY_RO(QGraphicsItem, QRectF, sceneBoundingRect); MO_ADD_PROPERTY_RO(QGraphicsItem, QPointF, scenePos); MO_ADD_PROPERTY_RO(QGraphicsItem, QTransform, sceneTransform); MO_ADD_PROPERTY_RO(QGraphicsItem, QPainterPath, shape); MO_ADD_PROPERTY_CR(QGraphicsItem, QString, toolTip, setToolTip); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsItem*, topLevelItem); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsWidget*, topLevelWidget); MO_ADD_PROPERTY_RO(QGraphicsItem, QTransform, transform/*, setTransform*/); // TODO: support setTransform MO_ADD_PROPERTY_CR(QGraphicsItem, QPointF, transformOriginPoint, setTransformOriginPoint); MO_ADD_PROPERTY_RO(QGraphicsItem, int, type); MO_ADD_PROPERTY_RO(QGraphicsItem, QGraphicsWidget*, window); MO_ADD_PROPERTY (QGraphicsItem, qreal, x, setX); MO_ADD_PROPERTY (QGraphicsItem, qreal, y, setY); MO_ADD_PROPERTY (QGraphicsItem, qreal, zValue, setZValue); MO_ADD_METAOBJECT1(QAbstractGraphicsShapeItem, QGraphicsItem); MO_ADD_PROPERTY_CR(QAbstractGraphicsShapeItem, QBrush, brush, setBrush); MO_ADD_PROPERTY_CR(QAbstractGraphicsShapeItem, QPen, pen, setPen); MO_ADD_METAOBJECT1(QGraphicsEllipseItem, QAbstractGraphicsShapeItem); MO_ADD_PROPERTY_CR(QGraphicsEllipseItem, QRectF, rect, setRect); MO_ADD_PROPERTY (QGraphicsEllipseItem, int, spanAngle, setSpanAngle); MO_ADD_PROPERTY (QGraphicsEllipseItem, int, startAngle, setStartAngle); MO_ADD_METAOBJECT1(QGraphicsPathItem, QAbstractGraphicsShapeItem); MO_ADD_PROPERTY_CR(QGraphicsPathItem, QPainterPath, path, setPath); MO_ADD_METAOBJECT1(QGraphicsPolygonItem, QAbstractGraphicsShapeItem); MO_ADD_PROPERTY (QGraphicsPolygonItem, Qt::FillRule, fillRule, setFillRule); MO_ADD_PROPERTY_CR(QGraphicsPolygonItem, QPolygonF, polygon, setPolygon); MO_ADD_METAOBJECT1(QGraphicsSimpleTextItem, QAbstractGraphicsShapeItem); MO_ADD_PROPERTY_CR(QGraphicsSimpleTextItem, QFont, font, setFont); MO_ADD_PROPERTY_CR(QGraphicsSimpleTextItem, QString, text, setText); MO_ADD_METAOBJECT1(QGraphicsRectItem, QAbstractGraphicsShapeItem); MO_ADD_PROPERTY_CR(QGraphicsRectItem, QRectF, rect, setRect); MO_ADD_METAOBJECT1(QGraphicsLineItem, QGraphicsItem); MO_ADD_PROPERTY_CR(QGraphicsLineItem, QLineF, line, setLine); MO_ADD_PROPERTY_CR(QGraphicsLineItem, QPen, pen, setPen); MO_ADD_METAOBJECT1(QGraphicsPixmapItem, QGraphicsItem); MO_ADD_PROPERTY_CR(QGraphicsPixmapItem, QPointF, offset, setOffset); MO_ADD_PROPERTY_CR(QGraphicsPixmapItem, QPixmap, pixmap, setPixmap); MO_ADD_PROPERTY (QGraphicsPixmapItem, QGraphicsPixmapItem::ShapeMode, shapeMode, setShapeMode); MO_ADD_PROPERTY (QGraphicsPixmapItem, Qt::TransformationMode, transformationMode, setTransformationMode); // no extra properties, but we need the inheritance connection for anything above to work MO_ADD_METAOBJECT2(QGraphicsObject, QGraphicsItem, QObject); MO_ADD_METAOBJECT0(QGraphicsLayoutItem); MO_ADD_PROPERTY_RO(QGraphicsLayoutItem, QRectF, contentsRect); MO_ADD_PROPERTY_RO(QGraphicsLayoutItem, bool, isLayout); MO_ADD_PROPERTY_RO(QGraphicsLayoutItem, bool, ownedByLayout); MO_ADD_METAOBJECT2(QGraphicsWidget, QGraphicsObject, QGraphicsLayoutItem); MO_ADD_PROPERTY_RO(QGraphicsWidget, QRectF, windowFrameGeometry); MO_ADD_PROPERTY_RO(QGraphicsWidget, QRectF, windowFrameRect); MO_ADD_METAOBJECT1(QGraphicsProxyWidget, QGraphicsWidget); MO_ADD_PROPERTY_RO(QGraphicsProxyWidget, QWidget*, widget); } void SceneInspector::registerVariantHandlers() { VariantHandler::registerStringConverter(Util::addressToString); VariantHandler::registerStringConverter(Util::addressToString); #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) VariantHandler::registerStringConverter(Util::displayString); VariantHandler::registerStringConverter(Util::displayString); VariantHandler::registerStringConverter(Util::displayString); #endif } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SceneInspectorFactory) #endif gammaray-2.3.0/plugins/sceneinspector/sceneinspector.h000066400000000000000000000057351255003167400232310ustar00rootroot00000000000000/* sceneinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_SCENEINSPECTOR_H #define GAMMARAY_SCENEINSPECTOR_SCENEINSPECTOR_H #include #include "sceneinspectorinterface.h" #include class QItemSelectionModel; class QItemSelection; class QModelIndex; namespace GammaRay { class PropertyController; class SceneModel; class SceneInspector : public SceneInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::SceneInspectorInterface) public: explicit SceneInspector(ProbeInterface *probe, QObject *parent = 0); private slots: void initializeGui() Q_DECL_OVERRIDE; void renderScene(const QTransform &transform, const QSize &size) Q_DECL_OVERRIDE; void sceneSelected(const QItemSelection &selection); void sceneItemSelected(const QItemSelection &selection); void sceneItemSelected(QGraphicsItem *item); void objectSelected(QObject *object, const QPoint &pos); void sceneClicked(const QPointF &pos) Q_DECL_OVERRIDE; void clientConnectedChanged(bool clientConnected); private: QString findBestType(QGraphicsItem *item); void registerGraphicsViewMetaTypes(); void registerVariantHandlers(); void connectToScene(); private: SceneModel *m_sceneModel; QItemSelectionModel* m_itemSelectionModel; PropertyController *m_propertyController; bool m_clientConnected; }; class SceneInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_sceneinspector.json") public: explicit SceneInspectorFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("Graphics Scenes"); } }; } #endif // GAMMARAY_SCENEINSPECTOR_H gammaray-2.3.0/plugins/sceneinspector/sceneinspectorclient.cpp000066400000000000000000000035331255003167400247550ustar00rootroot00000000000000/* sceneinspectorclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sceneinspectorclient.h" #include #include using namespace GammaRay; SceneInspectorClient::SceneInspectorClient(QObject *parent) : SceneInspectorInterface(parent) { } SceneInspectorClient::~SceneInspectorClient() { } void SceneInspectorClient::initializeGui() { Endpoint::instance()->invokeObject(objectName(), "initializeGui"); } void SceneInspectorClient::renderScene(const QTransform &transform, const QSize &size) { Endpoint::instance()->invokeObject(objectName(), "renderScene", QVariantList() << transform << size); } void SceneInspectorClient::sceneClicked(const QPointF &pos) { Endpoint::instance()->invokeObject(objectName(), "sceneClicked", QVariantList() << pos); } gammaray-2.3.0/plugins/sceneinspector/sceneinspectorclient.h000066400000000000000000000033521255003167400244210ustar00rootroot00000000000000/* sceneinspectorclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORCLIENT_H #define GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORCLIENT_H #include "sceneinspectorinterface.h" namespace GammaRay { class SceneInspectorClient : public SceneInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::SceneInspectorInterface) public: explicit SceneInspectorClient(QObject *parent = 0); ~SceneInspectorClient(); void initializeGui() Q_DECL_OVERRIDE; void renderScene(const QTransform &transform, const QSize &size) Q_DECL_OVERRIDE; void sceneClicked(const QPointF &pos) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_SCENEINSPECTORCLIENT_H gammaray-2.3.0/plugins/sceneinspector/sceneinspectorinterface.cpp000066400000000000000000000052141255003167400254350ustar00rootroot00000000000000/* sceneinspectorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sceneinspectorinterface.h" #include #include #include using namespace GammaRay; SceneInspectorInterface::SceneInspectorInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } SceneInspectorInterface::~SceneInspectorInterface() { } void SceneInspectorInterface::paintItemDecoration(QGraphicsItem *item, const QTransform &transform, QPainter *painter) { const QRectF itemBoundingRect = item->boundingRect(); // coord system, TODO: nicer axis with arrows, tics, markers for current mouse position etc. painter->setPen(Qt::black); const qreal maxX = qMax(qAbs(itemBoundingRect.left()), qAbs(itemBoundingRect.right())); const qreal maxY = qMax(qAbs(itemBoundingRect.top()), qAbs(itemBoundingRect.bottom())); const qreal maxXY = qMax(maxX, maxY) * 1.5f; painter->drawLine(item->mapToScene(-maxXY, 0), item->mapToScene(maxXY, 0)); painter->drawLine(item->mapToScene(0, -maxXY), item->mapToScene(0, maxXY)); painter->setPen(Qt::blue); const QPolygonF boundingBox = item->mapToScene(itemBoundingRect); painter->drawPolygon(boundingBox); painter->setPen(Qt::green); const QPainterPath shape = item->mapToScene(item->shape()); painter->drawPath(shape); painter->setPen(Qt::red); const QPointF transformOrigin = item->mapToScene(item->transformOriginPoint()); painter->drawEllipse(transformOrigin, 5.0 / transform.m11(), 5.0 / transform.m22()); } gammaray-2.3.0/plugins/sceneinspector/sceneinspectorinterface.h000066400000000000000000000042441255003167400251040ustar00rootroot00000000000000/* sceneinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORINTERFACE_H #define GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORINTERFACE_H #include class QPainter; class QGraphicsItem; class QSize; class QTransform; class QRectF; class QPixmap; class QPointF; namespace GammaRay { class SceneInspectorInterface : public QObject { Q_OBJECT public: explicit SceneInspectorInterface(QObject *parent = 0); virtual ~SceneInspectorInterface(); virtual void initializeGui() = 0; static void paintItemDecoration(QGraphicsItem *item, const QTransform &transform, QPainter *painter); public slots: virtual void renderScene(const QTransform &transform, const QSize &size) = 0; virtual void sceneClicked(const QPointF &pos) = 0; signals: void sceneRectChanged(const QRectF &rect); void sceneChanged(); void sceneRendered(const QPixmap &view); void itemSelected(const QRectF &boundingRect); }; } Q_DECLARE_INTERFACE(GammaRay::SceneInspectorInterface, "com.kdab.GammaRay.SceneInspector") #endif // GAMMARAY_SCENEINSPECTORINTERFACE_H gammaray-2.3.0/plugins/sceneinspector/sceneinspectorwidget.cpp000066400000000000000000000175031255003167400247640ustar00rootroot00000000000000/* sceneinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sceneinspectorwidget.h" #include "scenemodel.h" #include "sceneinspectorclient.h" #include "graphicsview.h" #include "ui_sceneinspectorwidget.h" #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; using namespace std; static QObject* createClientSceneInspector(const QString &/*name*/, QObject *parent) { return new SceneInspectorClient(parent); } SceneInspectorWidget::SceneInspectorWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::SceneInspectorWidget) , m_interface(0) , m_scene(new QGraphicsScene(this)) , m_pixmap(new QGraphicsPixmapItem) , m_updateTimer(new QTimer(this)) { ObjectBroker::registerClientObjectFactoryCallback(createClientSceneInspector); m_interface = ObjectBroker::object(); ui->setupUi(this); ui->scenePropertyWidget->setObjectBaseName("com.kdab.GammaRay.SceneInspector"); ui->sceneComboBox->setModel(ObjectBroker::model("com.kdab.GammaRay.SceneList")); connect(ui->sceneComboBox, SIGNAL(currentIndexChanged(int)), SLOT(sceneSelected(int))); QSortFilterProxyModel *sceneFilter = new KRecursiveFilterProxyModel(this); sceneFilter->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.SceneGraphModel")); ui->sceneTreeView->setModel(sceneFilter); ui->screneTreeSearchLine->setProxy(sceneFilter); QItemSelectionModel *itemSelection = ObjectBroker::selectionModel(sceneFilter); ui->sceneTreeView->setSelectionModel(itemSelection); connect(itemSelection, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(sceneItemSelected(QItemSelection))); ui->graphicsSceneView->setGraphicsScene(m_scene); connect(m_interface, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(sceneRectChanged(QRectF))); connect(m_interface, SIGNAL(sceneChanged()), this, SLOT(sceneChanged())); connect(m_interface, SIGNAL(sceneRendered(QPixmap)), this, SLOT(sceneRendered(QPixmap))); connect(m_interface, SIGNAL(itemSelected(QRectF)), this, SLOT(itemSelected(QRectF))); m_interface->initializeGui(); m_pixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations); m_scene->addItem(m_pixmap); connect(ui->graphicsSceneView->view(), SIGNAL(transformChanged()), this, SLOT(visibleSceneRectChanged())); connect(ui->graphicsSceneView->view()->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(visibleSceneRectChanged())); connect(ui->graphicsSceneView->view()->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(visibleSceneRectChanged())); if (Endpoint::instance()->isRemoteClient()) { ui->graphicsSceneView->view()->viewport()->installEventFilter(this); } QItemSelectionModel *selection = ObjectBroker::selectionModel(ui->sceneComboBox->model()); if (selection->currentIndex().isValid()) { sceneSelected(selection->currentIndex().row()); } else if (ui->sceneComboBox->currentIndex() >= 0) { // no server-side selection yet, but there's data available sceneSelected(ui->sceneComboBox->currentIndex()); } // limit fps to prevent bad performance, and to group update requests which is esp. required // for scrolling and similar high-frequency update requests m_updateTimer->setSingleShot(true); m_updateTimer->setInterval(100); connect(m_updateTimer, SIGNAL(timeout()), SLOT(requestSceneUpdate())); } SceneInspectorWidget::~SceneInspectorWidget() { } bool SceneInspectorWidget::eventFilter(QObject *obj, QEvent *event) { Q_ASSERT(obj == ui->graphicsSceneView->view()->viewport()); if (event->type() == QEvent::Resize) { QMetaObject::invokeMethod(this, "visibleSceneRectChanged", Qt::QueuedConnection); } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *e = static_cast(event); if (e->button() == Qt::LeftButton && e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { m_interface->sceneClicked(ui->graphicsSceneView->view()->mapToScene(e->pos())); } } return QObject::eventFilter(obj, event); } void SceneInspectorWidget::itemSelected(const QRectF &boundingRect) { ui->graphicsSceneView->view()->fitInView(boundingRect, Qt::KeepAspectRatio); ui->graphicsSceneView->view()->scale(0.8, 0.8); visibleSceneRectChanged(); } void SceneInspectorWidget::sceneRectChanged(const QRectF &rect) { m_scene->setSceneRect(rect); visibleSceneRectChanged(); } void SceneInspectorWidget::sceneChanged() { if (!m_updateTimer->isActive()) { m_updateTimer->start(); } } void SceneInspectorWidget::requestSceneUpdate() { if (!Endpoint::instance()->isRemoteClient()) { return; } if (ui->graphicsSceneView->view()->rect().isEmpty()) { // when the splitter is moved to hide the view, don't request updates return; } m_interface->renderScene(ui->graphicsSceneView->view()->viewportTransform(), ui->graphicsSceneView->view()->viewport()->rect().size()); } void SceneInspectorWidget::sceneRendered(const QPixmap &view) { m_pixmap->setPixmap(view); } void SceneInspectorWidget::visibleSceneRectChanged() { m_pixmap->setPos(ui->graphicsSceneView->view()->mapToScene(0, 0)); sceneChanged(); } void SceneInspectorWidget::sceneSelected(int index) { const QModelIndex mi = ui->sceneComboBox->model()->index(index, 0); ObjectBroker::selectionModel(ui->sceneComboBox->model())->select(mi, QItemSelectionModel::ClearAndSelect); if (!Endpoint::instance()->isRemoteClient()) { // for in-process mode, use the user scene directly. This is much more performant and we can // skip the pixmap conversions and fps limitations thereof. QObject *obj = ui->sceneComboBox->itemData(index, ObjectModel::ObjectRole).value(); QGraphicsScene *scene = qobject_cast(obj); cout << Q_FUNC_INFO << ' ' << scene << ' ' << obj << endl; if (scene) { ui->graphicsSceneView->setGraphicsScene(scene); } } } void SceneInspectorWidget::sceneItemSelected(const QItemSelection &selection) { if (Endpoint::instance()->isRemoteClient()) { return; } QModelIndex index; if (!selection.isEmpty()) index = selection.first().topLeft(); if (index.isValid()) { QGraphicsItem *item = index.data(SceneModel::SceneItemRole).value(); ui->graphicsSceneView->showGraphicsItem(item); ui->sceneTreeView->scrollTo(index); // in case selection does not come from us } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SceneInspectorUiFactory) #endif gammaray-2.3.0/plugins/sceneinspector/sceneinspectorwidget.h000066400000000000000000000050311255003167400244220ustar00rootroot00000000000000/* sceneinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORWIDGET_H #define GAMMARAY_SCENEINSPECTOR_SCENEINSPECTORWIDGET_H #include #include class QGraphicsPixmapItem; class QGraphicsScene; class QItemSelection; namespace GammaRay { class SceneInspectorInterface; namespace Ui { class SceneInspectorWidget; } class SceneInspectorWidget : public QWidget { Q_OBJECT public: explicit SceneInspectorWidget(QWidget *parent = 0); ~SceneInspectorWidget(); private slots: void sceneSelected(int index); void sceneItemSelected(const QItemSelection &selection); void sceneRectChanged(const QRectF &rect); void sceneChanged(); void requestSceneUpdate(); void sceneRendered(const QPixmap &view); void visibleSceneRectChanged(); void itemSelected(const QRectF &boundingRect); private: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; QScopedPointer ui; SceneInspectorInterface *m_interface; QGraphicsScene *m_scene; QGraphicsPixmapItem *m_pixmap; QTimer *m_updateTimer; }; class SceneInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_sceneinspector.json") }; } #endif // GAMMARAY_SCENEINSPECTOR_H gammaray-2.3.0/plugins/sceneinspector/sceneinspectorwidget.ui000066400000000000000000000044311255003167400246130ustar00rootroot00000000000000 GammaRay::SceneInspectorWidget 0 0 400 300 Qt::Horizontal Qt::Vertical 10 true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
GammaRay::PropertyWidget QWidget
ui/propertywidget.h
1
GammaRay::GraphicsSceneView QWidget
graphicssceneview.h
1
gammaray-2.3.0/plugins/sceneinspector/scenemodel.cpp000066400000000000000000000126071255003167400226520ustar00rootroot00000000000000/* scenemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "scenemodel.h" #include #include #include #include using namespace GammaRay; #define QGV_ITEMTYPE(Type) \ { \ Type t; \ m_typeNames.insert(t.type(), QLatin1String(#Type)); \ } SceneModel::SceneModel(QObject *parent) : QAbstractItemModel(parent), m_scene(0) { QGV_ITEMTYPE(QGraphicsLineItem) QGV_ITEMTYPE(QGraphicsPixmapItem) QGV_ITEMTYPE(QGraphicsRectItem) QGV_ITEMTYPE(QGraphicsEllipseItem) QGV_ITEMTYPE(QGraphicsPathItem) QGV_ITEMTYPE(QGraphicsPolygonItem) QGV_ITEMTYPE(QGraphicsSimpleTextItem) QGV_ITEMTYPE(QGraphicsItemGroup) } void SceneModel::setScene(QGraphicsScene *scene) { beginResetModel(); m_scene = scene; endResetModel(); } QGraphicsScene *SceneModel::scene() const { return m_scene; } QVariant SceneModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } QGraphicsItem *item = static_cast(index.internalPointer()); if (item && role == Qt::DisplayRole) { QGraphicsObject *obj = item->toGraphicsObject(); if (index.column() == 0) { if (obj && !obj->objectName().isEmpty()) { return obj->objectName(); } return QString::fromLatin1("0x%1"). arg(QString::number(reinterpret_cast(item), 16)); } else if (index.column() == 1) { if (obj) { return obj->metaObject()->className(); } return typeName(item->type()); } } else if (role == SceneItemRole) { return QVariant::fromValue(item); } else if (item && role == Qt::ForegroundRole) { if (!item->isVisible()) { return qApp->palette().color(QPalette::Disabled, QPalette::Text); } } return QVariant(); } int SceneModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } int SceneModel::rowCount(const QModelIndex &parent) const { if (!m_scene) { return 0; } if (parent.isValid()) { if (parent.column() != 0) { return 0; } QGraphicsItem* item = static_cast(parent.internalPointer()); if (item) { return item->childItems().size(); } else { return 0; } } return topLevelItems().size(); } QModelIndex SceneModel::parent(const QModelIndex &child) const { if (!child.isValid()) { return QModelIndex(); } QGraphicsItem *item = static_cast(child.internalPointer()); if (!item->parentItem()) { return QModelIndex(); } int row = 0; if (item->parentItem()->parentItem()) { row = item->parentItem()->parentItem()->childItems().indexOf(item->parentItem()); } return createIndex(row, 0, item->parentItem()); } QModelIndex SceneModel::index(int row, int column, const QModelIndex &parent) const { if (column < 0 || column >= columnCount()) { return QModelIndex(); } if (!parent.isValid() && row >= 0 && row < topLevelItems().size()) { return createIndex(row, column, topLevelItems().at(row)); } QGraphicsItem *parentItem = static_cast(parent.internalPointer()); if (!parentItem || row < 0 || row >= parentItem->childItems().size()) { return QModelIndex(); } return createIndex(row, column, parentItem->childItems().at(row)); } QList SceneModel::topLevelItems() const { QList topLevel; if (!m_scene) { return topLevel; } Q_FOREACH (QGraphicsItem *item, m_scene->items()) { if (!item->parentItem()) { topLevel.push_back(item); } } return topLevel; } QVariant SceneModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Item"); case 1: return tr("Type"); } } return QAbstractItemModel::headerData(section, orientation, role); } QString SceneModel::typeName(int itemType) const { const QHash::const_iterator it = m_typeNames.find(itemType); if (it != m_typeNames.end()) { return it.value(); } if (itemType == QGraphicsItem::UserType) { return QLatin1String("UserType"); } if (itemType > QGraphicsItem::UserType) { return QString::fromLatin1("UserType + %1"). arg(itemType - static_cast(QGraphicsItem::UserType)); } return QString::number(itemType); } gammaray-2.3.0/plugins/sceneinspector/scenemodel.h000066400000000000000000000046111255003167400223130ustar00rootroot00000000000000/* scenemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCENEINSPECTOR_SCENEMODEL_H #define GAMMARAY_SCENEINSPECTOR_SCENEMODEL_H #include #include class QGraphicsScene; class QGraphicsItem; namespace GammaRay { class SceneModel : public QAbstractItemModel { Q_OBJECT public: enum Role { SceneItemRole = UserRole + 1 }; explicit SceneModel(QObject *parent = 0); void setScene(QGraphicsScene *scene); QGraphicsScene *scene() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QList topLevelItems() const; /// Returns a string type name for the given QGV item type id QString typeName(int itemType) const; QGraphicsScene *m_scene; QHash m_typeNames; }; } #endif // GAMMARAY_SCENEMODEL_H gammaray-2.3.0/plugins/scriptenginedebugger/000077500000000000000000000000001255003167400211755ustar00rootroot00000000000000gammaray-2.3.0/plugins/scriptenginedebugger/CMakeLists.txt000066400000000000000000000016521255003167400237410ustar00rootroot00000000000000# probe plugin set(gammaray_scriptenginedebugger_plugin_srcs scriptenginedebugger.cpp ) gammaray_add_plugin(gammaray_scriptenginedebugger_plugin gammaray_scriptenginedebugger.desktop ${gammaray_scriptenginedebugger_plugin_srcs} ) target_link_libraries(gammaray_scriptenginedebugger_plugin ${QT_QTSCRIPT_LIBRARIES} ${QT_QTSCRIPTTOOLS_LIBRARIES} gammaray_core ) # UI plugin if(GAMMARAY_BUILD_UI) set(gammaray_scriptenginedebugger_ui_plugin_srcs scriptenginedebuggerwidget.cpp ) qt4_wrap_ui(gammaray_scriptenginedebugger_ui_plugin_srcs scriptenginedebuggerwidget.ui) gammaray_add_plugin(gammaray_scriptenginedebugger_ui_plugin gammaray_scriptenginedebugger_ui.desktop ${gammaray_scriptenginedebugger_ui_plugin_srcs} ) target_link_libraries(gammaray_scriptenginedebugger_ui_plugin ${QT_QTGUI_LIBRARIES} ${QT_QTSCRIPT_LIBRARIES} ${QT_QTSCRIPTTOOLS_LIBRARIES} gammaray_core ) endif() gammaray-2.3.0/plugins/scriptenginedebugger/gammaray_scriptenginedebugger.desktop000066400000000000000000000002741255003167400306500ustar00rootroot00000000000000[Desktop Entry] Name=Script Engines X-GammaRay-Types=QScriptEngine; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_scriptenginedebugger_plugin X-GammaRay-Remote=false gammaray-2.3.0/plugins/scriptenginedebugger/gammaray_scriptenginedebugger.json000066400000000000000000000002121255003167400301400ustar00rootroot00000000000000{ "id": "gammaray_scriptenginedebugger", "name": "Script Engines", "types": [ "QScriptEngine" ], "remoteSupport": false } gammaray-2.3.0/plugins/scriptenginedebugger/gammaray_scriptenginedebugger_ui.desktop000066400000000000000000000002711255003167400313420ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_scriptenginedebugger X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_scriptenginedebugger_ui_plugin X-GammaRay-Remote=false gammaray-2.3.0/plugins/scriptenginedebugger/scriptenginedebugger.cpp000066400000000000000000000044361255003167400261070ustar00rootroot00000000000000/* scriptenginedebugger.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "scriptenginedebugger.h" #include #include #include #include #include #include using namespace GammaRay; ///NOTE: for crashes related to script engine debugger on shutdown, see: /// https://bugreports.qt.nokia.com/browse/QTBUG-21548 /// Also it seems that we get another crash when the interrupt action /// was triggered and we close the mainwindow. ScriptEngineDebugger::ScriptEngineDebugger(ProbeInterface *probe, QObject *parent) : QObject(parent) { ObjectTypeFilterProxyModel *scriptEngineFilter = new ObjectTypeFilterProxyModel(this); scriptEngineFilter->setSourceModel(probe->objectListModel()); SingleColumnObjectProxyModel *singleColumnProxy = new SingleColumnObjectProxyModel(this); singleColumnProxy->setSourceModel(scriptEngineFilter); probe->registerModel("com.kdab.GammaRay.ScriptEngines", singleColumnProxy); } ScriptEngineDebugger::~ScriptEngineDebugger() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(ScriptEngineDebuggerFactory) #endif gammaray-2.3.0/plugins/scriptenginedebugger/scriptenginedebugger.h000066400000000000000000000037611255003167400255540ustar00rootroot00000000000000/* scriptenginedebugger.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCRIPTENGINEDEBUGGER_SCRIPTENGINEDEBUGGER_H #define GAMMARAY_SCRIPTENGINEDEBUGGER_SCRIPTENGINEDEBUGGER_H #include #include namespace GammaRay { class ScriptEngineDebugger : public QObject { Q_OBJECT public: explicit ScriptEngineDebugger(ProbeInterface *probe, QObject *parent = 0); virtual ~ScriptEngineDebugger(); }; class ScriptEngineDebuggerFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_scriptenginedebugger.json") public: explicit ScriptEngineDebuggerFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("Script Engines"); } }; } #endif // GAMMARAY_SCRIPTENGINEDEBUGGER_H gammaray-2.3.0/plugins/scriptenginedebugger/scriptenginedebuggerwidget.cpp000066400000000000000000000054401255003167400273070ustar00rootroot00000000000000/* scriptenginedebuggerwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "scriptenginedebuggerwidget.h" #include "ui_scriptenginedebuggerwidget.h" #include #include #include #include #include #include #include using namespace GammaRay; ///NOTE: for crashes related to script engine debugger on shutdown, see: /// https://bugreports.qt.nokia.com/browse/QTBUG-21548 /// Also it seems that we get another crash when the interrupt action /// was triggered and we close the mainwindow. ScriptEngineDebuggerWidget::ScriptEngineDebuggerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ScriptEngineDebuggerWidget), debugger(new QScriptEngineDebugger(this)) { ui->setupUi(this); ui->scriptEngineComboBox->setModel(ObjectBroker::model("com.kdab.GammaRay.ScriptEngines")); connect(ui->scriptEngineComboBox, SIGNAL(activated(int)), SLOT(scriptEngineSelected(int))); ui->verticalLayout_10->addWidget(debugger->standardWindow()); if (ui->scriptEngineComboBox->count()) { scriptEngineSelected(0); } } ScriptEngineDebuggerWidget::~ScriptEngineDebuggerWidget() { debugger->detach(); } void ScriptEngineDebuggerWidget::scriptEngineSelected(int index) { QObject *obj = ui->scriptEngineComboBox->itemData(index, ObjectModel::ObjectRole).value(); QScriptEngine *engine = qobject_cast(obj); if (engine) { debugger->attachTo(engine); // FIXME: if we'd do that, we'd get crashes on shutdown. // debugger->action(QScriptEngineDebugger::InterruptAction)->trigger(); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(ScriptEngineDebuggerUiFactory) #endif gammaray-2.3.0/plugins/scriptenginedebugger/scriptenginedebuggerwidget.h000066400000000000000000000041171255003167400267540ustar00rootroot00000000000000/* scriptenginedebuggerwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SCRIPTENGINEDEBUGGER_SCRIPTENGINEDEBUGGERWIDGET_H #define GAMMARAY_SCRIPTENGINEDEBUGGER_SCRIPTENGINEDEBUGGERWIDGET_H #include #include #include class QScriptEngineDebugger; namespace GammaRay { namespace Ui { class ScriptEngineDebuggerWidget; } class ScriptEngineDebuggerWidget : public QWidget { Q_OBJECT public: explicit ScriptEngineDebuggerWidget(QWidget *parent = 0); virtual ~ScriptEngineDebuggerWidget(); private slots: void scriptEngineSelected(int index); private: QScopedPointer ui; QScriptEngineDebugger *debugger; }; class ScriptEngineDebuggerUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_scriptenginedebugger.json") }; } #endif // GAMMARAY_SCRIPTENGINEDEBUGGER_H gammaray-2.3.0/plugins/scriptenginedebugger/scriptenginedebuggerwidget.ui000066400000000000000000000010341255003167400271350ustar00rootroot00000000000000 GammaRay::ScriptEngineDebuggerWidget 0 0 400 300 gammaray-2.3.0/plugins/selectionmodelinspector/000077500000000000000000000000001255003167400217335ustar00rootroot00000000000000gammaray-2.3.0/plugins/selectionmodelinspector/CMakeLists.txt000066400000000000000000000016251255003167400244770ustar00rootroot00000000000000# probe part set(gammaray_selectionmodelinspector_plugin_srcs selectionmodelinspector.cpp ) gammaray_add_plugin(gammaray_selectionmodelinspector_plugin gammaray_selectionmodelinspector.desktop ${gammaray_selectionmodelinspector_plugin_srcs} ) target_link_libraries(gammaray_selectionmodelinspector_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) # ui part if(GAMMARAY_BUILD_UI) set(gammaray_selectionmodelinspector_plugin_ui_srcs selectionmodelinspectorwidget.cpp ) qt4_wrap_ui(gammaray_selectionmodelinspector_plugin_ui_srcs selectionmodelinspectorwidget.ui ) gammaray_add_plugin(gammaray_selectionmodelinspector_ui_plugin gammaray_selectionmodelinspector_ui.desktop ${gammaray_selectionmodelinspector_plugin_ui_srcs} ) target_link_libraries(gammaray_selectionmodelinspector_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common ) endif() gammaray-2.3.0/plugins/selectionmodelinspector/gammaray_selectionmodelinspector.desktop000066400000000000000000000002571255003167400321450ustar00rootroot00000000000000[Desktop Entry] Name=Selection Models X-GammaRay-Types=QItemSelectionModel; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_selectionmodelinspector_plugin gammaray-2.3.0/plugins/selectionmodelinspector/gammaray_selectionmodelinspector.json000066400000000000000000000001711255003167400314400ustar00rootroot00000000000000{ "id": "gammaray_selectionmodelinspector", "name": "Selection Models", "types": [ "QItemSelectionModel" ] } gammaray-2.3.0/plugins/selectionmodelinspector/gammaray_selectionmodelinspector_ui.desktop000066400000000000000000000002471255003167400326410ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_selectionmodelinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_selectionmodelinspector_ui_plugin gammaray-2.3.0/plugins/selectionmodelinspector/selectionmodelinspector.cpp000066400000000000000000000053771255003167400274100ustar00rootroot00000000000000/* selectionmodelinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "selectionmodelinspector.h" #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) #include typedef QSortFilterProxyModel QIdentityProxyModel; #else #include #endif using namespace GammaRay; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SelectionModelInspectorFactory) #endif SelectionModelInspector::SelectionModelInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) , m_current(new QIdentityProxyModel(this)) { ObjectTypeFilterProxyModel *selectionModelProxy = new ObjectTypeFilterProxyModel(this); selectionModelProxy->setSourceModel(probe->objectListModel()); probe->registerModel("com.kdab.GammaRay.SelectionModelsModel", selectionModelProxy); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(selectionModelProxy); connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(currentChanged(QModelIndex))); probe->registerModel("com.kdab.GammaRay.CurrentSelectionModel", m_current); } void SelectionModelInspector::currentChanged(const QModelIndex ¤t) { QObject *selectionModelObject = current.data(ObjectModel::ObjectRole).value(); QItemSelectionModel *selectionModel = qobject_cast(selectionModelObject); if (selectionModel && selectionModel->model()) { m_current->setSourceModel(const_cast(selectionModel->model())); } else { m_current->setSourceModel(0); } } gammaray-2.3.0/plugins/selectionmodelinspector/selectionmodelinspector.h000066400000000000000000000042341255003167400270440ustar00rootroot00000000000000/* selectionmodelinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SELECTIONMODELINSPECTOR_SELECTIONMODELINSPECTOR_H #define GAMMARAY_SELECTIONMODELINSPECTOR_SELECTIONMODELINSPECTOR_H #include #include class QAbstractProxyModel; namespace GammaRay { class SelectionModelInspector : public QObject { Q_OBJECT public: explicit SelectionModelInspector(ProbeInterface *probe, QObject *parent = 0); private slots: void currentChanged(const QModelIndex ¤t); private: QAbstractProxyModel *m_current; }; class SelectionModelInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_selectionmodelinspector.json") public: explicit SelectionModelInspectorFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Selection Models"); } }; } #endif // GAMMARAY_SELECTIONMODELINSPECTOR_H gammaray-2.3.0/plugins/selectionmodelinspector/selectionmodelinspectorwidget.cpp000066400000000000000000000040661255003167400306060ustar00rootroot00000000000000/* selectionmodelinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "selectionmodelinspectorwidget.h" #include "ui_selectionmodelinspectorwidget.h" #include #include using namespace GammaRay; SelectionModelInspectorWidget::SelectionModelInspectorWidget(QWidget *widget) : QWidget(widget), ui(new Ui::SelectionModelInspectorWidget) { ui->setupUi(this); ui->selectionModelView->setModel(ObjectBroker::model("com.kdab.GammaRay.SelectionModelsModel")); ui->selectionModelView->setRootIsDecorated(false); ui->selectionModelView->setSelectionModel(ObjectBroker::selectionModel(ui->selectionModelView->model())); ui->selectionModelVisualizer->setRootIsDecorated(false); ui->selectionModelVisualizer->setModel(ObjectBroker::model("com.kdab.GammaRay.CurrentSelectionModel")); } SelectionModelInspectorWidget::~SelectionModelInspectorWidget() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SelectionModelInspectorUiFactory) #endif gammaray-2.3.0/plugins/selectionmodelinspector/selectionmodelinspectorwidget.h000066400000000000000000000037631255003167400302560ustar00rootroot00000000000000/* selectionmodelinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SELECTIONMODELINSPECTOR_SELECTIONMODELINSPECTORWIDGET_H #define GAMMARAY_SELECTIONMODELINSPECTOR_SELECTIONMODELINSPECTORWIDGET_H #include #include class QItemSelection; namespace GammaRay { namespace Ui { class SelectionModelInspectorWidget; } class SelectionModelInspectorWidget : public QWidget { Q_OBJECT public: explicit SelectionModelInspectorWidget(QWidget *widget = 0); ~SelectionModelInspectorWidget(); private: QScopedPointer ui; }; class SelectionModelInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_selectionmodelinspector.json") }; } #endif // GAMMARAY_SELECTIONMODELINSPECTOR_H gammaray-2.3.0/plugins/selectionmodelinspector/selectionmodelinspectorwidget.ui000066400000000000000000000014271255003167400304370ustar00rootroot00000000000000 GammaRay::SelectionModelInspectorWidget 0 0 400 300 Qt::Horizontal gammaray-2.3.0/plugins/signalmonitor/000077500000000000000000000000001255003167400176635ustar00rootroot00000000000000gammaray-2.3.0/plugins/signalmonitor/CMakeLists.txt000066400000000000000000000024061255003167400224250ustar00rootroot00000000000000# shared part set(gammaray_signalmonitor_shared_srcs signalmonitorinterface.cpp signalmonitorcommon.cpp ) add_library(gammaray_signalmonitor_shared STATIC ${gammaray_signalmonitor_shared_srcs}) target_link_libraries(gammaray_signalmonitor_shared LINK_PRIVATE gammaray_common) set_target_properties(gammaray_signalmonitor_shared PROPERTIES POSITION_INDEPENDENT_CODE ON) # probe plugin set(gammaray_signalmonitor_srcs signalmonitor.cpp signalhistorymodel.cpp relativeclock.cpp ) gammaray_add_plugin(gammaray_signalmonitor gammaray_signalmonitor.desktop ${gammaray_signalmonitor_srcs} ) target_link_libraries(gammaray_signalmonitor gammaray_core gammaray_signalmonitor_shared ) if (Qt5_FOUND) target_link_libraries(gammaray_signalmonitor Qt5::Gui) endif () if(GAMMARAY_BUILD_UI) # ui plugin set(gammaray_signalmonitor_ui_srcs signalhistorydelegate.cpp signalhistoryview.cpp signalmonitorwidget.cpp signalmonitorclient.cpp ) qt4_wrap_ui(gammaray_signalmonitor_ui_srcs signalmonitorwidget.ui ) gammaray_add_plugin(gammaray_signalmonitor_ui gammaray_signalmonitor_ui.desktop ${gammaray_signalmonitor_ui_srcs} ) target_link_libraries(gammaray_signalmonitor_ui gammaray_ui gammaray_signalmonitor_shared ) endif() gammaray-2.3.0/plugins/signalmonitor/gammaray_signalmonitor.desktop000066400000000000000000000002121255003167400260140ustar00rootroot00000000000000[Desktop Entry] Name=Signals X-GammaRay-Types="QObject" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_signalmonitor gammaray-2.3.0/plugins/signalmonitor/gammaray_signalmonitor.json000066400000000000000000000001321255003167400253150ustar00rootroot00000000000000{ "id": "gammaray_signalmonitor", "name": "Signals", "types": [ "QObject" ] } gammaray-2.3.0/plugins/signalmonitor/gammaray_signalmonitor_ui.desktop000066400000000000000000000002141255003167400265130ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_signalmonitor X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_signalmonitor_ui gammaray-2.3.0/plugins/signalmonitor/relativeclock.cpp000066400000000000000000000036531255003167400232250ustar00rootroot00000000000000/* relativeclock.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "relativeclock.h" #ifdef Q_OS_LINUX #include #include #endif // Q_OS_LINUX #include using namespace GammaRay; static qint64 appStartTime() { #ifdef Q_OS_LINUX // On Linux the application start time can be read by procfs. const QString &self = QString::fromLatin1("/proc/%1").arg(qApp->applicationPid()); return QFileInfo(self).lastModified().toMSecsSinceEpoch(); #else // !Q_OS_LINUX // On other platforms this is a rough estimation if called early. return QDateTime::currentMSecsSinceEpoch(); #endif // !Q_OS_LINUX } const RelativeClock* RelativeClock::sinceAppStart() { static const RelativeClock clock(appStartTime()); return &clock; } qint64 RelativeClock::currentMSecsSinceEpoch() { return QDateTime::currentMSecsSinceEpoch(); } gammaray-2.3.0/plugins/signalmonitor/relativeclock.h000066400000000000000000000035411255003167400226660ustar00rootroot00000000000000/* relativeclock.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_RELATIVECLOCK_H #define GAMMARAY_RELATIVECLOCK_H #include namespace GammaRay { class RelativeClock { public: explicit RelativeClock(qint64 offset = currentMSecsSinceEpoch()) : m_offset(offset) { } qint64 mSecs() const { return currentMSecsSinceEpoch() - offset(); } qint64 mSecs(qint64 alignment) const; qint64 offset() const { return m_offset; } static const RelativeClock* sinceAppStart(); private: static qint64 currentMSecsSinceEpoch(); private: const qint64 m_offset; }; inline qint64 RelativeClock::mSecs(qint64 alignment) const { const qint64 t = mSecs(); return t - t % alignment; } } // namespace GammaRay #endif // GAMMARAY_RELATIVECLOCK_H gammaray-2.3.0/plugins/signalmonitor/signalhistorydelegate.cpp000066400000000000000000000135551255003167400247720ustar00rootroot00000000000000/* signalhistorydelegate.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalhistorydelegate.h" #include "signalhistorymodel.h" #include "signalmonitorinterface.h" #include "signalmonitorcommon.h" #include #include #include #include #include using namespace GammaRay; SignalHistoryDelegate::SignalHistoryDelegate(QObject *parent) : QStyledItemDelegate(parent) , m_updateTimer(new QTimer(this)) , m_visibleOffset(0) , m_visibleInterval(15000) , m_totalInterval(0) { connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimeout())); m_updateTimer->start(1000 / 25); onUpdateTimeout(); SignalMonitorInterface *iface = ObjectBroker::object(); connect(iface, SIGNAL(clock(qlonglong)), this, SLOT(onServerClockChanged(qlonglong))); iface->sendClockUpdates(true); } void SignalHistoryDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyledItemDelegate::paint(painter, option, index); const qint64 interval = m_visibleInterval; const qint64 startTime = m_visibleOffset; const qint64 endTime = startTime + interval; const QAbstractItemModel *const model = index.model(); const QVector &events = model->data(index, SignalHistoryModel::EventsRole).value >(); const qint64 t0 = qMax(0LL, model->data(index, SignalHistoryModel::StartTimeRole).value() - startTime); qint64 t1 = model->data(index, SignalHistoryModel::EndTimeRole).value(); if (t1 < 0) // still alive t1 = m_totalInterval; t1 -= startTime; const qint64 dt = qMax(0LL, t1) - t0; const int x0 = option.rect.x() + 1; const int y0 = option.rect.y(); const int dx = option.rect.width() - 2; const int dy = option.rect.height(); const int x1 = x0 + dx * t0 / interval; const int x2 = dx * dt / interval + 1; if (t1 >= 0) { painter->fillRect(x1, y0 + 1, x2, dy - 2, option.palette.window()); } painter->setPen(option.palette.color(QPalette::WindowText)); foreach (qint64 ev, events) { const qint64 ts = SignalHistoryModel::timestamp(ev); if (ts >= startTime && ts < endTime) { const int x = x0 + dx * (ts - startTime) / interval; painter->drawLine(x, y0 + 1, x, y0 + dy - 2); } } } QSize SignalHistoryDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { return QSize(0, option.fontMetrics.lineSpacing()); // FIXME: minimum height } void SignalHistoryDelegate::setVisibleInterval(qint64 interval) { if (m_visibleInterval != interval) { m_visibleInterval = interval; emit visibleIntervalChanged(m_visibleInterval); } } void SignalHistoryDelegate::setVisibleOffset(qint64 offset) { setActive(false); if (m_visibleOffset != offset) { m_visibleOffset = offset; emit visibleOffsetChanged(m_visibleOffset); } } void SignalHistoryDelegate::onUpdateTimeout() { // move the visible region to show the most recent samples m_visibleOffset = m_totalInterval - m_visibleInterval; emit visibleOffsetChanged(m_visibleOffset); } void SignalHistoryDelegate::onServerClockChanged(qint64 msecs) { m_totalInterval = msecs; emit totalIntervalChanged(); } void SignalHistoryDelegate::setActive(bool active) { if (m_updateTimer->isActive() != active) { if (active) { m_updateTimer->start(); } else { m_updateTimer->stop(); } emit isActiveChanged(isActive()); } } bool SignalHistoryDelegate::isActive() const { return m_updateTimer->isActive(); } QString SignalHistoryDelegate::toolTipAt(const QModelIndex &index, int position, int width) { const QAbstractItemModel *const model = index.model(); const QVector &events = model->data(index, SignalHistoryModel::EventsRole).value >(); const qint64 t = m_visibleInterval * position / width + m_visibleOffset; qint64 dtMin = std::numeric_limits::max(); int signalIndex = -1; qint64 signalTimestamp = -1; for (int i = 0; i < events.size(); ++i) { signalTimestamp = SignalHistoryModel::timestamp(events.at(i)); const qint64 dt = qAbs(signalTimestamp - t); if (dt < dtMin) { signalIndex = SignalHistoryModel::signalIndex(events.at(i)); dtMin = dt; } } if (signalIndex < 0) return QString(); const auto signalNames = index.data(SignalHistoryModel::SignalMapRole).value >(); const auto it = signalNames.constFind(signalIndex); QString signalName; // see SignalHistoryModel, we store this with offset 1 to fit unknown ones into an unsigned value if (signalIndex == 0 || it == signalNames.constEnd() || it.value().isEmpty()) signalName = tr(""); else signalName = it.value(); const QString &ts = QLocale().toString(signalTimestamp); return tr("%1 at %2 ms").arg(signalName, ts); } gammaray-2.3.0/plugins/signalmonitor/signalhistorydelegate.h000066400000000000000000000054341255003167400244340ustar00rootroot00000000000000/* signalhistorydelegate.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALHISTORYDELEGATE_H #define GAMMARAY_SIGNALHISTORYDELEGATE_H #include namespace GammaRay { class SignalHistoryDelegate : public QStyledItemDelegate { Q_OBJECT Q_PROPERTY(qint64 visibleInterval READ visibleInterval WRITE setVisibleInterval NOTIFY visibleIntervalChanged) Q_PROPERTY(qint64 visibleOffset READ visibleOffset NOTIFY setVisibleOffset NOTIFY visibleOffsetChanged) Q_PROPERTY(bool isActive READ isActive WRITE setActive NOTIFY isActiveChanged) public: explicit SignalHistoryDelegate(QObject *parent = 0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; void setVisibleInterval(qint64 interval); qint64 visibleInterval() const { return m_visibleInterval; } void setVisibleOffset(qint64 offset); qint64 visibleOffset() const { return m_visibleOffset; } qint64 totalInterval() const { return m_totalInterval; } void setActive(bool isActive); bool isActive() const; QString toolTipAt(const QModelIndex &index, int position, int width); signals: void visibleIntervalChanged(qint64 value); void visibleOffsetChanged(qint64 value); void isActiveChanged(bool value); void totalIntervalChanged(); private slots: void onUpdateTimeout(); void onServerClockChanged(qlonglong msecs); private: QTimer *const m_updateTimer; qint64 m_visibleOffset; qint64 m_visibleInterval; qint64 m_totalInterval; }; } // namespace GammaRay #endif // GAMMARAY_SIGNALHISTORYDELEGATE_H gammaray-2.3.0/plugins/signalmonitor/signalhistorymodel.cpp000066400000000000000000000173601255003167400243160ustar00rootroot00000000000000/* signalhistorymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalhistorymodel.h" #include "relativeclock.h" #include "signalmonitorcommon.h" #include #include #include #include #include #include #include using namespace GammaRay; /// Tries to reuse an already existing instances of \param str by checking /// a global string pool. If no instance of \param str is interned yet the /// string will be added to the pool. template static T internString(const T &str) { static QSet pool; // Check if the pool already contains the string... const typename QSet::const_iterator it = pool.find(str); // ...and return it if possible. if (it != pool.end()) return *it; // Otherwise add the string to the pool. pool.insert(str); return str; } static SignalHistoryModel *s_historyModel = 0; static void signal_begin_callback(QObject *caller, int method_index, void **argv) { Q_UNUSED(argv); if (s_historyModel) { const int signalIndex = method_index + 1; // offset 1, so unknown signals end up at 0 static const QMetaMethod m = s_historyModel->metaObject()->method(s_historyModel->metaObject()->indexOfMethod("onSignalEmitted(QObject*,int)")); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_ASSERT(m.isValid()); #endif m.invoke(s_historyModel, Qt::AutoConnection, Q_ARG(QObject*, caller), Q_ARG(int, signalIndex)); } } SignalHistoryModel::SignalHistoryModel(ProbeInterface *probe, QObject *parent) : QAbstractTableModel(parent) { connect(probe->probe(), SIGNAL(objectCreated(QObject*)), this, SLOT(onObjectAdded(QObject*))); connect(probe->probe(), SIGNAL(objectDestroyed(QObject*)), this, SLOT(onObjectRemoved(QObject*))); SignalSpyCallbackSet spy; spy.signalBeginCallback = signal_begin_callback; probe->registerSignalSpyCallbackSet(spy); s_historyModel = this; } SignalHistoryModel::~SignalHistoryModel() { s_historyModel = 0; } int SignalHistoryModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return m_tracedObjects.size(); } int SignalHistoryModel::columnCount(const QModelIndex &) const { return 3; } SignalHistoryModel::Item* SignalHistoryModel::item(const QModelIndex& index) const { if (!index.isValid()) return 0; return m_tracedObjects.at(index.row()); } QVariant SignalHistoryModel::data(const QModelIndex &index, int role) const { switch (static_cast(index.column())) { case ObjectColumn: if (role == Qt::DisplayRole) return item(index)->objectName; if (role == Qt::ToolTipRole) return item(index)->toolTip; if (role == Qt::DecorationRole) return item(index)->decoration; break; case TypeColumn: if (role == Qt::DisplayRole) return item(index)->objectType; if (role == Qt::ToolTipRole) return item(index)->toolTip; break; case EventColumn: if (role == EventsRole) return QVariant::fromValue(item(index)->events); if (role == StartTimeRole) return item(index)->startTime; if (role == EndTimeRole) return item(index)->endTime(); if (role == SignalMapRole) return QVariant::fromValue(item(index)->signalNames); break; } return QVariant(); } QVariant SignalHistoryModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case ObjectColumn: return tr("Object"); case TypeColumn: return tr("Type"); case EventColumn: return tr("Events"); } } return QVariant(); } QMap< int, QVariant > SignalHistoryModel::itemData(const QModelIndex& index) const { QMap d = QAbstractItemModel::itemData(index); d.insert(EventsRole, data(index, EventsRole)); d.insert(StartTimeRole, data(index, StartTimeRole)); d.insert(EndTimeRole, data(index, EndTimeRole)); d.insert(SignalMapRole, data(index, SignalMapRole)); return d; } void SignalHistoryModel::onObjectAdded(QObject* object) { Q_ASSERT(thread() == QThread::currentThread()); // blacklist event dispatchers if (qstrncmp(object->metaObject()->className(), "QPAEventDispatcher", 18) == 0 || qstrncmp(object->metaObject()->className(), "QGuiEventDispatcher", 19) == 0 || qstrncmp(object->metaObject()->className(), "QEventDispatcher", 16) == 0) return; beginInsertRows(QModelIndex(), m_tracedObjects.size(), m_tracedObjects.size()); Item *const data = new Item(object); m_itemIndex.insert(object, m_tracedObjects.size()); m_tracedObjects.push_back(data); endInsertRows(); } void SignalHistoryModel::onObjectRemoved(QObject* object) { Q_ASSERT(thread() == QThread::currentThread()); const auto it = m_itemIndex.find(object); if (it == m_itemIndex.end()) return; const int itemIndex = *it; m_itemIndex.erase(it); Item *data = m_tracedObjects.at(itemIndex); Q_ASSERT(data->object == object); data->object = 0; emit dataChanged(index(itemIndex, EventColumn), index(itemIndex, EventColumn)); } void SignalHistoryModel::onSignalEmitted(QObject *sender, int signalIndex) { Q_ASSERT(thread() == QThread::currentThread()); const qint64 timestamp = RelativeClock::sinceAppStart()->mSecs(); const auto it = m_itemIndex.constFind(sender); if (it == m_itemIndex.constEnd()) return; const int itemIndex = *it; Item *data = m_tracedObjects.at(itemIndex); Q_ASSERT(data->object == sender); // ensure the item is known if (signalIndex > 0 && !data->signalNames.contains(signalIndex)) { // protect dereferencing of sender here QMutexLocker lock(Probe::objectLock()); if (!Probe::instance()->isValidObject(sender)) return; const QByteArray signalName = sender->metaObject()->method(signalIndex - 1) #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) .signature(); #else .methodSignature(); #endif data->signalNames.insert(signalIndex, internString(signalName)); } data->events.push_back((timestamp << 16) | signalIndex); emit dataChanged(index(itemIndex, EventColumn), index(itemIndex, EventColumn)); } SignalHistoryModel::Item::Item(QObject *obj) : object(obj) , startTime(RelativeClock::sinceAppStart()->mSecs()) { objectName = Util::shortDisplayString(object); objectType = internString(QByteArray(obj->metaObject()->className())); toolTip = Util::tooltipForObject(object); decoration = Util::iconForObject(object).value(); } qint64 SignalHistoryModel::Item::endTime() const { if (object) return -1; // still alive if (!events.isEmpty()) return timestamp(events.size() - 1); return startTime; } gammaray-2.3.0/plugins/signalmonitor/signalhistorymodel.h000066400000000000000000000064241255003167400237620ustar00rootroot00000000000000/* signalhistorymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALHISTORYMODEL_H #define GAMMARAY_SIGNALHISTORYMODEL_H #include #include #include #include #include #include namespace GammaRay { class ProbeInterface; class SignalHistoryModel : public QAbstractTableModel { Q_OBJECT private: struct Item { Item(QObject *obj); QObject* object; // never dereference, might be invalid! QHash signalNames; QString objectName; QByteArray objectType; QString toolTip; QIcon decoration; QVector events; const qint64 startTime; // FIXME: make them all methods qint64 endTime() const; qint64 timestamp(int i) const { return SignalHistoryModel::timestamp(events.at(i)); } int signalIndex(int i) const { return SignalHistoryModel::signalIndex(events.at(i)); } }; public: enum ColumnId { ObjectColumn, TypeColumn, EventColumn }; enum RoleId { EventsRole = ObjectModel::UserRole + 1, StartTimeRole, EndTimeRole, SignalMapRole }; explicit SignalHistoryModel(ProbeInterface *probe, QObject *parent = 0); ~SignalHistoryModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap itemData(const QModelIndex &index) const Q_DECL_OVERRIDE; static qint64 timestamp(qint64 ev) { return ev >> 16; } static int signalIndex(qint64 ev) { return ev & 0xffff; } private: Item *item(const QModelIndex &index) const; private slots: void onObjectAdded(QObject *object); void onObjectRemoved(QObject *object); void onSignalEmitted(QObject *sender, int signalIndex); private: QVector m_tracedObjects; QHash m_itemIndex; }; } // namespace GammaRay #endif // GAMMARAY_SIGNALHISTORYMODEL_H gammaray-2.3.0/plugins/signalmonitor/signalhistoryview.cpp000066400000000000000000000105161255003167400241640ustar00rootroot00000000000000/* signalhistoryview.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalhistoryview.h" #include "signalhistorydelegate.h" #include "signalhistorymodel.h" #include #include #include #include using namespace GammaRay; SignalHistoryView::SignalHistoryView(QWidget *parent) : QTreeView(parent) , m_eventDelegate(new SignalHistoryDelegate(this)) , m_eventScrollBar(0) { new DeferredResizeModeSetter(header(), 0, QHeaderView::Interactive); new DeferredResizeModeSetter(header(), 1, QHeaderView::Interactive); new DeferredResizeModeSetter(header(), 2, QHeaderView::Stretch); setItemDelegateForColumn(SignalHistoryModel::EventColumn, m_eventDelegate); connect(m_eventDelegate, SIGNAL(visibleOffsetChanged(qint64)), this, SLOT(eventDelegateChanged())); connect(m_eventDelegate, SIGNAL(visibleIntervalChanged(qint64)), this, SLOT(eventDelegateChanged())); connect(m_eventDelegate, SIGNAL(totalIntervalChanged()), this, SLOT(eventDelegateChanged())); } void SignalHistoryView::eventDelegateChanged() { viewport()->update(eventColumnPosition(), 0, eventColumnWidth(), height()); if (m_eventScrollBar) { const bool signalsBlocked = m_eventScrollBar->blockSignals(true); // With 31 bits we cover more than 24 days when counting milliseconds. // That's much more time than this tool can handle. IMHO. m_eventScrollBar->setMaximum( qMax(m_eventDelegate->totalInterval() - m_eventDelegate->visibleInterval(), 0LL)); m_eventScrollBar->setSingleStep(m_eventDelegate->visibleInterval() / 10); m_eventScrollBar->setPageStep(m_eventDelegate->visibleInterval()); if (m_eventDelegate->isActive()) { m_eventScrollBar->setValue(m_eventScrollBar->maximum()); } m_eventScrollBar->blockSignals(signalsBlocked); } } void SignalHistoryView::setEventScrollBar(QScrollBar *scrollBar) { if (m_eventScrollBar != scrollBar) { if (m_eventScrollBar) { disconnect(m_eventScrollBar, 0, this, 0); } m_eventScrollBar = scrollBar; if (m_eventScrollBar) { connect(m_eventScrollBar, SIGNAL(sliderMoved(int)), this, SLOT(eventScrollBarSliderMoved(int))); } } } int SignalHistoryView::eventColumnPosition() const { return columnViewportPosition(SignalHistoryModel::EventColumn); } int SignalHistoryView::eventColumnWidth() const { return columnWidth(SignalHistoryModel::EventColumn); } void SignalHistoryView::eventScrollBarSliderMoved(int value) { m_eventDelegate->setActive(false); m_eventDelegate->setVisibleOffset(value); } bool SignalHistoryView::viewportEvent(QEvent *event) { if (event->type() == QEvent::ToolTip) { const QHelpEvent *const help = static_cast(event); const QModelIndex index = indexAt(help->pos()); if (index.isValid() && index.column() == SignalHistoryModel::EventColumn) { const int x0 = help->pos().x() - eventColumnPosition(); const int dx = eventColumnWidth(); const QString &toolTipText = m_eventDelegate->toolTipAt(index, x0, dx); if (!toolTipText.isEmpty()) { QToolTip::showText(help->globalPos(), toolTipText); } else { QToolTip::hideText(); event->ignore(); } return true; } } return QTreeView::viewportEvent(event); } gammaray-2.3.0/plugins/signalmonitor/signalhistoryview.h000066400000000000000000000043641255003167400236350ustar00rootroot00000000000000/* signalhistoryview.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALHISTORYVIEW_H #define GAMMARAY_SIGNALHISTORYVIEW_H #include namespace GammaRay { class SignalHistoryDelegate; class SignalHistoryView : public QTreeView { Q_OBJECT Q_PROPERTY(QScrollBar *eventScrollBar READ eventScrollBar WRITE setEventScrollBar NOTIFY eventScrollBarChanged) Q_PROPERTY(SignalHistoryDelegate *eventDelegate READ eventDelegate FINAL CONSTANT) public: explicit SignalHistoryView(QWidget *parent = 0); void setEventScrollBar(QScrollBar *scrollBar); QScrollBar *eventScrollBar() const { return m_eventScrollBar; } SignalHistoryDelegate *eventDelegate() const { return m_eventDelegate; } int eventColumnPosition() const; int eventColumnWidth() const; signals: void eventScrollBarChanged(QScrollBar *scrollBar); protected: bool viewportEvent(QEvent *event) Q_DECL_OVERRIDE; private slots: void eventDelegateChanged(); void eventScrollBarSliderMoved(int value); private: SignalHistoryDelegate *const m_eventDelegate; QScrollBar *m_eventScrollBar; }; } // namespace GammaRay #endif // GAMMARAY_SIGNALHISTORYVIEW_H gammaray-2.3.0/plugins/signalmonitor/signalmonitor.cpp000066400000000000000000000042701255003167400232570ustar00rootroot00000000000000/* signalmonitor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitor.h" #include "signalhistorymodel.h" #include "relativeclock.h" #include "signalmonitorcommon.h" #include using namespace GammaRay; SignalMonitor::SignalMonitor(ProbeInterface *probe, QObject *parent) : SignalMonitorInterface(parent) { StreamOperators::registerSignalMonitorStreamOperators(); SignalHistoryModel *model = new SignalHistoryModel(probe, this); probe->registerModel("com.kdab.GammaRay.SignalHistoryModel", model); m_clock = new QTimer(this); m_clock->setInterval(1000/25); // update frequency of the delegate, we could slow this down a lot, and let the client interpolate, if necessary m_clock->setSingleShot(false); connect(m_clock, SIGNAL(timeout()), this, SLOT(timeout())); } SignalMonitor::~SignalMonitor() { } void SignalMonitor::timeout() { emit clock(RelativeClock::sinceAppStart()->mSecs()); } void SignalMonitor::sendClockUpdates(bool enabled) { if (enabled) m_clock->start(); else m_clock->stop(); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SignalMonitorFactory) #endif gammaray-2.3.0/plugins/signalmonitor/signalmonitor.h000066400000000000000000000041701255003167400227230ustar00rootroot00000000000000/* signalmonitor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITOR_H #define GAMMARAY_SIGNALMONITOR_H #include "signalmonitorinterface.h" #include class QTimer; namespace GammaRay { class SignalMonitor : public SignalMonitorInterface { Q_OBJECT Q_INTERFACES(GammaRay::SignalMonitorInterface) public: explicit SignalMonitor(ProbeInterface *probe, QObject *parent = 0); ~SignalMonitor(); public slots: void sendClockUpdates(bool enabled) Q_DECL_OVERRIDE; private slots: void timeout(); private: QTimer *m_clock; }; class SignalMonitorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_signalmonitor.json") public: explicit SignalMonitorFactory(QObject *parent = 0) : QObject(parent) { } virtual inline QString name() const { return tr("Signals"); } }; } // namespace GammaRay #endif // GAMMARAY_SIGNALMONITOR_H gammaray-2.3.0/plugins/signalmonitor/signalmonitorclient.cpp000066400000000000000000000030331255003167400244520ustar00rootroot00000000000000/* signalmonitorclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitorclient.h" #include using namespace GammaRay; SignalMonitorClient::SignalMonitorClient(QObject* parent): SignalMonitorInterface(parent) { } SignalMonitorClient::~SignalMonitorClient() { } void SignalMonitorClient::sendClockUpdates(bool enabled) { Endpoint::instance()->invokeObject(objectName(), "sendClockUpdates", QVariantList() << QVariant::fromValue(enabled)); } gammaray-2.3.0/plugins/signalmonitor/signalmonitorclient.h000066400000000000000000000031221255003167400241160ustar00rootroot00000000000000/* signalmonitorclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITORCLIENT_H #define GAMMARAY_SIGNALMONITORCLIENT_H #include "signalmonitorinterface.h" namespace GammaRay { class SignalMonitorClient : public SignalMonitorInterface { Q_OBJECT Q_INTERFACES(GammaRay::SignalMonitorInterface) public: explicit SignalMonitorClient(QObject* parent = 0); ~SignalMonitorClient(); public slots: void sendClockUpdates(bool enabled) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_SIGNALMONITORCLIENT_H gammaray-2.3.0/plugins/signalmonitor/signalmonitorcommon.cpp000066400000000000000000000026251255003167400244720ustar00rootroot00000000000000/* signalmonitorcommon.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitorcommon.h" #include using namespace GammaRay; void GammaRay::StreamOperators::registerSignalMonitorStreamOperators() { qRegisterMetaTypeStreamOperators >(); qRegisterMetaTypeStreamOperators >(); } gammaray-2.3.0/plugins/signalmonitor/signalmonitorcommon.h000066400000000000000000000031311255003167400241300ustar00rootroot00000000000000/* signalmonitorcommon.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITORCOMMON_H #define GAMMARAY_SIGNALMONITORCOMMON_H #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_DECLARE_METATYPE(QVector) typedef QHash IntByteArrayHash; Q_DECLARE_METATYPE(IntByteArrayHash) #endif namespace GammaRay { namespace StreamOperators { void registerSignalMonitorStreamOperators(); } } #endif // GAMMARAY_SIGNALMONITORCOMMON_H gammaray-2.3.0/plugins/signalmonitor/signalmonitorinterface.cpp000066400000000000000000000026551255003167400251450ustar00rootroot00000000000000/* signalmonitorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitorinterface.h" #include using namespace GammaRay; SignalMonitorInterface::SignalMonitorInterface(QObject* parent): QObject(parent) { ObjectBroker::registerObject(this); } SignalMonitorInterface::~SignalMonitorInterface() { } gammaray-2.3.0/plugins/signalmonitor/signalmonitorinterface.h000066400000000000000000000032421255003167400246030ustar00rootroot00000000000000/* signalmonitorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITORINTERFACE_H #define GAMMARAY_SIGNALMONITORINTERFACE_H #include namespace GammaRay { class SignalMonitorInterface : public QObject { Q_OBJECT public: explicit SignalMonitorInterface(QObject *parent = 0); ~SignalMonitorInterface(); public slots: virtual void sendClockUpdates(bool enabled) = 0; signals: void clock(qlonglong msecs); }; } Q_DECLARE_INTERFACE(GammaRay::SignalMonitorInterface, "com.kdab.GammaRay.SignalMonitorInterface/1.0") #endif // GAMMARAY_SIGNALMONITORINTERFACE_H gammaray-2.3.0/plugins/signalmonitor/signalmonitorwidget.cpp000066400000000000000000000105731255003167400244660ustar00rootroot00000000000000/* signalmonitorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitorwidget.h" #include "ui_signalmonitorwidget.h" #include "signalhistorydelegate.h" #include "signalhistorymodel.h" #include "signalmonitorclient.h" #include "signalmonitorcommon.h" #include #include #include using namespace GammaRay; static QObject* signalMonitorClientFactory(const QString&, QObject *parent) { return new SignalMonitorClient(parent); } SignalMonitorWidget::SignalMonitorWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::SignalMonitorWidget) { StreamOperators::registerSignalMonitorStreamOperators(); ObjectBroker::registerClientObjectFactoryCallback(signalMonitorClientFactory); ui->setupUi(this); QAbstractItemModel *const signalHistory = ObjectBroker::model("com.kdab.GammaRay.SignalHistoryModel"); QSortFilterProxyModel *const searchProxy = new KRecursiveFilterProxyModel(this); searchProxy->setSourceModel(signalHistory); searchProxy->setDynamicSortFilter(true); ui->objectSearchLine->setProxy(searchProxy); ui->objectTreeView->setModel(searchProxy); //ui->objectTreeView->setSelectionModel(ObjectBroker::selectionModel(ui->objectTreeView->model())); ui->objectTreeView->setEventScrollBar(ui->eventScrollBar); connect(ui->pauseButton, SIGNAL(toggled(bool)), this, SLOT(pauseAndResume(bool))); connect(ui->intervalScale, SIGNAL(valueChanged(int)), this, SLOT(intervalScaleValueChanged(int))); connect(ui->objectTreeView->eventDelegate(), SIGNAL(isActiveChanged(bool)), this, SLOT(eventDelegateIsActiveChanged(bool))); connect(ui->objectTreeView->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(adjustEventScrollBarSize())); } SignalMonitorWidget::~SignalMonitorWidget() { } void SignalMonitorWidget::intervalScaleValueChanged(int value) { // FIXME: Define a more reasonable formula. qint64 i = 5000 / std::pow(1.07, value); ui->objectTreeView->eventDelegate()->setVisibleInterval(i); } void SignalMonitorWidget::adjustEventScrollBarSize() { // FIXME: Would like to have this in SignalHistoryView, but letting that // widget manage layouts of this widget would be nasty. Still I also I don't // feel like hooking a custom scrollbar into QTreeView. Sleeping between a // rock and a hard place. const QWidget *const scrollBar = ui->objectTreeView->verticalScrollBar(); const QWidget *const viewport = ui->objectTreeView->viewport(); const int eventColumnLeft = ui->objectTreeView->eventColumnPosition(); const int scrollBarLeft = scrollBar->mapTo(this, scrollBar->pos()).x(); const int viewportLeft = viewport->mapTo(this, viewport->pos()).x(); const int viewportRight = viewportLeft + viewport->width(); ui->eventScrollBarLayout->setContentsMargins(eventColumnLeft, scrollBarLeft - viewportRight, width() - viewportRight, 0); } void SignalMonitorWidget::pauseAndResume(bool pause) { ui->objectTreeView->eventDelegate()->setActive(!pause); } void SignalMonitorWidget::eventDelegateIsActiveChanged(bool active) { ui->pauseButton->setChecked(!active); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(SignalMonitorUiFactory) #endif gammaray-2.3.0/plugins/signalmonitor/signalmonitorwidget.h000066400000000000000000000041101255003167400241210ustar00rootroot00000000000000/* signalmonitorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITORWIDGET_H #define GAMMARAY_SIGNALMONITORWIDGET_H #include "ui/tooluifactory.h" #include namespace GammaRay { namespace Ui { class SignalMonitorWidget; } class SignalMonitorWidget : public QWidget { Q_OBJECT public: explicit SignalMonitorWidget(QWidget *parent = 0); ~SignalMonitorWidget(); private slots: void intervalScaleValueChanged(int value); void adjustEventScrollBarSize(); void pauseAndResume(bool pause); void eventDelegateIsActiveChanged(bool active); private: static const QString ITEM_TYPE_NAME_OBJECT; QScopedPointer ui; }; class SignalMonitorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_signalmonitor.json") }; } // namespace GammaRay #endif // GAMMARAY_SIGNALMONITORWIDGET_H gammaray-2.3.0/plugins/signalmonitor/signalmonitorwidget.ui000066400000000000000000000066651255003167400243300ustar00rootroot00000000000000 GammaRay::SignalMonitorWidget 0 0 400 300 Form 0 6 Pause true Qt::Horizontal 40 20 Zoom Level: -100 100 0 Qt::Horizontal Qt::ScrollBarAlwaysOff QAbstractItemView::SingleSelection false true 0 0 true Qt::Horizontal KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
GammaRay::SignalHistoryView QTreeView
signalhistoryview.h
gammaray-2.3.0/plugins/statemachineviewer/000077500000000000000000000000001255003167400206655ustar00rootroot00000000000000gammaray-2.3.0/plugins/statemachineviewer/CMakeLists.txt000066400000000000000000000070521255003167400234310ustar00rootroot00000000000000# shared part set(gammaray_statemachineviewer_shared_srcs statemachineviewerinterface.cpp ) # probe part set(gammaray_statemachineviewer_plugin_srcs statemachineviewerserver.cpp transitionmodel.cpp statemodel.cpp statemachinewatcher.cpp ) gammaray_add_plugin(gammaray_statemachineviewer_plugin gammaray_statemachineviewer.desktop ${gammaray_statemachineviewer_shared_srcs} ${gammaray_statemachineviewer_plugin_srcs} ) target_link_libraries(gammaray_statemachineviewer_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) # UI part - dependencies set(GRAPHVIZ_MIN_VERSION "2.20") find_package(Graphviz) set_package_properties(Graphviz PROPERTIES TYPE RECOMMENDED DESCRIPTION "Graph visualization software" URL "http://www.graphviz.org/" PURPOSE "Needed for the state machine visualizer plugin." ) set(HAVE_GRAPHVIZ ${GRAPHVIZ_FOUND}) if(GRAPHVIZ_FOUND) add_definitions(-DGRAPHVIZ_MAJOR_VERSION=${GRAPHVIZ_MAJOR_VERSION} -DGRAPHVIZ_MINOR_VERSION=${GRAPHVIZ_MINOR_VERSION}) endif() set_package_properties(KDSME PROPERTIES URL "https://github.com/KDAB/KDStateMachineEditor" DESCRIPTION "KDAB State Machine Editor framework" TYPE OPTIONAL PURPOSE "Provide Next-gen graphical state machine viewer for the statmeachineviewer plugin.") if (Qt5_FOUND) find_package(KDSME CONFIG QUIET) endif() # UI part if(GAMMARAY_BUILD_UI AND (GRAPHVIZ_FOUND OR KDSME_FOUND)) set(gammaray_statemachineviewer_ui_plugin_libs ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common gammaray_ui ) set(gammaray_statemachineviewer_ui_plugin_srcs statemachineviewerclient.cpp statemachineview.cpp ) if (KDSME_FOUND AND Qt5Quick_FOUND) # new KDSME varaint list(APPEND gammaray_statemachineviewer_ui_plugin_srcs statemachineviewerwidgetng.cpp ) list(APPEND gammaray_statemachineviewer_ui_plugin_libs KDSME::Core KDSME::View ) else() # old Graphviz-based variant list(APPEND gammaray_statemachineviewer_ui_plugin_srcs gvgraph/gvgraph.cpp gvgraph/gvgraphitems.cpp gvgraph/gvutils.cpp statemachineviewerwidget.cpp ) include_directories( ${GRAPHVIZ_INCLUDE_DIR} # TODO: Work-around issue in graphviz/types.h header # is included there, but it should rather be "cgraph.h" ${GRAPHVIZ_INCLUDE_DIR}/graphviz ) list(APPEND gammaray_statemachineviewer_ui_plugin_libs ${GRAPHVIZ_GVC_LIBRARY} ) if(GRAPHVIZ_CGRAPH_LIBRARY AND GRAPHVIZ_VERSION VERSION_GREATER 2.30.0) message(STATUS "Enabling use of experimental 'cgraph' library of GraphViz") # you must add this define when using cgraph from graphviz # some headers check for this define (see for example graphviz/types.h header) add_definitions(-DWITH_CGRAPH) list(APPEND gammaray_statemachineviewer_ui_plugin_libs ${GRAPHVIZ_CGRAPH_LIBRARY} ) else() list(APPEND gammaray_statemachineviewer_ui_plugin_libs ${GRAPHVIZ_GRAPH_LIBRARY} ) endif() add_definitions(${GRAPHVIZ_COMPILE_FLAGS}) add_executable(statemachineviewer_test gvgraph/gvgraph.cpp gvgraph/gvgraphitems.cpp gvgraph/gvutils.cpp test_main.cpp ) target_link_libraries(statemachineviewer_test ${gammaray_statemachineviewer_ui_plugin_libs}) endif() qt4_wrap_ui(gammaray_statemachineviewer_ui_plugin_srcs statemachineviewer.ui) gammaray_add_plugin(gammaray_statemachineviewer_ui_plugin gammaray_statemachineviewer_ui.desktop ${gammaray_statemachineviewer_shared_srcs} ${gammaray_statemachineviewer_ui_plugin_srcs} ) target_link_libraries(gammaray_statemachineviewer_ui_plugin ${gammaray_statemachineviewer_ui_plugin_libs} ) endif() gammaray-2.3.0/plugins/statemachineviewer/gammaray_statemachineviewer.desktop000066400000000000000000000002431255003167400300240ustar00rootroot00000000000000[Desktop Entry] Name=State Machines X-GammaRay-Types=QAbstractState; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_statemachineviewer_plugin gammaray-2.3.0/plugins/statemachineviewer/gammaray_statemachineviewer.json000066400000000000000000000001551255003167400273260ustar00rootroot00000000000000{ "id": "gammaray_statemachineviewer", "name": "State Machines", "types": [ "QAbstractState" ] } gammaray-2.3.0/plugins/statemachineviewer/gammaray_statemachineviewer_ui.desktop000066400000000000000000000002351255003167400305220ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_statemachineviewer X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_statemachineviewer_ui_plugin gammaray-2.3.0/plugins/statemachineviewer/gvgraph/000077500000000000000000000000001255003167400223235ustar00rootroot00000000000000gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvgraph.cpp000066400000000000000000000320251255003167400244670ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gvgraph.h" #include "gvutils.h" #include #ifdef WITH_CGRAPH # include #else # include #endif #include #include #include #include using namespace GammaRay; using namespace GammaRay::GVUtils; using namespace std; /*! Dot uses a 72 * DPI value for converting it's position coordinates from points to pixels while we display at 96 DPI on most operating systems. */ const qreal DotDefaultDPI = 72.0; GVGraph::GVGraph(const QString &name) : _context(gvContext()), _graph(0), _name(name) { createGraph(); } void GVGraph::createGraph() { Q_ASSERT(_context); #ifdef WITH_CGRAPH _graph = _agopen(_name, Agdirected, &AgDefaultDisc); #else _graph = _agopen(_name, AGDIGRAPHSTRICT); // Strict directed graph, see libgraph doc #endif Q_ASSERT(_graph); _graphMap.insert(_graph, GVSubGraph("ROOT")); _agset(_graph, "overlap", "prism"); _agset(_graph, "splines", "true"); _agset(_graph, "pad", "0,2"); _agset(_graph, "dpi", "96,0"); _agset(_graph, "nodesep", "0,4"); setFont(_font); } void GVGraph::closeGraph() { gvFreeLayout(_context, _graph); agclose(_graph); _graph = 0; } void GVGraph::clear() { closeGraph(); _graphMap.clear(); _nodeMap.clear(); _edgeMap.clear(); createGraph(); } GVGraph::~GVGraph() { closeGraph(); } GraphId GVGraph::addGraph(const QString &name) { return addGraph(name, _graph); } GraphId GVGraph::addGraph(const QString &name, GraphId subGraphId) { Agraph_t *graph = agGraph(subGraphId); return addGraph(name, graph); } GraphId GVGraph::addGraph(const QString &name, Agraph_t *graph) { if (!graph) { qWarning() << "Subgraph does not exist:" << graph; return 0; } const QString realName = "cluster" + name; Agraph_t *subGraph = _agsubg(graph, realName); Q_ASSERT(subGraph); _graphMap.insert(subGraph, GVSubGraph(realName)); return (GraphId)subGraph; } void GVGraph::removeGraph(GraphId graphId) { Agraph_t *graph = agGraph(graphId); if (!graph) { return; } Agnode_t *node = agfstnode(graph); while (node) { removeNode(id(node)); node = agnxtnode(_graph, node); } agdelete(_graph, graph); _graphMap.remove(graph); } NodeId GVGraph::addNode(const QString &name, GraphId subGraphId) { Agraph_t *graph = agGraph(subGraphId); return addNode(name, graph); } NodeId GVGraph::addNode(const QString &name, Agraph_t *graph) { if (!graph) { qWarning() << Q_FUNC_INFO << "Node not added, graph is NULL:" << name; return 0; } // TODO: Check for duplicates? Agnode_t *node = _agnode(graph, name); Q_ASSERT(node); _agset(node, "label", name); _nodeMap.insert(node, GVNode(name)); return (NodeId)node; } NodeId GVGraph::addNode(const QString &name) { return addNode(name, _graph); } QList< NodeId > GVGraph::addNodes(const QStringList &names) { QList ids; ids.reserve(names.size()); for (int i=0; i GVGraph::gvNodes() const { QList list; list.reserve(_nodeMap.size()); const qreal dpi = dpiForGraph(_graph); Q_FOREACH (Agnode_t *node, _nodeMap.keys()) { GVNode object = _nodeMap[node]; object.m_font = _font; //Set the name of the node object.m_name = agget(node, const_cast("label")); //Fetch the X coordinate, apply the DPI conversion rate (actual DPI / 72, used by dot) qreal x = ND_coord(node).x * (dpi / DotDefaultDPI); //Translate the Y coordinate from bottom-left to top-left corner qreal y = (GD_bb(_graph).UR.y - ND_coord(node).y) * (dpi / DotDefaultDPI); object.m_centerPos = QPoint(x, y); //Transform the width and height from inches to pixels object.m_height = ND_height(node) * dpi; object.m_width = ND_width(node) * dpi; if (qstricmp(ND_shape(node)->name, "rectangle") == 0) { if (qstricmp(agget(node, const_cast("style")), "rounded") == 0) { object.m_shape = GVNode::RoundedRect; } else { object.m_shape = GVNode::Rect; } } else if (qstricmp(ND_shape(node)->name, "doublecircle") == 0) { object.m_shape = GVNode::DoubleEllipse; } if (qstricmp(agget(node, const_cast("style")), "filled") == 0) { object.m_fillColor = QColor(agget(node, const_cast("fillcolor"))); } list.append(GVNodePair(id(node), object)); } return list; } QList GVGraph::gvEdges() const { QList list; list.reserve(_edgeMap.size()); const qreal dpi = dpiForGraph(_graph); Q_FOREACH (Agedge_t *edge, _edgeMap.keys()) { GVEdge object = _edgeMap[edge]; object.m_font = _font; //Fill the source and target node names if (ED_tail_label(edge)) object.m_source = QString::fromUtf8(ED_tail_label(edge)->text); if (ED_head_label(edge)) object.m_target = QString::fromUtf8(ED_head_label(edge)->text); if (ED_label(edge)) { object.m_label = QString::fromUtf8(ED_label(edge)->text); // note that the position attributes in graphviz point to the *center* of this element. // we need to subtract half of the width/height to get the top-left position #if GRAPHVIZ_MAJOR_VERSION >= 2 && GRAPHVIZ_MINOR_VERSION > 20 const double posx = ED_label(edge)->pos.x; const double posy = ED_label(edge)->pos.y; #else const double posx = ED_label(edge)->p.x; const double posy = ED_label(edge)->p.y; #endif object.m_labelBoundingRect = QRectF( (posx - ED_label(edge)->dimen.x / 2.0) * (dpi / DotDefaultDPI), ((GD_bb(_graph).UR.y - posy) - ED_label(edge)->dimen.y / 2.0) * (dpi / DotDefaultDPI), ED_label(edge)->dimen.x * (dpi / DotDefaultDPI), ED_label(edge)->dimen.y * (dpi / DotDefaultDPI)); } //Calculate the path from the spline (only one spline, as the graph is strict. //If it wasn't, we would have to iterate over the first list too) //Calculate the path from the spline (only one as the graph is strict) if ((ED_spl(edge)->list != 0) && (ED_spl(edge)->list->size%3 == 1)) { //If there is a starting point, draw a line from it to the first curve point if (ED_spl(edge)->list->sflag) { object.m_path.moveTo(ED_spl(edge)->list->sp.x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->sp.y) * (dpi / DotDefaultDPI)); object.m_path.lineTo(ED_spl(edge)->list->list[0].x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->list[0].y) * (dpi / DotDefaultDPI)); } else { object.m_path.moveTo(ED_spl(edge)->list->list[0].x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->list[0].y) * (dpi / DotDefaultDPI)); } //Loop over the curve points for (int i=1; ilist->size; i+=3) { object.m_path.cubicTo(ED_spl(edge)->list->list[i].x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->list[i].y) * (dpi / DotDefaultDPI), ED_spl(edge)->list->list[i+1].x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->list[i+1].y) * (dpi / DotDefaultDPI), ED_spl(edge)->list->list[i+2].x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->list[i+2].y) * (dpi / DotDefaultDPI)); } //If there is an ending point, draw a line to it if(ED_spl(edge)->list->eflag) { object.m_path.lineTo(ED_spl(edge)->list->ep.x * (dpi / DotDefaultDPI), (GD_bb(_graph).UR.y - ED_spl(edge)->list->ep.y) * (dpi / DotDefaultDPI)); } } Q_ASSERT(!object.m_path.isEmpty()); list.append(GVEdgePair(id(edge), object)); } return list; } QList GVGraph::gvSubGraphs() const { QList list; Q_FOREACH (Agraph_t *subGraph, _graphMap.keys()) { if (subGraph == _graph) { continue; } const QRectF rect = boundingRectForAgraph(subGraph); QPainterPath path; path.addRect(rect); GVSubGraph object = _graphMap[subGraph]; object.m_path = path; object.m_name = agnameof(subGraph); list.append(GVSubGraphPair(id(subGraph), object)); } return list; } gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvgraph.h000066400000000000000000000072031255003167400241340ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_GVGRAPH_H #define GAMMARAY_STATEMACHINEVIEWER_GVGRAPH_H #include "gvgraphelements.h" #include "gvtypes.h" #include #include #include #include namespace GammaRay { typedef QPair GVNodePair; typedef QPair GVEdgePair; typedef QPair GVSubGraphPair; /// An object containing a libgraph graph and its associated nodes and edges class GVGraph { public: /*! * \brief Construct a Graphviz graph object * \param name The name of the graph, must be unique in the application */ explicit GVGraph(const QString &name); ~GVGraph(); GraphId addGraph(const QString &name); GraphId addGraph(const QString &name, GraphId subGraphId); void removeGraph(GraphId graphId); QList gvSubGraphs() const; void setGraphAttr(const QString &attr, const QString &value, GraphId id = 0); /// Add and remove nodes NodeId addNode(const QString &name); NodeId addNode(const QString &name, GraphId subGraphId); QList addNodes(const QStringList &names); void removeNode(NodeId nodeId); void clearNodes(); QList gvNodes() const; void setNodeAttribute(NodeId id, const QString &attr, const QString &value); /// Add and remove edges EdgeId addEdge(NodeId source, NodeId target, const QString &name); void removeEdge(EdgeId id); QList gvEdges() const; void setEdgeAttribute(EdgeId id, const QString &attr, const QString &value); /// Set the font to use in all the labels void setFont(const QFont &font); QRectF boundingRect() const; void clear(); void applyLayout(); private: GraphId addGraph(const QString &name, Agraph_t *graph); NodeId addNode(const QString &name, Agraph_t *graph); void createGraph(); void closeGraph(); NodeId id(Agnode_t *node) const { return (NodeId)node; } EdgeId id(Agedge_t *edge) const { return (EdgeId)edge; } GraphId id(Agraph_t *graph) const { return (GraphId)graph; } Agnode_t *agNode(NodeId nodeId) const; Agedge_t *agEdge(EdgeId edgeId) const; Agraph_t *agGraph(GraphId graphId) const; QRectF boundingRectForAgraph(Agraph_t *graph) const; GVC_t *_context; Agraph_t *_graph; QFont _font; QString _name; // data QHash _graphMap; QHash _edgeMap; QHash _nodeMap; }; } #endif // GAMMARAY_GVGRAPH_H gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvgraphelements.h000066400000000000000000000066741255003167400257040ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_GVGRAPHELEMENTS_H #define GAMMARAY_STATEMACHINEVIEWER_GVGRAPHELEMENTS_H #include #include #include namespace GammaRay { class GVGraph; class GVElement { public: friend class GVGraph; explicit GVElement(const QString &name) : m_font(QFont("Helvetica [Cronxy]", 6)), m_name(name) { } GVElement() { } QString name() const { return m_name; } /// Font for rendering any text owned by this item QFont m_font; private: /// The unique identifier of the element in the graph QString m_name; }; class GVSubGraph : public GVElement { friend class GVGraph; public: explicit GVSubGraph(const QString &name) : GVElement(name) { } GVSubGraph() { } QPainterPath path() const { return m_path; } private: QPainterPath m_path; }; /// A struct containing the information for a GVGraph's node class GVNode : public GVElement { friend class GVGraph; public: enum Shape { Ellipse, DoubleEllipse, Rect, RoundedRect }; GVNode(const QString &name) : GVElement(name), m_height(0), m_width(0), m_shape(Ellipse) { } GVNode() : m_height(0), m_width(0), m_shape(Ellipse) { } QPoint centerPos() const { return m_centerPos; } QSize size() const { return QSize(m_width, m_height); } Shape shape() const { return m_shape; } QColor fillColor() const { return m_fillColor; } private: /// The position of the center point of the node from the top-left corner QPoint m_centerPos; /// The size of the node in pixels qreal m_height, m_width; /// The shape of this node Shape m_shape; /// Color to fill this node, invalid for non-filled nodes. QColor m_fillColor; }; /// A struct containing the information for a GVGraph's edge class GVEdge : public GVElement { public: explicit GVEdge(const QString &name) : GVElement(name) { } GVEdge() { } /// The source and target nodes of the edge QString m_source; QString m_target; /// Path of the edge's line QPainterPath m_path; /// The label of the edge QString m_label; /// Position of the label QRectF m_labelBoundingRect; }; } #endif gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvgraphitems.cpp000066400000000000000000000122671255003167400255370ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gvgraphitems.h" #include #include using namespace GammaRay; GVNodeItem::GVNodeItem(const GVNode &node, QGraphicsItem *parent) : QGraphicsItemGroup(parent), m_node(node) { const QSizeF size = node.size(); const QRectF rect(-size.width() / 2, -size.height() / 2, size.width(), size.height()); switch (node.shape()) { case GVNode::Rect: { QGraphicsRectItem *item = new QGraphicsRectItem(this); item->setRect(rect); m_shapeItem = item; break; } case GVNode::RoundedRect: { QPainterPath path; path.addRoundedRect(rect, 10, 10); QGraphicsPathItem *item = new QGraphicsPathItem(this); item->setPath(path); m_shapeItem = item; break; } case GVNode::Ellipse: case GVNode::DoubleEllipse: { QGraphicsEllipseItem *item = new QGraphicsEllipseItem(this); item->setRect(rect); if (node.shape() == GVNode::DoubleEllipse) { QGraphicsEllipseItem *doubleItem = new QGraphicsEllipseItem(item); doubleItem->setRect(rect.adjusted(4, 4, -4, -4)); m_shapeItem = doubleItem; } else { m_shapeItem = item; } break; } default: Q_ASSERT(false); } m_textItem = new QGraphicsTextItem(node.name(), this); m_textItem->setFont(node.m_font); setPos(m_node.centerPos()); setToolTip(QObject::tr("State: %1").arg(node.name())); setFlags(ItemIsSelectable); // init text item child { QGraphicsTextItem *item = m_textItem; QRectF textRect = item->boundingRect(); while (size.width() < textRect.size().width() && item->font().pointSize() > 1) { QFont font = item->font(); font.setPointSize(font.pointSize() - 1); item->setFont(font); textRect = item->boundingRect(); } const QSizeF size = textRect.size(); item->setPos(QPointF(-size.width() / 2, -size.height() / 2)); } if (node.fillColor().isValid()) { setBrush(node.fillColor()); } } void GVNodeItem::setPen(const QPen &pen) { m_shapeItem->setPen(pen); } QBrush GVNodeItem::brush() const { return m_shapeItem->brush(); } void GVNodeItem::setBrush(const QBrush &brush) { m_shapeItem->setBrush(brush); } GVEdgeItem::GVEdgeItem(const GVEdge &edge, QGraphicsItem *parent) : QGraphicsItemGroup(parent), m_edge(edge) { m_pathItem = new QGraphicsPathItem(this); m_pathItem->setPath(edge.m_path); setToolTip(QObject::tr("Transition: %1 -> %2").arg(edge.m_source).arg(edge.m_target)); // arrow head quick-fix QVector points = QVector() << QPointF(0, 0) << QPointF(-8, 4) << QPointF(-8, -4); m_arrowItem = new QGraphicsPolygonItem(this); m_arrowItem->setPolygon(QPolygonF(points)); m_arrowItem->setPos(edge.m_path.pointAtPercent(1.0)); m_arrowItem->setRotation(-edge.m_path.angleAtPercent(1.0)); setPen(m_pathItem->pen()); m_textItem = new QGraphicsTextItem(edge.m_label, this); m_textItem->setFont(edge.m_font); // init text item child { QGraphicsTextItem *item = m_textItem; const QRectF boundingRect = item->mapRectFromScene(edge.m_labelBoundingRect); const QSizeF size = boundingRect.size(); QRectF textRect = item->boundingRect(); while (size.width() < textRect.size().width() && item->font().pointSize() > 1) { QFont font = item->font(); font.setPointSize(font.pointSize() - 1); item->setFont(font); textRect = item->boundingRect(); } item->setPos(boundingRect.x(), boundingRect.y()); } } void GVEdgeItem::setPen(const QPen &pen) { m_pathItem->setPen(pen); QPen arrowPen(pen); arrowPen.setStyle(Qt::SolidLine); m_arrowItem->setPen(arrowPen); m_arrowItem->setBrush(arrowPen.color()); } GVGraphItem::GVGraphItem(const GVSubGraph &graph, QGraphicsItem *parent) : QGraphicsPathItem(parent), m_graph(graph), m_textItem(0) { setZValue(-1); setPath(graph.path()); setPen(QColor(Qt::gray)); setBrush(QColor(100, 100, 100, 20)); setToolTip(QObject::tr("Graph: %1").arg(graph.name())); { // TODO: Implement text item } } gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvgraphitems.h000066400000000000000000000053171255003167400252020ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_GVGRAPHITEMS_H #define GAMMARAY_STATEMACHINEVIEWER_GVGRAPHITEMS_H #include #include #include "gvgraph.h" namespace GammaRay { class GVNodeItem : public QGraphicsItemGroup { public: explicit GVNodeItem(const GVNode &node, QGraphicsItem *parent = 0); enum { Type = UserType + 1 }; inline int type() const { return Type; } QGraphicsTextItem *textItem() const { return m_textItem; } void setPen(const QPen &pen); QBrush brush() const; void setBrush(const QBrush &brush); private: GVNode m_node; QGraphicsTextItem *m_textItem; QAbstractGraphicsShapeItem *m_shapeItem; }; class GVEdgeItem : public QGraphicsItemGroup { public: explicit GVEdgeItem(const GVEdge &edge, QGraphicsItem *parent = 0); enum { Type = UserType + 2 }; inline int type() const { return Type; } QGraphicsTextItem *textItem() const { return m_textItem; } void setPen(const QPen &pen); private: GVEdge m_edge; QGraphicsPathItem *m_pathItem; QGraphicsPolygonItem *m_arrowItem; QGraphicsTextItem *m_textItem; }; class GVGraphItem : public QGraphicsPathItem { public: explicit GVGraphItem(const GVSubGraph &edge, QGraphicsItem *parent = 0); enum { Type = UserType + 3 }; inline int type() const { return Type; } QGraphicsTextItem *textItem() const { return m_textItem; } private: GVSubGraph m_graph; QGraphicsTextItem *m_textItem; }; } #endif // GAMMARAY_GVGRAPHITEMS_H gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvtypes.h000066400000000000000000000025261255003167400242020ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_GVTYPES_H #define GAMMARAY_STATEMACHINEVIEWER_GVTYPES_H #include namespace GammaRay { typedef quintptr ElementId; typedef quintptr EdgeId; typedef quintptr NodeId; typedef quintptr GraphId; } #endif gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvutils.cpp000066400000000000000000000071161255003167400245310ustar00rootroot00000000000000/* gvutils.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gvutils.h" #include #ifdef WITH_CGRAPH # include #else # include #endif using namespace GammaRay; #ifdef WITH_CGRAPH Agraph_t *GVUtils::_agopen(const QString &name, Agdesc_t kind, Agdisc_t *disc) #else Agraph_t *GVUtils::_agopen(const QString &name, int kind) #endif { #ifdef WITH_CGRAPH return agopen(const_cast(qPrintable(name)), kind, disc); #else return agopen(const_cast(qPrintable(name)), kind); #endif } QString GVUtils::_agget(void* object, const QString &attr, const QString &alt) { const QString str = agget(object, const_cast(qPrintable(attr))); if(str.isEmpty()) { return alt; } else { return str; } } Agsym_t* GVUtils::_agnodeattr(Agraph_t *object, const QString &attr, const QString &alt) { #ifdef WITH_CGRAPH return agattr(object, AGNODE, #else return agnodeattr(object, #endif const_cast(qPrintable(attr)), const_cast(qPrintable(alt))); } Agsym_t* GVUtils::_agedgeattr(Agraph_t *object, const QString &attr, const QString &alt) { #ifdef WITH_CGRAPH return agattr(object, AGEDGE, #else return agedgeattr(object, #endif const_cast(qPrintable(attr)), const_cast(qPrintable(alt))); } Agnode_t* GVUtils::_agnode(Agraph_t* graph, const QString& attr, bool create) { #ifdef WITH_CGRAPH return agnode(graph, const_cast(qPrintable(attr)), create); #else Q_UNUSED(create); return agnode(graph, const_cast(qPrintable(attr))); #endif } Agedge_t* GVUtils::_agedge(Agraph_t *graph, Agnode_t *tail, Agnode_t *head, const QString &name, bool create) { #ifdef WITH_CGRAPH return agedge(graph, tail, head, const_cast(qPrintable(name)), create); #else Q_UNUSED(name); Q_UNUSED(create); return agedge(graph, tail, head); #endif } Agraph_t* GVUtils::_agsubg(Agraph_t *graph, const QString &attr, bool create) { #ifdef WITH_CGRAPH return agsubg(graph, const_cast(qPrintable(attr)), create); #else Q_UNUSED(create); return agsubg(graph, const_cast(qPrintable(attr))); #endif } int GVUtils::_agset(void *object, const QString &attr, const QString &value) { return agsafeset(object, const_cast(qPrintable(attr)), const_cast(qPrintable(value)), const_cast("")); } int GVUtils::_gvLayout(GVC_t* gvc, graph_t* g, const char* engine) { return gvLayout(gvc, g, const_cast(engine)); } gammaray-2.3.0/plugins/statemachineviewer/gvgraph/gvutils.h000066400000000000000000000047551255003167400242040ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_GVUTILS_H #define GAMMARAY_STATEMACHINEVIEWER_GVUTILS_H #include #include //must include after QString to avoid possible //conflicting declarations for strcmp(), memcmp()... namespace GammaRay { namespace GVUtils { /// The agopen method for opening a graph #ifdef WITH_CGRAPH extern Agraph_t *_agopen(const QString &name, Agdesc_t kind, Agdisc_t *disc); #else extern Agraph_t *_agopen(const QString &name, int kind); #endif /// Add an alternative value parameter to the method for getting an object's attribute QString _agget(void *object, const QString &attr, const QString& alt = QString()); Agsym_t *_agnodeattr(Agraph_t *object, const QString &attr, const QString &alt = QString()); Agsym_t *_agedgeattr(Agraph_t *object, const QString &attr, const QString &alt = QString()); int _gvLayout(GVC_t *gvc, graph_t *g, const char *engine); Agnode_t *_agnode(Agraph_t *graph, const QString &attr, bool create = true); Agedge_t *_agedge(Agraph_t *graph, Agnode_t *tail, Agnode_t *head, const QString &name = QString(), bool create = true); Agraph_t *_agsubg(Agraph_t *graph, const QString &attr, bool create = true); /// Directly use agsafeset which always works, contrarily to agset int _agset(void* object, const QString& attr, const QString& value); } } #endif gammaray-2.3.0/plugins/statemachineviewer/statemachineview.cpp000066400000000000000000000032451255003167400247350ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineview.h" #include using namespace GammaRay; StateMachineView::StateMachineView(QWidget *parent) : QGraphicsView(parent) { } StateMachineView::StateMachineView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) { } void StateMachineView::zoomBy(qreal scaleFactor) { scale(scaleFactor, scaleFactor); } void StateMachineView::wheelEvent(QWheelEvent *event) { const qreal step = qAbs(event->delta() / 100.0); const qreal zoomFactor = event->delta() >= 0 ? step : 1.0f / step ; zoomBy(zoomFactor); event->accept(); } gammaray-2.3.0/plugins/statemachineviewer/statemachineview.h000066400000000000000000000031501255003167400243750ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEW_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEW_H #include namespace GammaRay { class StateMachineView : public QGraphicsView { Q_OBJECT public: explicit StateMachineView(QWidget *parent = 0); explicit StateMachineView(QGraphicsScene *scene, QWidget *parent = 0); public Q_SLOTS: void zoomBy(qreal scaleFactor); protected: void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_STATEMACHINEVIEW_H gammaray-2.3.0/plugins/statemachineviewer/statemachineviewer.ui000066400000000000000000000132241255003167400251150ustar00rootroot00000000000000 GammaRay::StateMachineViewer 0 0 809 594 Qt::Horizontal Qt::Vertical Settings Maximum depth of state hierarchy shown: depthSpinBox 0 false true false Save As Image... <qt>Limits the maximum size of the exported image file. Zooming could otherwise make the image extremely large. The number given is in units of mega pixel.</qt> Maximum Size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter maxMegaPixelsSpinBox <qt>Limits the maximum size of the exported image file. Zooming could otherwise make the image extremely large. The number given is in units of mega pixel.</qt> 0 MPx MPx Start/Stop State Machine: startStopButton true true false true 100 false 1 0 StateMachineView QGraphicsView
statemachineview.h
gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerclient.cpp000066400000000000000000000033031255003167400264560ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineviewerclient.h" #include using namespace GammaRay; StateMachineViewerClient::StateMachineViewerClient(QObject *parent) : StateMachineViewerInterface(parent) { } void StateMachineViewerClient::setMaximumDepth(int depth) { Endpoint::instance()->invokeObject(objectName(), "setMaximumDepth", QVariantList() << depth); } void StateMachineViewerClient::toggleRunning() { Endpoint::instance()->invokeObject(objectName(), "toggleRunning"); } void StateMachineViewerClient::repopulateGraph() { Endpoint::instance()->invokeObject(objectName(), "repopulateGraph"); } gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerclient.h000066400000000000000000000032531255003167400261270ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERCLIENT_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERCLIENT_H #include "statemachineviewerinterface.h" namespace GammaRay { class StateMachineViewerClient : public StateMachineViewerInterface { Q_OBJECT Q_INTERFACES(GammaRay::StateMachineViewerInterface) public: explicit StateMachineViewerClient(QObject *parent = 0); void setMaximumDepth(int depth) Q_DECL_OVERRIDE; void toggleRunning() Q_DECL_OVERRIDE; void repopulateGraph() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_STATEMACHINEVIEWERCLIENT_H gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerinterface.cpp000066400000000000000000000034311255003167400271420ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineviewerinterface.h" #include using namespace GammaRay; StateMachineViewerInterface::StateMachineViewerInterface(QObject *parent) : QObject(parent) { qRegisterMetaType(); qRegisterMetaTypeStreamOperators(); qRegisterMetaType(); qRegisterMetaTypeStreamOperators(); qRegisterMetaType(); qRegisterMetaTypeStreamOperators(); qRegisterMetaType(); qRegisterMetaTypeStreamOperators(); ObjectBroker::registerObject(this); } StateMachineViewerInterface::~StateMachineViewerInterface() { } gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerinterface.h000066400000000000000000000104411255003167400266060ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERINTERFACE_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERINTERFACE_H #include #include #include class QAbstractState; class QAbstractTransition; namespace GammaRay { // note: typedef bring major pain, on the client side i.e. it would always look for // signal/slots with the base type (or actually, the first type which was registered // to the meta type system)... struct TransitionId { TransitionId(const TransitionId &id) : id(id.id) {} explicit TransitionId(QAbstractTransition *transition = 0) : id(reinterpret_cast(transition)) {} operator quint64() const { return id; } quint64 id; }; inline QDataStream &operator<<(QDataStream &out, TransitionId value) { out << value.id; return out; } inline QDataStream &operator>>(QDataStream &in, TransitionId &value) { in >> value.id; return in; } struct StateId { StateId(const StateId &id) : id(id.id) {} explicit StateId(QAbstractState *state= 0) : id(reinterpret_cast(state)) {} operator quint64() const { return id; } quint64 id; }; inline QDataStream &operator<<(QDataStream &out, StateId value) { out << value.id; return out; } inline QDataStream &operator>>(QDataStream &in, StateId &value) { in >> value.id; return in; } enum StateType { OtherState, FinalState, ShallowHistoryState, DeepHistoryState, StateMachineState }; inline QDataStream &operator<<(QDataStream &out, StateType value) { out << int(value); return out; } inline QDataStream &operator>>(QDataStream &in, StateType &value) { int val; in >> val; value = static_cast(val); return in; } typedef QList StateMachineConfiguration; class StateMachineViewerInterface : public QObject { Q_OBJECT public: explicit StateMachineViewerInterface(QObject *parent = 0); virtual ~StateMachineViewerInterface(); public slots: virtual void toggleRunning() = 0; virtual void setMaximumDepth(int depth) = 0; virtual void repopulateGraph() = 0; signals: void statusChanged(bool haveStateMachine, bool running); void message(const QString &message); void aboutToRepopulateGraph(); void graphRepopulated(); void stateConfigurationChanged(const GammaRay::StateMachineConfiguration& config); void maximumDepthChanged(int depth); void transitionTriggered(GammaRay::TransitionId transition, const QString &label); void stateAdded(GammaRay::StateId state, GammaRay::StateId parent, bool hasChildren, const QString &label, GammaRay::StateType type, bool connectToInitial); void stateEntered(GammaRay::StateId state); void stateExited(GammaRay::StateId state); void transitionAdded(GammaRay::TransitionId state, GammaRay::StateId source, GammaRay::StateId target, const QString &label); }; } Q_DECLARE_METATYPE(GammaRay::StateId) Q_DECLARE_METATYPE(GammaRay::TransitionId) Q_DECLARE_METATYPE(GammaRay::StateMachineConfiguration) Q_DECLARE_METATYPE(GammaRay::StateType) Q_DECLARE_INTERFACE(GammaRay::StateMachineViewerInterface, "com.kdab.GammaRay.StateMachineViewer") #endif // GAMMARAY_STATEMACHINEVIEWERINTERFACE_H gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerserver.cpp000066400000000000000000000265271255003167400265230ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Milian Wolff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineviewerserver.h" #include "statemodel.h" #include "statemachinewatcher.h" #include "transitionmodel.h" #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; using namespace std; namespace { QString labelForTransition(QAbstractTransition *transition) { const QString objectName = transition->objectName(); if (!objectName.isEmpty()) { return objectName; } // Try to get a label for the transition if it is a QSignalTransition. QSignalTransition *signalTransition = qobject_cast(transition); if (signalTransition) { return QString::fromLatin1("%1::%2"). arg(Util::displayString(signalTransition->senderObject())). arg(QString::fromLatin1(signalTransition->signal().mid(1))); } return Util::displayString(transition); } } StateMachineViewerServer::StateMachineViewerServer(ProbeInterface *probe, QObject *parent) : StateMachineViewerInterface(parent), m_stateModel(new StateModel(this)), m_transitionModel(new TransitionModel(this)), m_maximumDepth(0), m_stateMachineWatcher(new StateMachineWatcher(this)) { probe->registerModel("com.kdab.GammaRay.StateModel", m_stateModel); QItemSelectionModel *stateSelectionModel = ObjectBroker::selectionModel(m_stateModel); connect(stateSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(stateSelectionChanged())); ObjectTypeFilterProxyModel *stateMachineFilter = new ObjectTypeFilterProxyModel(this); stateMachineFilter->setSourceModel(probe->objectListModel()); probe->registerModel("com.kdab.GammaRay.StateMachineModel", stateMachineFilter); QItemSelectionModel *stateMachineSelectionModel = ObjectBroker::selectionModel(stateMachineFilter); connect(stateMachineSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(handleMachineClicked(QModelIndex))); connect(m_stateMachineWatcher, SIGNAL(stateEntered(QAbstractState*)), SLOT(stateEntered(QAbstractState*))); connect(m_stateMachineWatcher, SIGNAL(stateExited(QAbstractState*)), SLOT(stateExited(QAbstractState*))); connect(m_stateMachineWatcher, SIGNAL(transitionTriggered(QAbstractTransition*)), SLOT(handleTransitionTriggered(QAbstractTransition*))); setMaximumDepth(3); updateStartStop(); } void StateMachineViewerServer::repopulateGraph() { emit aboutToRepopulateGraph(); // just to be sure the client has the same setting than we do emit maximumDepthChanged(m_maximumDepth); updateStartStop(); if (m_filteredStates.isEmpty()) { addState(m_stateModel->stateMachine()); } else { foreach(QAbstractState* state, m_filteredStates) { addState(state); } } m_recursionGuard.clear(); emit graphRepopulated(); } QStateMachine *StateMachineViewerServer::selectedStateMachine() const { return m_stateModel->stateMachine(); } static int treeDepth(QAbstractState *ascendant, QAbstractState *obj) { if (!Util::descendantOf(ascendant, obj)) { return -1; } int depth = 0; QAbstractState *parent = obj->parentState(); while (parent) { ++depth; parent = parent->parentState(); } return depth; } bool StateMachineViewerServer::mayAddState(QAbstractState *state) { if (!state) { return false; } if (m_recursionGuard.contains(state)) { return false; } if (!m_filteredStates.isEmpty()) { bool isValid = false; foreach(QAbstractState* filter, m_filteredStates) { if (filter == state || Util::descendantOf(filter, state)) { isValid = true; break; } } if (!isValid) { return false; } } if (m_maximumDepth > 0) { int depth = -1; if (!m_filteredStates.isEmpty()) { foreach(QAbstractState* filter, m_filteredStates) { depth = ::treeDepth(filter, state); if (depth != -1) { break; } } } else { depth = ::treeDepth(m_stateModel->stateMachine(), state); } if (depth > m_maximumDepth) { return false; } } return true; } void StateMachineViewerServer::setFilteredStates(const QVector& states) { if (m_filteredStates == states) { return; } if (states.isEmpty()) { emit message(tr("Clearing filter.")); } else { QStringList stateNames; stateNames.reserve(states.size()); foreach(QAbstractState* state, states) { stateNames << Util::displayString(state); } emit message(tr("Setting filter on: %1").arg(stateNames.join(", "))); } m_filteredStates = states; } void StateMachineViewerServer::setMaximumDepth(int depth) { if (m_maximumDepth == depth) { return; } emit message(tr("Showing states until a depth of %1").arg(depth)); m_maximumDepth = depth; repopulateGraph(); emit maximumDepthChanged(depth); } void StateMachineViewerServer::setSelectedStateMachine(QStateMachine* machine) { QStateMachine* oldMachine = selectedStateMachine(); if (oldMachine) { disconnect(oldMachine, SIGNAL(started()), this, SLOT(updateStartStop())); disconnect(oldMachine, SIGNAL(stopped()), this, SLOT(updateStartStop())); disconnect(oldMachine, SIGNAL(finished()), this, SLOT(updateStartStop())); } m_stateModel->setStateMachine(machine); stateConfigurationChanged(); setFilteredStates(QVector()); m_stateMachineWatcher->setWatchedStateMachine(machine); repopulateGraph(); if (machine) { connect(machine, SIGNAL(started()), this, SLOT(updateStartStop())); connect(machine, SIGNAL(stopped()), this, SLOT(updateStartStop())); connect(machine, SIGNAL(finished()), this, SLOT(updateStartStop())); } updateStartStop(); } void StateMachineViewerServer::handleMachineClicked(const QModelIndex &index) { if (!index.isValid()) { setSelectedStateMachine(0); return; } QObject *stateMachineObject = index.data(ObjectModel::ObjectRole).value(); QStateMachine *machine = qobject_cast(stateMachineObject); setSelectedStateMachine(machine); } void StateMachineViewerServer::stateSelectionChanged() { const QModelIndexList& selection = ObjectBroker::selectionModel(m_stateModel)->selectedRows(); QVector filter; filter.reserve(selection.size()); foreach(const QModelIndex &index, selection) { QObject *stateObject = index.data(ObjectModel::ObjectRole).value(); Q_ASSERT(stateObject); QAbstractState *state = qobject_cast(stateObject); Q_ASSERT(state); bool addState = true; /// only pick the top-level items of the selection // NOTE: this might be slow for large selections, if someone wants to come up with a better // algorithm, please - go for it! foreach(QAbstractState *potentialParent, filter) { if (Util::descendantOf(potentialParent, state)) { addState = false; break; } } if (addState) { filter << state; } } setFilteredStates(filter); } void StateMachineViewerServer::handleTransitionTriggered(QAbstractTransition *transition) { emit transitionTriggered(TransitionId(transition), Util::displayString(transition)); } void StateMachineViewerServer::stateEntered(QAbstractState *state) { emit message(tr("State entered: %1").arg(Util::displayString(state))); stateConfigurationChanged(); } void StateMachineViewerServer::stateExited(QAbstractState *state) { emit message(tr("State exited: %1").arg(Util::displayString(state))); stateConfigurationChanged(); } void StateMachineViewerServer::stateConfigurationChanged() { QSet newConfig; if (selectedStateMachine()) { newConfig = selectedStateMachine()->configuration(); } if (newConfig == m_lastStateConfig) { return; } m_lastStateConfig = newConfig; StateMachineConfiguration config; config.reserve(newConfig.size()); foreach(QAbstractState* state, newConfig) { config << StateId(state); } emit stateConfigurationChanged(config); } void StateMachineViewerServer::addState(QAbstractState *state) { if (!mayAddState(state)) { return; } Q_ASSERT(!m_recursionGuard.contains(state)); m_recursionGuard.insert(state); QState *parentState = state->parentState(); if (parentState) { addState(parentState); // be sure that parent is added first } const bool hasChildren = state->findChild(); const QString &label = Util::displayString(state); // add a connection from parent state to initial state if // parent state is valid and parent state has an initial state const bool connectToInitial = parentState && parentState->initialState() == state; StateType type = OtherState; if (qobject_cast(state)) { type = FinalState; } else if (auto historyState = qobject_cast(state)) { type = historyState->historyType() == QHistoryState::ShallowHistory ? ShallowHistoryState : DeepHistoryState; } else if (qobject_cast(state)) { type = StateMachineState; } emit stateAdded(StateId(state), StateId(parentState), hasChildren, label, type, connectToInitial); // add transitions Q_FOREACH (QAbstractTransition *transition, state->findChildren()) { addTransition(transition); } // recursive call to add children Q_FOREACH (QAbstractState* child, state->findChildren()) { addState(child); } } void StateMachineViewerServer::addTransition(QAbstractTransition *transition) { QState *sourceState = transition->sourceState(); QAbstractState *targetState = transition->targetState(); addState(sourceState); addState(targetState); const QString label = labelForTransition(transition); emit transitionAdded(TransitionId(transition), StateId(sourceState), StateId(targetState), label); } void StateMachineViewerServer::updateStartStop() { emit statusChanged(selectedStateMachine() != 0, selectedStateMachine() && selectedStateMachine()->isRunning()); } void StateMachineViewerServer::toggleRunning() { if (!selectedStateMachine()) { return; } if (selectedStateMachine()->isRunning()) { selectedStateMachine()->stop(); } else { selectedStateMachine()->start(); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(StateMachineViewerFactory) #endif gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerserver.h000066400000000000000000000071121255003167400261550ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERSERVER_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERSERVER_H #include "statemachineviewerutil.h" #include "statemachineviewerinterface.h" #include #include #include #include #include #include #include class QAbstractTransition; class QStateMachine; class QAbstractState; class QAbstractItemModel; class QModelIndex; namespace GammaRay { class StateModel; class StateMachineWatcher; class TransitionModel; class StateMachineViewerServer : public StateMachineViewerInterface { Q_OBJECT Q_INTERFACES(GammaRay::StateMachineViewerInterface) public: explicit StateMachineViewerServer(ProbeInterface *probe, QObject *parent = 0); void addState(QAbstractState *state); void addTransition(QAbstractTransition *transition); QStateMachine *selectedStateMachine() const; using StateMachineViewerInterface::stateConfigurationChanged; private slots: void stateEntered(QAbstractState *state); void stateExited(QAbstractState *state); void stateConfigurationChanged(); void handleTransitionTriggered(QAbstractTransition *); void handleMachineClicked(const QModelIndex &); void stateSelectionChanged(); void setFilteredStates(const QVector &states); void setMaximumDepth(int depth) Q_DECL_OVERRIDE; void setSelectedStateMachine(QStateMachine* machine); void updateStartStop(); void toggleRunning() Q_DECL_OVERRIDE; void repopulateGraph() Q_DECL_OVERRIDE; private: void updateStateItems(); bool mayAddState(QAbstractState *state); StateModel *m_stateModel; TransitionModel *m_transitionModel; // filters QVector m_filteredStates; int m_maximumDepth; StateMachineWatcher *m_stateMachineWatcher; QSet m_recursionGuard; QSet m_lastStateConfig; }; class StateMachineViewerFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_statemachineviewer.json") public: explicit StateMachineViewerFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("State Machine Viewer"); } }; } #endif // GAMMARAY_STATEMACHINEVIEWERSERVER_H gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerutil.h000066400000000000000000000036371255003167400256340ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERUTIL_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERUTIL_H #include template class RingBuffer { public: RingBuffer() : m_size(5) { } void resize(int size) { Q_ASSERT(size > 0); m_size = size; cleanup(); } void enqueue(T t) { m_entries.enqueue(t); cleanup(); } void clear() { m_entries.clear(); } int size() const { return m_entries.size(); } T tail() const { return m_entries.last(); } QList entries() const { return m_entries; } private: void cleanup() { while (m_entries.size() > m_size) { m_entries.dequeue(); } } QQueue m_entries; int m_size; }; #endif gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerwidget.cpp000066400000000000000000000373541255003167400265000ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineviewerwidget.h" #include "gvgraph/gvgraph.h" #include "gvgraph/gvgraphitems.h" #include "statemachineviewerclient.h" #include #include #include #include #include #include #include #include #include enum { KEY_STATETYPE }; #include using namespace GammaRay; using namespace std; static QObject* createStateMachineViewerClient(const QString &/*name*/, QObject *parent) { return new StateMachineViewerClient(parent); } template static qreal relativePosition(const QList& list, T t) { const int index = list.indexOf(t); Q_ASSERT(index != -1); return (index+1.0) / list.size(); } StateMachineViewerWidget::StateMachineViewerWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , m_ui(new Ui::StateMachineViewer) , m_graph(new GVGraph("State Machine")) , m_font(QFont("Helvetica [Cronxy]", 6)) , m_interface(0) { m_lastConfigurations.resize(5); ObjectBroker::registerClientObjectFactoryCallback(createStateMachineViewerClient); m_interface = ObjectBroker::object(); m_ui->setupUi(this); m_graph->setFont(m_font); m_ui->graphicsView->setDragMode(QGraphicsView::ScrollHandDrag); m_ui->graphicsView->setScene(new QGraphicsScene(this)); m_ui->graphicsView->setRenderHint(QPainter::Antialiasing); QAbstractItemModel *stateMachineModel = ObjectBroker::model("com.kdab.GammaRay.StateMachineModel"); m_ui->stateMachinesView->setModel(stateMachineModel); m_ui->stateMachinesView->setSelectionModel(ObjectBroker::selectionModel(stateMachineModel)); new DeferredResizeModeSetter(m_ui->stateMachinesView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(m_ui->stateMachinesView->header(), 1, QHeaderView::ResizeToContents); new DeferredTreeViewConfiguration(m_ui->stateMachinesView, false); QAbstractItemModel *stateModel = ObjectBroker::model("com.kdab.GammaRay.StateModel"); connect(stateModel, SIGNAL(modelReset()), this, SLOT(stateModelReset())); m_ui->singleStateMachineView->setModel(stateModel); m_ui->singleStateMachineView->setSelectionModel(ObjectBroker::selectionModel(stateModel)); m_ui->singleStateMachineView->setSelectionMode(QAbstractItemView::ExtendedSelection); new DeferredResizeModeSetter(m_ui->singleStateMachineView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(m_ui->singleStateMachineView->header(), 1, QHeaderView::ResizeToContents); new DeferredTreeViewConfiguration(m_ui->singleStateMachineView, true, false); connect(m_ui->depthSpinBox, SIGNAL(valueChanged(int)), m_interface, SLOT(setMaximumDepth(int))); connect(m_ui->startStopButton, SIGNAL(clicked()), m_interface, SLOT(toggleRunning())); connect(m_ui->exportButton, SIGNAL(clicked()), SLOT(exportAsImage())); m_ui->maxMegaPixelsSpinBox->setValue(maximumMegaPixels()); connect(m_ui->maxMegaPixelsSpinBox, SIGNAL(valueChanged(int)), SLOT(setMaximumMegaPixels(int))); connect(m_interface, SIGNAL(maximumDepthChanged(int)), m_ui->depthSpinBox, SLOT(setValue(int))); connect(m_interface, SIGNAL(message(QString)), this, SLOT(showMessage(QString))); connect(m_interface, SIGNAL(aboutToRepopulateGraph()), this, SLOT(clearGraph())); connect(m_interface, SIGNAL(graphRepopulated()), this, SLOT(repopulateView())); connect(m_interface, SIGNAL(stateConfigurationChanged(GammaRay::StateMachineConfiguration)), this, SLOT(stateConfigurationChanged(GammaRay::StateMachineConfiguration))); connect(m_interface, SIGNAL(stateAdded(GammaRay::StateId,GammaRay::StateId,bool,QString,GammaRay::StateType,bool)), this, SLOT(stateAdded(GammaRay::StateId,GammaRay::StateId,bool,QString,GammaRay::StateType,bool))); connect(m_interface, SIGNAL(transitionAdded(GammaRay::TransitionId,GammaRay::StateId,GammaRay::StateId,QString)), this, SLOT(transitionAdded(GammaRay::TransitionId,GammaRay::StateId,GammaRay::StateId,QString))); connect(m_interface, SIGNAL(statusChanged(bool,bool)), this, SLOT(statusChanged(bool,bool))); connect(m_interface, SIGNAL(transitionTriggered(GammaRay::TransitionId,QString)), this, SLOT(transitionTriggered(GammaRay::TransitionId,QString))); m_interface->repopulateGraph(); } StateMachineViewerWidget::~StateMachineViewerWidget() { } void StateMachineViewerWidget::statusChanged(const bool haveStateMachine, const bool running) { if (!running) { m_ui->startStopButton->setChecked(false); m_ui->startStopButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); } else { m_ui->startStopButton->setChecked(true); m_ui->startStopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); } m_ui->startStopButton->setEnabled(haveStateMachine); } void StateMachineViewerWidget::clearView() { m_ui->graphicsView->scene()->clear(); } void StateMachineViewerWidget::repopulateView() { clearView(); m_graph->applyLayout(); QGraphicsScene *scene = m_ui->graphicsView->scene(); Q_FOREACH (const GVNodePair &nodePair, m_graph->gvNodes()) { const NodeId &id = nodePair.first; const GVNode &node = nodePair.second; GVNodeItem *item = new GVNodeItem(node); item->setData(KEY_STATETYPE, QVariant::fromValue(m_nodeTypeMap.value(id, OtherState))); scene->addItem(item); m_nodeItemMap.insert(id, item); } Q_FOREACH (const GVEdgePair &edgePair, m_graph->gvEdges()) { const EdgeId &id = edgePair.first; const GVEdge &edge = edgePair.second; GVEdgeItem *item = new GVEdgeItem(edge); scene->addItem(item); m_edgeItemMap.insert(id, item); } Q_FOREACH (const GVSubGraphPair &graphPair, m_graph->gvSubGraphs()) { const GraphId &id = graphPair.first; const GVSubGraph &graph = graphPair.second; GVGraphItem *item = new GVGraphItem(graph); scene->addItem(item); m_graphItemMap.insert(id, item); } updateStateItems(); updateTransitionItems(); // correctly set the scene rect scene->setSceneRect(scene->itemsBoundingRect()); } void StateMachineViewerWidget::clearGraph() { m_graph->clear(); m_graphItemMap.clear(); m_nodeItemMap.clear(); m_edgeItemMap.clear(); m_stateGraphIdMap.clear(); m_stateNodeIdMap.clear(); m_transitionEdgeIdMap.clear(); m_nodeTypeMap.clear(); m_lastTransitions.clear(); m_lastConfigurations.clear(); } void StateMachineViewerWidget::transitionTriggered(TransitionId transition, const QString &label) { showMessage(tr("Transition triggered: %1").arg(label)); m_lastTransitions.enqueue(transition); updateTransitionItems(); } void StateMachineViewerWidget::showMessage(const QString &message) { // update log QPlainTextEdit *plainTextEdit = m_ui->plainTextEdit; plainTextEdit->appendPlainText(message); // auto-scroll hack QScrollBar *sb = plainTextEdit->verticalScrollBar(); sb->setValue(sb->maximum()); } void StateMachineViewerWidget::updateTransitionItems() { // restore default color Q_FOREACH (QGraphicsItem *item, m_ui->graphicsView->scene()->items()) { GVEdgeItem *edgeItem = qgraphicsitem_cast(item); if (edgeItem) { edgeItem->setPen(QPen()); } } // set color based on recent usage Q_FOREACH (TransitionId t, m_lastTransitions.entries()) { EdgeId id = m_transitionEdgeIdMap.value(t); GVEdgeItem *edgeItem = m_edgeItemMap.value(id); if (!edgeItem) { continue; } QColor color(Qt::red); color.setRedF(relativePosition(m_lastTransitions.entries(), t)); QPen pen(Qt::DashLine); pen.setWidth(2); pen.setColor(color); edgeItem->setPen(pen); } } void StateMachineViewerWidget::stateConfigurationChanged(const StateMachineConfiguration &config) { if (m_lastConfigurations.size() > 0 && m_lastConfigurations.tail() == config) { return; } m_lastConfigurations.enqueue(config); updateStateItems(); } void StateMachineViewerWidget::updateStateItems() { // initialize Q_FOREACH (GVNodeItem* item, m_nodeItemMap) { Q_ASSERT(item); QColor color; switch (item->data(KEY_STATETYPE).value()) { case FinalState: color = QColor(Qt::black); break; case StateMachineState: color = QColor(Qt::gray); break; default: color = QColor(Qt::white); break; } QBrush brush = item->brush(); if (brush.style() == Qt::NoBrush) brush.setStyle(Qt::SolidPattern); brush.setColor(color); item->setBrush(brush); } // color recent configurations based on last usage // note that each configuration has the same color saturation atm Q_FOREACH (const StateMachineConfiguration &config, m_lastConfigurations.entries()) { const qreal alpha = relativePosition(m_lastConfigurations.entries(), config); Q_FOREACH (StateId state, config) { NodeId id = m_stateNodeIdMap.value(state); GVNodeItem *nodeItem = m_nodeItemMap.value(id); if (!nodeItem) { continue; } QColor color(Qt::red); color.setAlphaF(alpha); QBrush brush = nodeItem->brush(); brush.setColor(color); nodeItem->setBrush(brush); } } } void StateMachineViewerWidget::stateAdded(const StateId state, const StateId parent, const bool hasChildren, const QString &label, const StateType type, const bool connectToInitial) { if (m_stateNodeIdMap.contains(state)) { return; } const GraphId parentGraphId = m_stateGraphIdMap.value(parent); GraphId graphId = parentGraphId; const QString stateId = QString::number(state); if (parent && parentGraphId) { if (hasChildren) { // only create sub-graphs if we have child states graphId = m_graph->addGraph(stateId, parentGraphId); m_graph->setGraphAttr(QLatin1String("label"), label, graphId); } } else { graphId = m_graph->addGraph(stateId); m_graph->setGraphAttr(QLatin1String("label"), label, graphId); } Q_ASSERT(graphId); const NodeId nodeId = m_graph->addNode(stateId, graphId); Q_ASSERT(nodeId); m_graph->setNodeAttribute(nodeId, QLatin1String("label"), label); m_nodeTypeMap.insert(nodeId, type); switch (type) { case FinalState: m_graph->setNodeAttribute(nodeId, "GammaRayStateType", "final"); m_graph->setNodeAttribute(nodeId, "shape", "doublecircle"); m_graph->setNodeAttribute(nodeId, "label", ""); m_graph->setNodeAttribute(nodeId, "style", "filled"); m_graph->setNodeAttribute(nodeId, "fillcolor", "black"); m_graph->setNodeAttribute(nodeId, "fixedsize", "true"); m_graph->setNodeAttribute(nodeId, "heigh", "0.15"); m_graph->setNodeAttribute(nodeId, "width", "0.15"); break; case ShallowHistoryState: m_graph->setNodeAttribute(nodeId, "GammaRayStateType", "shallowhistory"); m_graph->setNodeAttribute(nodeId, "label", "H"); m_graph->setNodeAttribute(nodeId, "shape", "circle"); break; case DeepHistoryState: m_graph->setNodeAttribute(nodeId, "GammaRayStateType", "deephistory"); m_graph->setNodeAttribute(nodeId, "label", "H*"); m_graph->setNodeAttribute(nodeId, "shape", "circle"); break; case StateMachineState: case OtherState: m_graph->setNodeAttribute(nodeId, "GammaRayStateType", "other"); m_graph->setNodeAttribute(nodeId, "shape", "rectangle"); m_graph->setNodeAttribute(nodeId, "style", "rounded"); break; } if (connectToInitial && parentGraphId) { NodeId initialNode = m_graph->addNode(QString("initial-%1").arg(QString::number(parent)), parentGraphId); m_graph->addEdge(initialNode, nodeId, QString()); m_graph->setNodeAttribute(initialNode, "shape", "circle"); m_graph->setNodeAttribute(initialNode, "style", "filled"); m_graph->setNodeAttribute(initialNode, "fillcolor", "black"); m_graph->setNodeAttribute(initialNode, "fixedsize", "true"); m_graph->setNodeAttribute(initialNode, "heigh", "0.1"); m_graph->setNodeAttribute(initialNode, "width", "0.1"); m_graph->setNodeAttribute(initialNode, "label", ""); } m_stateGraphIdMap.insert(state, graphId); m_stateNodeIdMap.insert(state, nodeId); } void StateMachineViewerWidget::transitionAdded(const TransitionId transition, const StateId source, const StateId target, const QString &label) { NodeId sourceStateId = m_stateNodeIdMap.value(source); NodeId targetStateId = m_stateNodeIdMap.value(target); if (!sourceStateId || !targetStateId) { return; } EdgeId id = m_graph->addEdge(sourceStateId, targetStateId, QString::number(transition)); Q_ASSERT(id); if (!label.isEmpty()) { m_graph->setEdgeAttribute(id, QLatin1String("label"), label); } m_transitionEdgeIdMap.insert(transition, id); } int StateMachineViewerWidget::maximumMegaPixels() const { return QSettings().value("StateMachineViewerServer/maximumMegaPixels", 10).toInt(); } void StateMachineViewerWidget::setMaximumMegaPixels(int megaPixels) { QSettings().setValue("StateMachineViewerServer/maximumMegaPixels", megaPixels); } void StateMachineViewerWidget::exportAsImage() { QSettings settings; const QString key = QLatin1String("StateMachineViewerServer/imageDir"); QString lastDir = settings.value(key).toString(); const QString fileName = QFileDialog::getSaveFileName(this, tr("Save As Image"), lastDir, tr("Images (*.png *.jpg *.jpeg)")); if (fileName.isEmpty()) { return; } lastDir = QFileInfo(fileName).absolutePath(); settings.setValue(key, lastDir); QGraphicsView* view = m_ui->graphicsView; const QRectF sceneRect = view->transform().mapRect(view->sceneRect()); QSizeF size(sceneRect.width(), sceneRect.height()); // limit mega pixels const double maxPixels = maximumMegaPixels() * 1E+6; const double actualMegaPixels = size.width() * size.height(); if (actualMegaPixels > maxPixels && actualMegaPixels != 0) { size *= sqrt(maxPixels / actualMegaPixels); } int quality = -1; const char* format; if (fileName.endsWith(QLatin1String("jpg"), Qt::CaseInsensitive) || fileName.endsWith(QLatin1String("jpeg"), Qt::CaseInsensitive)) { format = "JPG"; quality = 90; } else { format = "PNG"; } QImage image(size.width() , size.height(), QImage::Format_ARGB32_Premultiplied); image.fill(QColor(Qt::white).rgb()); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); view->scene()->render(&painter); image.save(fileName, format, quality); } void StateMachineViewerWidget::stateModelReset() { m_ui->singleStateMachineView->expandAll(); m_lastTransitions.clear(); m_lastConfigurations.clear(); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(StateMachineViewerUiFactory) #endif gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerwidget.h000066400000000000000000000071501255003167400261340ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERWIDGET_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEVIEWERWIDGET_H #include #include "statemachineviewerinterface.h" #include "statemachineviewerutil.h" #include "gvgraph/gvtypes.h" #include #include class QModelIndex; namespace GammaRay { class GVGraph; namespace Ui { class StateMachineViewer; } class GVNodeItem; class GVEdgeItem; class GVGraphItem; class StateMachineViewerWidget : public QWidget { Q_OBJECT public: explicit StateMachineViewerWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); ~StateMachineViewerWidget(); private slots: void clearView(); void repopulateView(); void clearGraph(); void stateAdded(const GammaRay::StateId state, const GammaRay::StateId parent, const bool hasChildren, const QString &label, const GammaRay::StateType type, const bool connectToInitial); void stateConfigurationChanged(const GammaRay::StateMachineConfiguration &config); void transitionAdded(const GammaRay::TransitionId transition, const GammaRay::StateId source, const GammaRay::StateId target, const QString &label); void transitionTriggered(GammaRay::TransitionId transition, const QString &label); void showMessage(const QString &message); void statusChanged(const bool haveStateMachine, const bool running); void exportAsImage(); void stateModelReset(); void setMaximumMegaPixels(int); private: void updateStateItems(); void updateTransitionItems(); int maximumMegaPixels() const; QScopedPointer m_ui; GVGraph *m_graph; QFont m_font; QHash m_transitionEdgeIdMap; QHash m_stateGraphIdMap; QHash m_stateNodeIdMap; QHash m_edgeItemMap; QHash m_graphItemMap; QHash m_nodeItemMap; QHash m_nodeTypeMap; RingBuffer m_lastConfigurations; RingBuffer m_lastTransitions; StateMachineViewerInterface *m_interface; }; class StateMachineViewerUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_statemachineviewer.json") }; } #endif // GAMMARAY_STATEMACHINEVIEWERWIDGET_H gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerwidgetng.cpp000066400000000000000000000252661255003167400270240ustar00rootroot00000000000000/* statemachineviewerwidgetng.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachineviewerwidgetng.h" #include "ui_statemachineviewer.h" #include "statemachineviewerclient.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define IF_DEBUG(x) using namespace GammaRay; namespace { QObject* createStateMachineViewerClient(const QString &/*name*/, QObject *parent) { return new StateMachineViewerClient(parent); } KDSME::RuntimeController::Configuration toSmeConfiguration(const StateMachineConfiguration& config, const QHash& map) { KDSME::RuntimeController::Configuration result; foreach (const StateId& id, config) { if (auto state = map.value(id)) { result << state; } } return result; } } StateMachineViewerWidgetNG::StateMachineViewerWidgetNG(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) , m_ui(new Ui::StateMachineViewer) , m_machine(0) { ObjectBroker::registerClientObjectFactoryCallback(createStateMachineViewerClient); m_interface = ObjectBroker::object(); m_ui->setupUi(this); m_ui->graphicsView->setDragMode(QGraphicsView::ScrollHandDrag); m_ui->graphicsView->setScene(new QGraphicsScene(this)); m_ui->graphicsView->setRenderHint(QPainter::Antialiasing); QAbstractItemModel *stateMachineModel = ObjectBroker::model("com.kdab.GammaRay.StateMachineModel"); m_ui->stateMachinesView->setModel(stateMachineModel); m_ui->stateMachinesView->setSelectionModel(ObjectBroker::selectionModel(stateMachineModel)); new DeferredResizeModeSetter(m_ui->stateMachinesView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(m_ui->stateMachinesView->header(), 1, QHeaderView::ResizeToContents); new DeferredTreeViewConfiguration(m_ui->stateMachinesView, false); QAbstractItemModel *stateModel = ObjectBroker::model("com.kdab.GammaRay.StateModel"); connect(stateModel, SIGNAL(modelReset()), this, SLOT(stateModelReset())); m_ui->singleStateMachineView->setModel(stateModel); m_ui->singleStateMachineView->setSelectionMode(QAbstractItemView::ExtendedSelection); new DeferredResizeModeSetter(m_ui->singleStateMachineView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(m_ui->singleStateMachineView->header(), 1, QHeaderView::ResizeToContents); new DeferredTreeViewConfiguration(m_ui->singleStateMachineView, true, false); connect(m_ui->depthSpinBox, SIGNAL(valueChanged(int)), m_interface, SLOT(setMaximumDepth(int))); connect(m_ui->startStopButton, SIGNAL(clicked()), m_interface, SLOT(toggleRunning())); // TODO: Re-enable? //connect(m_ui->exportButton, SIGNAL(clicked()), SLOT(exportAsImage())); m_ui->exportButton->setDisabled(true); m_ui->maxMegaPixelsSpinBox->setValue(maximumMegaPixels()); connect(m_ui->maxMegaPixelsSpinBox, SIGNAL(valueChanged(int)), SLOT(setMaximumMegaPixels(int))); m_stateMachineView = new KDSME::StateMachineView; // FIXME: Do it properly delete m_ui->graphicsView; m_ui->verticalSplitter->setChildrenCollapsible(false); m_ui->verticalSplitter->addWidget(m_stateMachineView); m_ui->verticalSplitter->setStretchFactor(m_ui->verticalSplitter->indexOf(m_stateMachineView), 3); connect(m_interface, SIGNAL(message(QString)), this, SLOT(showMessage(QString))); connect(m_interface, SIGNAL(stateConfigurationChanged(GammaRay::StateMachineConfiguration)), this, SLOT(stateConfigurationChanged(GammaRay::StateMachineConfiguration))); connect(m_interface, SIGNAL(stateAdded(GammaRay::StateId,GammaRay::StateId,bool,QString,GammaRay::StateType,bool)), this, SLOT(stateAdded(GammaRay::StateId,GammaRay::StateId,bool,QString,GammaRay::StateType,bool))); connect(m_interface, SIGNAL(transitionAdded(GammaRay::TransitionId,GammaRay::StateId,GammaRay::StateId,QString)), this, SLOT(transitionAdded(GammaRay::TransitionId,GammaRay::StateId,GammaRay::StateId,QString))); connect(m_interface, SIGNAL(statusChanged(bool,bool)), this, SLOT(statusChanged(bool,bool))); connect(m_interface, SIGNAL(transitionTriggered(GammaRay::TransitionId,QString)), this, SLOT(transitionTriggered(GammaRay::TransitionId,QString))); connect(m_interface, SIGNAL(aboutToRepopulateGraph()), this, SLOT(clearGraph())); connect(m_interface, SIGNAL(graphRepopulated()), this, SLOT(repopulateView())); // append actions for the state machine view KDSME::StateMachineToolBar* toolBar = new KDSME::StateMachineToolBar(m_stateMachineView, this); toolBar->setHidden(true); addActions(toolBar->actions()); m_interface->repopulateGraph(); } StateMachineViewerWidgetNG::~StateMachineViewerWidgetNG() { } int StateMachineViewerWidgetNG::maximumMegaPixels() const { return QSettings().value("StateMachineViewerServer/maximumMegaPixels", 10).toInt(); } void StateMachineViewerWidgetNG::setMaximumMegaPixels(int megaPixels) { QSettings().setValue("StateMachineViewerServer/maximumMegaPixels", megaPixels); } void StateMachineViewerWidgetNG::showMessage(const QString& message) { // update log QPlainTextEdit *plainTextEdit = m_ui->plainTextEdit; plainTextEdit->appendPlainText(message); // auto-scroll hack QScrollBar *sb = plainTextEdit->verticalScrollBar(); sb->setValue(sb->maximum()); } void StateMachineViewerWidgetNG::stateConfigurationChanged(const StateMachineConfiguration& config) { if (m_machine) { m_machine->runtimeController()->setActiveConfiguration(toSmeConfiguration(config, m_idToStateMap)); } } void StateMachineViewerWidgetNG::stateAdded(const StateId stateId, const StateId parentId, const bool hasChildren, const QString& label, const StateType type, const bool connectToInitial) { Q_UNUSED(hasChildren); IF_DEBUG(qDebug() << "stateAdded" << stateId << parentId << label << type); if (m_idToStateMap.contains(stateId)) { return; } KDSME::State* parentState = m_idToStateMap.value(parentId); KDSME::State* state = 0; if (type == StateMachineState) { state = m_machine = new KDSME::StateMachine; } else if (type == GammaRay::FinalState) { state = new KDSME::FinalState(parentState); } else if (type == GammaRay::ShallowHistoryState) { state = new KDSME::HistoryState(KDSME::HistoryState::ShallowHistory, parentState); } else if (type == GammaRay::DeepHistoryState) { state = new KDSME::HistoryState(KDSME::HistoryState::DeepHistory, parentState); } else { state = new KDSME::State(parentState); } if (connectToInitial && parentState) { KDSME::State* initialState = new KDSME::PseudoState(KDSME::PseudoState::InitialState, parentState); initialState->setFlags(KDSME::Element::ElementIsSelectable); KDSME::Transition* transition = new KDSME::Transition(initialState); transition->setTargetState(state); transition->setFlags(KDSME::Element::ElementIsSelectable); } Q_ASSERT(state); state->setLabel(label); state->setInternalId(stateId); state->setFlags(KDSME::Element::ElementIsSelectable); m_idToStateMap[stateId] = state; } void StateMachineViewerWidgetNG::transitionAdded(const TransitionId transitionId, const StateId sourceId, const StateId targetId, const QString& label) { if (m_idToTransitionMap.contains(transitionId)) return; IF_DEBUG(qDebug() << "transitionAdded" << transitionId << label << sourceId << targetId); KDSME::State* source = m_idToStateMap.value(sourceId); KDSME::State* target = m_idToStateMap.value(targetId); if (!source || !target) { qDebug() << "Null source or target for transition:" << transitionId; return; } KDSME::Transition* transition = new KDSME::Transition(source); transition->setTargetState(target); transition->setLabel(label); transition->setFlags(KDSME::Element::ElementIsSelectable); m_idToTransitionMap[transitionId] = transition; } void StateMachineViewerWidgetNG::statusChanged(const bool haveStateMachine, const bool running) { if (m_machine) { m_machine->runtimeController()->setIsRunning(running); } if (!running) { m_ui->startStopButton->setChecked(false); m_ui->startStopButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); } else { m_ui->startStopButton->setChecked(true); m_ui->startStopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); } m_ui->startStopButton->setEnabled(haveStateMachine); } void StateMachineViewerWidgetNG::transitionTriggered(TransitionId transitionId, const QString& label) { Q_UNUSED(label); if (m_machine) { m_machine->runtimeController()->setLastTransition(m_idToTransitionMap.value(transitionId)); } } void StateMachineViewerWidgetNG::clearGraph() { IF_DEBUG(qDebug() << Q_FUNC_INFO); m_stateMachineView->scene()->setRootState(0); m_idToStateMap.clear(); m_idToTransitionMap.clear(); } void StateMachineViewerWidgetNG::repopulateView() { IF_DEBUG(qDebug() << Q_FUNC_INFO); m_stateMachineView->scene()->setRootState(m_machine); if (!m_machine) return; m_stateMachineView->scene()->layout(); IF_DEBUG(m_machine->dumpObjectTree();) m_stateMachineView->fitInView(); } void StateMachineViewerWidgetNG::stateModelReset() { m_ui->singleStateMachineView->expandAll(); if (m_machine) { m_machine->runtimeController()->clear(); } } gammaray-2.3.0/plugins/statemachineviewer/statemachineviewerwidgetng.h000066400000000000000000000060421255003167400264600ustar00rootroot00000000000000/* statemachineviewerwidgetng.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef STATEMACHINEVIEWERWIDGETNG_H #define STATEMACHINEVIEWERWIDGETNG_H #include #include "statemachineviewerinterface.h" #include namespace KDSME { class State; class StateMachine; class StateMachineView; class Transition; } namespace GammaRay { namespace Ui { class StateMachineViewer; } class StateMachineViewerWidgetNG : public QWidget { Q_OBJECT public: explicit StateMachineViewerWidgetNG(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~StateMachineViewerWidgetNG(); private slots: void showMessage(const QString &message); void stateAdded(const GammaRay::StateId stateId, const GammaRay::StateId parentId, const bool hasChildren, const QString& label, const GammaRay::StateType type, const bool connectToInitial); void stateConfigurationChanged(const GammaRay::StateMachineConfiguration &config); void transitionAdded(const GammaRay::TransitionId transitionId, const GammaRay::StateId source, const GammaRay::StateId target, const QString& label); void statusChanged(const bool haveStateMachine, const bool running); void transitionTriggered(GammaRay::TransitionId transition, const QString &label); void stateModelReset(); void repopulateView(); void clearGraph(); void setMaximumMegaPixels(int); private: int maximumMegaPixels() const; QScopedPointer m_ui; KDSME::StateMachineView* m_stateMachineView; StateMachineViewerInterface *m_interface; QHash m_idToStateMap; QHash m_idToTransitionMap; KDSME::StateMachine* m_machine; }; class StateMachineViewerUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_statemachineviewer.json") }; } #endif // STATEMACHINEVIEWERWIDGETNG_H gammaray-2.3.0/plugins/statemachineviewer/statemachinewatcher.cpp000066400000000000000000000104011255003167400254100ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemachinewatcher.h" #include #include #include #include #include using namespace GammaRay; StateMachineWatcher::StateMachineWatcher(QObject *parent) : QObject(parent), m_watchedStateMachine(0), m_lastEnteredState(0), m_lastExitedState(0) { } StateMachineWatcher::~StateMachineWatcher() { } void StateMachineWatcher::setWatchedStateMachine(QStateMachine *machine) { if (m_watchedStateMachine == machine) { return; } m_watchedStateMachine = machine; clearWatchedStates(); Q_FOREACH (QAbstractState* state, machine->findChildren()) { watchState(state); } emit watchedStateMachineChanged(machine); } QStateMachine *StateMachineWatcher::watchedStateMachine() const { return m_watchedStateMachine; } void StateMachineWatcher::watchState(QAbstractState *state) { if (state->machine() != m_watchedStateMachine) { return; } connect(state, SIGNAL(entered()), this, SLOT(handleStateEntered()), Qt::UniqueConnection); connect(state, SIGNAL(exited()), this, SLOT(handleStateExited()), Qt::UniqueConnection); connect(state, SIGNAL(destroyed(QObject*)), this, SLOT(handleStateDestroyed()), Qt::UniqueConnection); Q_FOREACH (QAbstractTransition *transition, state->findChildren()) { connect(transition, SIGNAL(triggered()), this, SLOT(handleTransitionTriggered()), Qt::UniqueConnection); } m_watchedStates << state; } void StateMachineWatcher::clearWatchedStates() { Q_FOREACH (QAbstractState *state, m_watchedStates) { disconnect(state, SIGNAL(entered()), this, SLOT(handleStateEntered())); disconnect(state, SIGNAL(exited()), this, SLOT(handleStateExited())); disconnect(state, SIGNAL(destroyed(QObject*)), this, SLOT(handleStateDestroyed())); Q_FOREACH (QAbstractTransition *transition, state->findChildren()) { disconnect(transition, SIGNAL(triggered()), this, SLOT(handleTransitionTriggered())); } } m_watchedStates.clear(); } void StateMachineWatcher::handleTransitionTriggered() { QAbstractTransition *transition = qobject_cast(QObject::sender()); Q_ASSERT(transition); emit transitionTriggered(transition); } void StateMachineWatcher::handleStateEntered() { QAbstractState* state = qobject_cast(QObject::sender()); Q_ASSERT(state); if (state->machine() != m_watchedStateMachine) { return; } if (state == m_lastEnteredState) { return; } m_lastEnteredState = state; emit stateEntered(state); } void StateMachineWatcher::handleStateExited() { QAbstractState* state = qobject_cast(QObject::sender()); Q_ASSERT(state); if (state->machine() != m_watchedStateMachine) { return; } if (state == m_lastExitedState) { return; } m_lastExitedState = state; emit stateExited(state); } void StateMachineWatcher::handleStateDestroyed() { QAbstractState* state = static_cast(QObject::sender()); Q_ASSERT(state); const int index = m_watchedStates.indexOf(state); Q_ASSERT(index != -1); m_watchedStates.remove(index); } gammaray-2.3.0/plugins/statemachineviewer/statemachinewatcher.h000066400000000000000000000044341255003167400250660ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEWATCHER_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMACHINEWATCHER_H #include #include class QAbstractState; class QAbstractState; class QAbstractTransition; class QState; class QStateMachine; namespace GammaRay { class StateMachineWatcher : public QObject { Q_OBJECT public: explicit StateMachineWatcher(QObject *parent = 0); virtual ~StateMachineWatcher(); void setWatchedStateMachine(QStateMachine *machine); QStateMachine *watchedStateMachine() const; Q_SIGNALS: void stateEntered(QAbstractState *state); void stateExited(QAbstractState *state); void transitionTriggered(QAbstractTransition*); void watchedStateMachineChanged(QStateMachine *); private Q_SLOTS: void watchState(QAbstractState *state); void clearWatchedStates(); void handleStateEntered(); void handleStateExited(); void handleStateDestroyed(); void handleTransitionTriggered(); private: QStateMachine *m_watchedStateMachine; QVector m_watchedStates; QAbstractState *m_lastEnteredState; QAbstractState *m_lastExitedState; }; } #endif // GAMMARAY_STATEMACHINEWATCHER_H gammaray-2.3.0/plugins/statemachineviewer/statemodel.cpp000066400000000000000000000176111255003167400235400ustar00rootroot00000000000000/* statemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "statemodel.h" #include "statemachinewatcher.h" #include #include #include #include #include // #include using namespace GammaRay; namespace GammaRay { class StateModelPrivate { StateModelPrivate(StateModel *qq) : q_ptr(qq), m_stateMachineWatcher(new StateMachineWatcher(qq)), m_stateMachine(0) { Q_ASSERT(qq->connect(m_stateMachineWatcher, SIGNAL(stateEntered(QAbstractState*)), qq, SLOT(stateConfigurationChanged()))); Q_ASSERT(qq->connect(m_stateMachineWatcher, SIGNAL(stateExited(QAbstractState*)), qq, SLOT(stateConfigurationChanged()))); } Q_DECLARE_PUBLIC(StateModel) StateModel * const q_ptr; StateMachineWatcher * const m_stateMachineWatcher; QStateMachine *m_stateMachine; QSet m_lastConfiguration; QList children(QObject *parent) const; QObject *mapModelIndex2QObject(const QModelIndex &) const; QModelIndex indexForState(QAbstractState *state) const; // private slots: void stateConfigurationChanged(); void handleMachineDestroyed(QObject*); }; } QList StateModelPrivate::children(QObject *parent) const { QList result; if (parent == 0) { parent = m_stateMachine; } // if the state machine is not yet set, return an empty list if (!parent) { return result; } foreach (QObject *o, parent->children()) { if (o->inherits("QAbstractState")) { result.append(o); } } qSort(result); return result; } QObject *StateModelPrivate::mapModelIndex2QObject(const QModelIndex &index) const { if (index.isValid()) { QObjectList c = children(reinterpret_cast(index.internalPointer())); return c[index.row()]; } return m_stateMachine; } QModelIndex StateModelPrivate::indexForState(QAbstractState *state) const { Q_ASSERT(state); if (state == m_stateMachine) { return QModelIndex(); } Q_ASSERT(state->parentState()); Q_Q(const StateModel); int row = children(state->parentState()).indexOf(state); if (row == -1) { return QModelIndex(); } return q->index(row, 0, indexForState(state->parentState())); } void StateModelPrivate::stateConfigurationChanged() { Q_Q(StateModel); QSet newConfig = m_stateMachine->configuration(); // states which became active foreach (QAbstractState *state, (newConfig - m_lastConfiguration)) { const QModelIndex source = indexForState(state); if (source.isValid()) { q->dataChanged(source, source); } } // states which became inactive foreach (QAbstractState *state, (m_lastConfiguration - newConfig)) { const QModelIndex source = indexForState(state); if (source.isValid()) { q->dataChanged(source, source); } } m_lastConfiguration = newConfig; } void StateModelPrivate::handleMachineDestroyed(QObject*) { Q_Q(StateModel); q->beginResetModel(); m_stateMachine = 0; q->endResetModel(); } StateModel::StateModel(QObject *parent) : ObjectModelBase(parent), d_ptr(new StateModelPrivate(this)) { QHash _roleNames = roleNames(); _roleNames.insert(TransitionsRole, "transitions"); _roleNames.insert(IsInitialStateRole, "isInitial"); setRoleNames(_roleNames); } StateModel::~StateModel() { delete d_ptr; } void StateModel::setStateMachine(QStateMachine *stateMachine) { Q_D(StateModel); if (d->m_stateMachine == stateMachine) { return; } if (d->m_stateMachine) { disconnect(d->m_stateMachine, SIGNAL(destroyed(QObject*)), this, SLOT(handleMachineDestroyed(QObject*))); } beginResetModel(); d->m_stateMachine = stateMachine; d->m_lastConfiguration = (stateMachine ? stateMachine->configuration() : QSet()); endResetModel(); if (d->m_stateMachine) { connect(d->m_stateMachine, SIGNAL(destroyed(QObject*)), this, SLOT(handleMachineDestroyed(QObject*))); } d->m_stateMachineWatcher->setWatchedStateMachine(stateMachine); } QStateMachine *StateModel::stateMachine() const { Q_D(const StateModel); return d->m_stateMachine; } QVariant StateModel::data(const QModelIndex &index, int role) const { Q_D(const StateModel); if (!index.isValid()) { return QVariant(); } if (role == TransitionsRole) { QObject *obj = d->mapModelIndex2QObject(index); QState *state = qobject_cast(obj); if (state) { QObjectList l = d->children(state->parent()); Q_ASSERT(l.contains(state)); QStringList nums; QList trs = state->transitions(); nums.reserve(trs.size()); foreach (QAbstractTransition *t, trs) { QAbstractState *child = t->targetState(); Q_ASSERT(l.contains(child)); nums << QString::number(l.indexOf(child) - l.indexOf(state)); } return nums.join(","); } } if (role == IsInitialStateRole) { QObject *obj = d->mapModelIndex2QObject(index); QState *state = qobject_cast(obj); if (state) { QState *parentState = state->parentState(); return (state == parentState->initialState()); } } QObject *obj = d->mapModelIndex2QObject(index); if (obj) { if (role == StateObjectRole) { return QVariant::fromValue(obj); } if (index.column() == 0 && role == Qt::CheckStateRole) { QAbstractState *s = qobject_cast(obj); if (s) { return d->m_stateMachine->configuration().contains(s) ? Qt::Checked : Qt::Unchecked; } } return dataForObject(obj, index, role); } return QVariant(); } int StateModel::rowCount(const QModelIndex &parent) const { Q_D(const StateModel); return d->children(d->mapModelIndex2QObject(parent)).count(); } QModelIndex StateModel::index(int row, int column, const QModelIndex &parent) const { Q_D(const StateModel); if (row < 0 || column < 0 || column > 1) { return QModelIndex(); } QObject *internalPointer = 0; if (!parent.isValid()) { internalPointer = d->m_stateMachine; } else { QObject *o = reinterpret_cast(parent.internalPointer()); QObjectList c = d->children(o); internalPointer = c.at(parent.row()); } QObjectList c = d->children(internalPointer); if (row >= c.size()) { return QModelIndex(); } return createIndex(row, column, internalPointer); } QModelIndex StateModel::parent(const QModelIndex &index) const { Q_D(const StateModel); if (!index.isValid()) { return QModelIndex(); } QObject *obj = d->mapModelIndex2QObject(index); QObject *parent = obj->parent(); if (parent == d->m_stateMachine) { return QModelIndex(); } QObject *grandParent = parent->parent(); int row = d->children(grandParent).indexOf(parent); return createIndex(row, 0, grandParent); } #include "moc_statemodel.cpp" gammaray-2.3.0/plugins/statemachineviewer/statemodel.h000066400000000000000000000045001255003167400231760ustar00rootroot00000000000000/* statemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_STATEMODEL_H #define GAMMARAY_STATEMACHINEVIEWER_STATEMODEL_H #include class QAbstractTransition; class QStateMachine; namespace GammaRay { class StateModelPrivate; class StateModel : public ObjectModelBase { Q_OBJECT public: enum Roles { TransitionsRole = ObjectModel::UserRole + 1, IsInitialStateRole, StateObjectRole = ObjectModel::UserRole + 11 }; explicit StateModel(QObject *parent = 0); ~StateModel(); void setStateMachine(QStateMachine *stateMachine); QStateMachine *stateMachine() const; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; protected: Q_DECLARE_PRIVATE(StateModel) StateModelPrivate * const d_ptr; private: Q_PRIVATE_SLOT(d_func(), void stateConfigurationChanged()) Q_PRIVATE_SLOT(d_func(), void handleMachineDestroyed(QObject*)) }; } #endif gammaray-2.3.0/plugins/statemachineviewer/test_main.cpp000066400000000000000000000053321255003167400233570ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gvgraph/gvgraph.h" #include "gvgraph/gvgraphitems.h" #include #include #include using namespace GammaRay; int main(int argc, char *argv[]) { QApplication app(argc, argv); // build data GVGraph *graph = new GVGraph("Graph"); NodeId nid1 = graph->addNode("Node1"); GraphId gid1 = graph->addGraph("SubGraph1"); NodeId nid2 = graph->addNode("Node2", gid1); NodeId nid3 = graph->addNode("Node3", gid1); EdgeId eid1 = graph->addEdge(nid1, nid2, "Edge1"); graph->setEdgeAttribute(eid1, "label", "Edge1"); EdgeId eid2 = graph->addEdge(nid2, nid3, "Edge2"); graph->setEdgeAttribute(eid2, "label", "Edge2"); EdgeId eid3 = graph->addEdge(nid1, nid3, "Edge3"); graph->setEdgeAttribute(eid3, "label", "Edge3"); graph->applyLayout(); if (argc > 1 && strcmp(argv[1], "--no-gui") == 0) { return 0; } // build ui QGraphicsView *view = new QGraphicsView; view->setRenderHint(QPainter::Antialiasing); QGraphicsScene *scene = new QGraphicsScene; view->setScene(scene); Q_FOREACH (const GVNodePair &pair, graph->gvNodes()) { const GVNode node = pair.second; QGraphicsItem *item = new GVNodeItem(node, 0); scene->addItem(item); } Q_FOREACH (const GVEdgePair &pair, graph->gvEdges()) { const GVEdge edge = pair.second; QGraphicsItem *item = new GVEdgeItem(edge, 0); scene->addItem(item); } Q_FOREACH (const GVSubGraphPair &pair, graph->gvSubGraphs()) { const GVSubGraph graph = pair.second; QGraphicsItem *item = new GVGraphItem(graph, 0); scene->addItem(item); } delete graph; graph = 0; view->show(); return app.exec(); } gammaray-2.3.0/plugins/statemachineviewer/transitionmodel.cpp000066400000000000000000000116041255003167400246060ustar00rootroot00000000000000/* transitionmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "transitionmodel.h" #include #include #include #include #include #include // #include using namespace GammaRay; namespace GammaRay { class TransitionModelPrivate { TransitionModelPrivate(TransitionModel *qq) : q_ptr(qq), m_state(0) { } Q_DECLARE_PUBLIC(TransitionModel) TransitionModel * const q_ptr; QAbstractState * m_state; QList children(QObject *parent) const; QObject *mapModelIndex2QObject(const QModelIndex &) const; }; } QList TransitionModelPrivate::children(QObject *parent) const { QList result; if (parent == 0) { parent = m_state; } foreach (QObject *o, parent->children()) { if (o->inherits("QAbstractTransition")) { result.append(o); } } qSort(result); return result; } QObject *TransitionModelPrivate::mapModelIndex2QObject(const QModelIndex &index) const { if (index.isValid()) { QObjectList c = children(reinterpret_cast(index.internalPointer())); return c[index.row()]; } return m_state; } TransitionModel::TransitionModel(QObject *parent) : ObjectModelBase(parent), d_ptr(new TransitionModelPrivate(this)) { QHash _roleNames = roleNames(); // TODO setRoleNames(_roleNames); } TransitionModel::~TransitionModel() { delete d_ptr; } void TransitionModel::setState(QAbstractState *state) { Q_D(TransitionModel); beginResetModel(); d->m_state = state; endResetModel(); } QVariant TransitionModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section < 2) { return ObjectModelBase::headerData(section, orientation, role); } if (section == 2) { return "Signal"; } if (section == 3) { return "Target"; } return QVariant(); } QVariant TransitionModel::data(const QModelIndex &index, int role) const { Q_D(const TransitionModel); if (!index.isValid() || !d->m_state) { return QVariant(); } QObject *obj = d->mapModelIndex2QObject(index); if (obj) { if (index.column() == 2 && role == Qt::DisplayRole) { QSignalTransition *sigTransition = qobject_cast(obj); if (sigTransition) { return sigTransition->signal(); } } else if (index.column() == 3 && role == Qt::DisplayRole) { QAbstractTransition *transition = qobject_cast(obj); if (transition) { return Util::displayString(transition->targetState()); } } return dataForObject(obj, index, role); } return QVariant(); } int TransitionModel::columnCount(const QModelIndex &parent) const { return ObjectModelBase::columnCount(parent) + 2; } int TransitionModel::rowCount(const QModelIndex &parent) const { Q_D(const TransitionModel); if (!d->m_state) { return 0; } return d->children(d->mapModelIndex2QObject(parent)).count(); } QModelIndex TransitionModel::index(int row, int column, const QModelIndex &parent) const { Q_D(const TransitionModel); if (parent.isValid() || !d->m_state) { return QModelIndex(); } if (row < 0 || column < 0 || column > 3) { return QModelIndex(); } QObject *internalPointer = 0; if (!parent.isValid()) { internalPointer = d->m_state; } else { QObject *o = reinterpret_cast(parent.internalPointer()) ; QObjectList c = d->children(o); internalPointer = c.at(parent.row()); } QObjectList c = d->children(internalPointer); if (row >= c.size()) { return QModelIndex(); } return createIndex(row, column, internalPointer); } QModelIndex TransitionModel::parent(const QModelIndex &index) const { Q_UNUSED(index); //Q_D(const TransitionModel); return QModelIndex(); } gammaray-2.3.0/plugins/statemachineviewer/transitionmodel.h000066400000000000000000000042651255003167400242600ustar00rootroot00000000000000/* transitionmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STATEMACHINEVIEWER_TRANSITIONMODEL_H #define GAMMARAY_STATEMACHINEVIEWER_TRANSITIONMODEL_H #include class QAbstractState; namespace GammaRay { class TransitionModelPrivate; class TransitionModel : public ObjectModelBase { public: explicit TransitionModel(QObject *parent = 0); ~TransitionModel(); void setState(QAbstractState *state); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount (const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; protected: Q_DECLARE_PRIVATE(TransitionModel) TransitionModelPrivate *const d_ptr; }; } #endif gammaray-2.3.0/plugins/styleinspector/000077500000000000000000000000001255003167400200655ustar00rootroot00000000000000gammaray-2.3.0/plugins/styleinspector/CMakeLists.txt000066400000000000000000000023611255003167400226270ustar00rootroot00000000000000# probe part set(gammaray_styleinspector_plugin_srcs styleinspector.cpp pixelmetricmodel.cpp standardiconmodel.cpp primitivemodel.cpp controlmodel.cpp styleoption.cpp abstractstyleelementmodel.cpp abstractstyleelementstatetable.cpp complexcontrolmodel.cpp dynamicproxystyle.cpp styleinspectorinterface.cpp ${CMAKE_SOURCE_DIR}/ui/palettemodel.cpp ) gammaray_add_plugin(gammaray_styleinspector_plugin gammaray_styleinspector.desktop ${gammaray_styleinspector_plugin_srcs} ) target_link_libraries(gammaray_styleinspector_plugin ${QT_QTGUI_LIBRARIES} gammaray_core ) if(QNXNTO) target_link_libraries(gammaray_styleinspector_plugin cpp) endif() # ui part if(GAMMARAY_BUILD_UI) set(gammaray_styleinspector_ui_plugin_srcs styleinspectorwidget.cpp styleelementstatetablepage.cpp styleinspectorinterface.cpp styleinspectorclient.cpp ) qt4_wrap_ui(gammaray_styleinspector_ui_plugin_srcs styleinspectorwidget.ui styleelementstatetablepage.ui ) gammaray_add_plugin(gammaray_styleinspector_ui_plugin gammaray_styleinspector_ui.desktop ${gammaray_styleinspector_ui_plugin_srcs} ) target_link_libraries(gammaray_styleinspector_ui_plugin ${QT_QTGUI_LIBRARIES} gammaray_ui ) endif() gammaray-2.3.0/plugins/styleinspector/abstractstyleelementmodel.cpp000066400000000000000000000044131255003167400260520ustar00rootroot00000000000000/* abstractstyleelementmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "abstractstyleelementmodel.h" #include #include #include using namespace GammaRay; AbstractStyleElementModel::AbstractStyleElementModel(QObject *parent) : QAbstractTableModel(parent) { } void AbstractStyleElementModel::setStyle(QStyle *style) { beginResetModel(); m_style = QPointer(style); endResetModel(); } QVariant AbstractStyleElementModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_style) { return QVariant(); } return doData(index.row(), index.column(), role); } int AbstractStyleElementModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return doColumnCount(); } int AbstractStyleElementModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !m_style) { return 0; } return doRowCount(); } bool AbstractStyleElementModel::isMainStyle() const { QStyle *style = qApp->style(); forever { if (style == m_style) { return true; } QProxyStyle *proxy = qobject_cast(style); if (!proxy) { return false; } style = proxy->baseStyle(); } } gammaray-2.3.0/plugins/styleinspector/abstractstyleelementmodel.h000066400000000000000000000044361255003167400255240ustar00rootroot00000000000000/* abstractstyleelementmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_ABSTRACTSTYLEELEMENTMODEL_H #define GAMMARAY_STYLEINSPECTOR_ABSTRACTSTYLEELEMENTMODEL_H #include #include class QStyle; namespace GammaRay { /** * Base class for all models showing style elements. */ class AbstractStyleElementModel : public QAbstractTableModel { Q_OBJECT public: explicit AbstractStyleElementModel(QObject *parent = 0); void setStyle(QStyle *style); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; protected: virtual QVariant doData(int row, int column, int role) const = 0; virtual int doColumnCount() const = 0; virtual int doRowCount() const = 0; /** Returns @c true if we are looking at the primary style of the application * ie. the one set in QApplication. This takes proxy styles into account. */ bool isMainStyle() const; protected: QPointer m_style; }; } #endif // GAMMARAY_ABSTRACTSTYLEELEMENTMODEL_H gammaray-2.3.0/plugins/styleinspector/abstractstyleelementstatetable.cpp000066400000000000000000000054211255003167400271020ustar00rootroot00000000000000/* abstractstyleelementstatetable.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "abstractstyleelementstatetable.h" #include "styleoption.h" #include "styleinspectorinterface.h" #include #include #include #include using namespace GammaRay; AbstractStyleElementStateTable::AbstractStyleElementStateTable(QObject *parent) : AbstractStyleElementModel(parent), m_interface(ObjectBroker::object()) { connect(m_interface, SIGNAL(cellSizeChanged()), SLOT(cellSizeChanged())); } void AbstractStyleElementStateTable::cellSizeChanged() { emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } int AbstractStyleElementStateTable::doColumnCount() const { return StyleOption::stateCount(); } QVariant AbstractStyleElementStateTable::doData(int row, int column, int role) const { Q_UNUSED(column); Q_UNUSED(row); if (role == Qt::SizeHintRole) { return m_interface->cellSizeHint(); } return QVariant(); } QVariant AbstractStyleElementStateTable::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && (role == Qt::DisplayRole || role == Qt::ToolTipRole)) { return StyleOption::stateDisplayName(section); } return QAbstractItemModel::headerData(section, orientation, role); } void AbstractStyleElementStateTable::fillStyleOption(QStyleOption *option, int column) const { option->rect = QRect(0, 0, m_interface->cellWidth(), m_interface->cellHeight()); option->palette = m_style->standardPalette(); option->state = StyleOption::prettyState(column); } gammaray-2.3.0/plugins/styleinspector/abstractstyleelementstatetable.h000066400000000000000000000044741255003167400265560ustar00rootroot00000000000000/* abstractstyleelementstatetable.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_ABSTRACTSTYLEELEMENTSTATETABLE_H #define GAMMARAY_STYLEINSPECTOR_ABSTRACTSTYLEELEMENTSTATETABLE_H #include "abstractstyleelementmodel.h" #include class QStyleOption; class QRect; class QPainter; namespace GammaRay { class StyleInspectorInterface; /** * Base class for style element x style option state tables. * Covers the state part, sub-classes need to fill in the corresponding rows. */ class AbstractStyleElementStateTable : public GammaRay::AbstractStyleElementModel { Q_OBJECT public: explicit AbstractStyleElementStateTable(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: int doColumnCount() const Q_DECL_OVERRIDE; QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; /// standard setup for the style option used in a cell in column @p column void fillStyleOption(QStyleOption *option, int column) const; protected: StyleInspectorInterface *m_interface; private slots: void cellSizeChanged(); }; } #endif // GAMMARAY_ABSTRACTSTYLEELEMENTSTATETABLE_H gammaray-2.3.0/plugins/styleinspector/complexcontrolmodel.cpp000066400000000000000000000123621255003167400246660ustar00rootroot00000000000000/* complexcontrolmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "complexcontrolmodel.h" #include "styleoption.h" #include "styleinspectorinterface.h" #include #include #include #include using namespace GammaRay; struct complex_control_element_t { const char *name; QStyle::ComplexControl control; QStyleOption * (*styleOptionFactory)(); QStyle::SubControls subControls; }; #define MAKE_CC2( control, factory ) { #control, QStyle:: control, &StyleOption:: factory, 0 } #define MAKE_CC3( control, factory, subControls ) { #control, QStyle:: control, &StyleOption:: factory, subControls } static const complex_control_element_t complexControlElements[] = { MAKE_CC3(CC_SpinBox, makeSpinBoxStyleOption, QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown | QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField), MAKE_CC3(CC_ComboBox, makeComboBoxStyleOption, QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxArrow | QStyle::SC_ComboBoxEditField | QStyle::SC_ComboBoxListBoxPopup), MAKE_CC3(CC_ScrollBar, makeSliderStyleOption, QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine | QStyle::SC_ScrollBarAddPage | QStyle::SC_ScrollBarSubPage | QStyle::SC_ScrollBarFirst | QStyle::SC_ScrollBarLast | QStyle::SC_ScrollBarSlider | QStyle::SC_ScrollBarGroove), MAKE_CC3(CC_Slider, makeSliderStyleOption, QStyle::SC_SliderGroove | QStyle::SC_SliderHandle | QStyle::SC_SliderTickmarks), MAKE_CC3(CC_ToolButton, makeToolButtonStyleOption, QStyle::SC_ToolButton | QStyle::SC_ToolButtonMenu), MAKE_CC3(CC_TitleBar, makeTitleBarStyleOption, QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarMinButton | QStyle::SC_TitleBarMaxButton | QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarNormalButton | QStyle::SC_TitleBarShadeButton | QStyle::SC_TitleBarUnshadeButton | QStyle::SC_TitleBarContextHelpButton), #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) MAKE_CC2(CC_Q3ListView, makeStyleOptionComplex), #endif MAKE_CC3(CC_Dial, makeSliderStyleOption, QStyle::SC_DialHandle | QStyle::SC_DialGroove | QStyle::SC_DialTickmarks), MAKE_CC2(CC_GroupBox, makeStyleOptionComplex), // MAKE_CC2(CC_GroupBox, makeGroupBoxStyleOption), // TODO: oxygen crashes with that due to widget access MAKE_CC3(CC_MdiControls, makeStyleOptionComplex, QStyle::SC_MdiNormalButton | QStyle::SC_MdiMinButton | QStyle::SC_MdiCloseButton) }; ComplexControlModel::ComplexControlModel(QObject *parent) : AbstractStyleElementStateTable(parent) { } QVariant ComplexControlModel::doData(int row, int column, int role) const { if (role == Qt::DecorationRole) { QPixmap pixmap(m_interface->cellSizeHint()); QPainter painter(&pixmap); Util::drawTransparencyPattern(&painter, pixmap.rect()); painter.scale(m_interface->cellZoom(), m_interface->cellZoom()); QScopedPointer opt( qstyleoption_cast(complexControlElements[row].styleOptionFactory())); Q_ASSERT(opt); fillStyleOption(opt.data(), column); m_style->drawComplexControl(complexControlElements[row].control, opt.data(), &painter); int colorIndex = 7; for (int i = 0; i < 32; ++i) { QStyle::SubControl sc = static_cast(1 << i); if (sc & complexControlElements[row].subControls) { QRectF scRect = m_style->subControlRect(complexControlElements[row].control, opt.data(), sc); scRect.adjust(0, 0, -1.0 / m_interface->cellZoom(), -1.0 / m_interface->cellZoom()); if (scRect.isValid() && !scRect.isEmpty()) { // HACK: add some real color mapping painter.setPen(static_cast(colorIndex++)); painter.drawRect(scRect); } } } return pixmap; } return AbstractStyleElementStateTable::doData(row, column, role); } int ComplexControlModel::doRowCount() const { return sizeof(complexControlElements) / sizeof(complexControlElements[0]); } QVariant ComplexControlModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical && role == Qt::DisplayRole) { return complexControlElements[section].name; } return AbstractStyleElementStateTable::headerData(section, orientation, role); } gammaray-2.3.0/plugins/styleinspector/complexcontrolmodel.h000066400000000000000000000033731255003167400243350ustar00rootroot00000000000000/* complexcontrolmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_COMPLEXCONTROLMODEL_H #define GAMMARAY_STYLEINSPECTOR_COMPLEXCONTROLMODEL_H #include "abstractstyleelementstatetable.h" namespace GammaRay { class ComplexControlModel : public AbstractStyleElementStateTable { Q_OBJECT public: explicit ComplexControlModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; int doRowCount() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_COMPLEXCONTROLMODEL_H gammaray-2.3.0/plugins/styleinspector/controlmodel.cpp000066400000000000000000000117671255003167400233060ustar00rootroot00000000000000/* controlmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "controlmodel.h" #include "styleoption.h" #include "styleinspectorinterface.h" #include #include #include #include using namespace GammaRay; struct control_element_t { const char *name; QStyle::ControlElement control; QStyleOption * (*styleOptionFactory)(); }; #define MAKE_CE( control ) { #control , QStyle:: control, &StyleOption::makeStyleOption } #define MAKE_CE_X( control, factory ) { #control, QStyle:: control, &StyleOption:: factory } static const control_element_t controlElements[] = { MAKE_CE_X(CE_PushButton, makeButtonStyleOption), MAKE_CE_X(CE_PushButtonBevel, makeButtonStyleOption), MAKE_CE_X(CE_PushButtonLabel, makeButtonStyleOption), MAKE_CE_X(CE_CheckBox, makeButtonStyleOption), MAKE_CE_X(CE_CheckBoxLabel, makeButtonStyleOption), MAKE_CE_X(CE_RadioButton, makeButtonStyleOption), MAKE_CE_X(CE_RadioButtonLabel, makeButtonStyleOption), MAKE_CE_X(CE_TabBarTab, makeTabStyleOption), MAKE_CE_X(CE_TabBarTabShape, makeTabStyleOption), MAKE_CE_X(CE_TabBarTabLabel, makeTabStyleOption), MAKE_CE_X(CE_ProgressBar, makeProgressBarStyleOption), MAKE_CE_X(CE_ProgressBarGroove, makeProgressBarStyleOption), MAKE_CE_X(CE_ProgressBarContents, makeProgressBarStyleOption), MAKE_CE_X(CE_ProgressBarLabel, makeProgressBarStyleOption), MAKE_CE_X(CE_MenuItem, makeMenuStyleOption), MAKE_CE(CE_MenuScroller), MAKE_CE(CE_MenuVMargin), MAKE_CE(CE_MenuHMargin), MAKE_CE(CE_MenuTearoff), MAKE_CE(CE_MenuEmptyArea), MAKE_CE_X(CE_MenuBarItem, makeMenuStyleOption), MAKE_CE(CE_MenuBarEmptyArea), MAKE_CE_X(CE_ToolButtonLabel, makeToolButtonStyleOption), MAKE_CE_X(CE_Header, makeHeaderStyleOption), MAKE_CE_X(CE_HeaderSection, makeHeaderStyleOption), MAKE_CE_X(CE_HeaderLabel, makeHeaderStyleOption), #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) MAKE_CE(CE_Q3DockWindowEmptyArea), #endif MAKE_CE_X(CE_ToolBoxTab, makeToolBoxStyleOption), MAKE_CE(CE_SizeGrip), MAKE_CE(CE_Splitter), MAKE_CE(CE_RubberBand), MAKE_CE(CE_DockWidgetTitle), MAKE_CE_X(CE_ScrollBarAddLine, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarSubLine, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarAddPage, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarSubPage, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarSlider, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarFirst, makeSliderStyleOption), MAKE_CE_X(CE_ScrollBarLast, makeSliderStyleOption), MAKE_CE(CE_FocusFrame), MAKE_CE_X(CE_ComboBoxLabel, makeComboBoxStyleOption), MAKE_CE(CE_ToolBar), MAKE_CE_X(CE_ToolBoxTabShape, makeToolBoxStyleOption), MAKE_CE_X(CE_ToolBoxTabLabel, makeToolBoxStyleOption), MAKE_CE_X(CE_HeaderEmptyArea, makeHeaderStyleOption), MAKE_CE(CE_ColumnViewGrip), MAKE_CE_X(CE_ItemViewItem, makeItemViewStyleOption), MAKE_CE_X(CE_ShapedFrame, makeFrameStyleOption) }; ControlModel::ControlModel(QObject *parent) : AbstractStyleElementStateTable(parent) { } QVariant ControlModel::doData(int row, int column, int role) const { if (role == Qt::DecorationRole) { QPixmap pixmap(m_interface->cellSizeHint()); QPainter painter(&pixmap); Util::drawTransparencyPattern(&painter, pixmap.rect()); painter.scale(m_interface->cellZoom(), m_interface->cellZoom()); QScopedPointer opt(controlElements[row].styleOptionFactory()); fillStyleOption(opt.data(), column); m_style->drawControl(controlElements[row].control, opt.data(), &painter); return pixmap; } return AbstractStyleElementStateTable::doData(row, column, role); } int ControlModel::doRowCount() const { return sizeof(controlElements) / sizeof(controlElements[0]); } QVariant ControlModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical && role == Qt::DisplayRole) { return controlElements[section].name; } return AbstractStyleElementStateTable::headerData(section, orientation, role); } gammaray-2.3.0/plugins/styleinspector/controlmodel.h000066400000000000000000000034211255003167400227370ustar00rootroot00000000000000/* controlmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_CONTROLMODEL_H #define GAMMARAY_STYLEINSPECTOR_CONTROLMODEL_H #include "abstractstyleelementstatetable.h" namespace GammaRay { /** * Model for listing all controls provided by a QStyle. */ class ControlModel : public AbstractStyleElementStateTable { Q_OBJECT public: explicit ControlModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; int doRowCount() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_CONTROLMODEL_H gammaray-2.3.0/plugins/styleinspector/dynamicproxystyle.cpp000066400000000000000000000045111255003167400244010ustar00rootroot00000000000000/* dynamicproxystyle.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "dynamicproxystyle.h" #include using namespace GammaRay; QWeakPointer DynamicProxyStyle::s_instance; DynamicProxyStyle::DynamicProxyStyle(QStyle *baseStyle) : QProxyStyle(baseStyle) { s_instance = QWeakPointer(this); } DynamicProxyStyle *DynamicProxyStyle::instance() { if (!s_instance) { insertProxyStyle(); } return s_instance.data(); } bool DynamicProxyStyle::exists() { return s_instance; } void DynamicProxyStyle::insertProxyStyle() { // TODO: if the current style is a CSS proxy, add us underneath // to avoid Qt adding yet another CSS proxy on top qApp->setStyle(new DynamicProxyStyle(qApp->style())); } void DynamicProxyStyle::setPixelMetric(QStyle::PixelMetric metric, int value) { m_pixelMetrics.insert(metric, value); } int DynamicProxyStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { QHash::const_iterator it = m_pixelMetrics.find(metric); if (it != m_pixelMetrics.end()) { return it.value(); } return QProxyStyle::pixelMetric(metric, option, widget); } gammaray-2.3.0/plugins/styleinspector/dynamicproxystyle.h000066400000000000000000000036701255003167400240530ustar00rootroot00000000000000/* dynamicproxystyle.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_DYNAMICPROXYSTYLE_H #define GAMMARAY_STYLEINSPECTOR_DYNAMICPROXYSTYLE_H #include #include namespace GammaRay { /** * A proxy style that allows runtime-editing of various parameters. */ class DynamicProxyStyle : public QProxyStyle { Q_OBJECT public: explicit DynamicProxyStyle(QStyle *baseStyle); static DynamicProxyStyle *instance(); static bool exists(); static void insertProxyStyle(); void setPixelMetric(PixelMetric metric, int value); int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const Q_DECL_OVERRIDE; private: QHash m_pixelMetrics; static QWeakPointer s_instance; }; } #endif // GAMMARAY_DYNAMICPROXYSTYLE_H gammaray-2.3.0/plugins/styleinspector/gammaray_styleinspector.desktop000066400000000000000000000002161255003167400264240ustar00rootroot00000000000000[Desktop Entry] Name=Style X-GammaRay-Types=QStyle; X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_styleinspector_plugin gammaray-2.3.0/plugins/styleinspector/gammaray_styleinspector.json000066400000000000000000000001311255003167400257200ustar00rootroot00000000000000{ "id": "gammaray_styleinspector", "name": "Styles", "types": [ "QStyle" ] } gammaray-2.3.0/plugins/styleinspector/gammaray_styleinspector_ui.desktop000066400000000000000000000002251255003167400271210ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_styleinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_styleinspector_ui_plugin gammaray-2.3.0/plugins/styleinspector/pixelmetricmodel.cpp000066400000000000000000000144241255003167400241440ustar00rootroot00000000000000/* pixelmetricmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pixelmetricmodel.h" #include "dynamicproxystyle.h" #include using namespace GammaRay; struct pixel_metric_t { const char *name; QStyle::PixelMetric pixelMetric; }; #define MAKE_PM(metric) { #metric, QStyle:: metric } static const pixel_metric_t pixelMetrics[] = { MAKE_PM(PM_ButtonMargin), MAKE_PM(PM_ButtonDefaultIndicator), MAKE_PM(PM_MenuButtonIndicator), MAKE_PM(PM_ButtonShiftHorizontal), MAKE_PM(PM_ButtonShiftVertical), MAKE_PM(PM_DefaultFrameWidth), MAKE_PM(PM_SpinBoxFrameWidth), MAKE_PM(PM_ComboBoxFrameWidth), MAKE_PM(PM_MaximumDragDistance), MAKE_PM(PM_ScrollBarExtent), MAKE_PM(PM_ScrollBarSliderMin), MAKE_PM(PM_SliderThickness), MAKE_PM(PM_SliderControlThickness), MAKE_PM(PM_SliderLength), MAKE_PM(PM_SliderTickmarkOffset), MAKE_PM(PM_SliderSpaceAvailable), MAKE_PM(PM_DockWidgetSeparatorExtent), MAKE_PM(PM_DockWidgetHandleExtent), MAKE_PM(PM_DockWidgetFrameWidth), MAKE_PM(PM_TabBarTabOverlap), MAKE_PM(PM_TabBarTabHSpace), MAKE_PM(PM_TabBarTabVSpace), MAKE_PM(PM_TabBarBaseHeight), MAKE_PM(PM_TabBarBaseOverlap), MAKE_PM(PM_ProgressBarChunkWidth), MAKE_PM(PM_SplitterWidth), MAKE_PM(PM_TitleBarHeight), MAKE_PM(PM_MenuScrollerHeight), MAKE_PM(PM_MenuHMargin), MAKE_PM(PM_MenuVMargin), MAKE_PM(PM_MenuPanelWidth), MAKE_PM(PM_MenuTearoffHeight), MAKE_PM(PM_MenuDesktopFrameWidth), MAKE_PM(PM_MenuBarPanelWidth), MAKE_PM(PM_MenuBarItemSpacing), MAKE_PM(PM_MenuBarVMargin), MAKE_PM(PM_MenuBarHMargin), MAKE_PM(PM_IndicatorWidth), MAKE_PM(PM_IndicatorHeight), MAKE_PM(PM_ExclusiveIndicatorWidth), MAKE_PM(PM_ExclusiveIndicatorHeight), #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) MAKE_PM(PM_CheckListButtonSize), MAKE_PM(PM_CheckListControllerSize), #endif MAKE_PM(PM_DialogButtonsSeparator), MAKE_PM(PM_DialogButtonsButtonWidth), MAKE_PM(PM_DialogButtonsButtonHeight), MAKE_PM(PM_MdiSubWindowFrameWidth), MAKE_PM(PM_MdiSubWindowMinimizedWidth), MAKE_PM(PM_HeaderMargin), MAKE_PM(PM_HeaderMarkSize), MAKE_PM(PM_HeaderGripMargin), MAKE_PM(PM_TabBarTabShiftHorizontal), MAKE_PM(PM_TabBarTabShiftVertical), MAKE_PM(PM_TabBarScrollButtonWidth), MAKE_PM(PM_ToolBarFrameWidth), MAKE_PM(PM_ToolBarHandleExtent), MAKE_PM(PM_ToolBarItemSpacing), MAKE_PM(PM_ToolBarItemMargin), MAKE_PM(PM_ToolBarSeparatorExtent), MAKE_PM(PM_ToolBarExtensionExtent), MAKE_PM(PM_SpinBoxSliderHeight), MAKE_PM(PM_DefaultTopLevelMargin), MAKE_PM(PM_DefaultChildMargin), MAKE_PM(PM_DefaultLayoutSpacing), MAKE_PM(PM_ToolBarIconSize), MAKE_PM(PM_ListViewIconSize), MAKE_PM(PM_IconViewIconSize), MAKE_PM(PM_SmallIconSize), MAKE_PM(PM_LargeIconSize), MAKE_PM(PM_FocusFrameVMargin), MAKE_PM(PM_FocusFrameHMargin), MAKE_PM(PM_ToolTipLabelFrameWidth), MAKE_PM(PM_CheckBoxLabelSpacing), MAKE_PM(PM_TabBarIconSize), MAKE_PM(PM_SizeGripSize), MAKE_PM(PM_DockWidgetTitleMargin), MAKE_PM(PM_MessageBoxIconSize), MAKE_PM(PM_ButtonIconSize), MAKE_PM(PM_DockWidgetTitleBarButtonMargin), MAKE_PM(PM_RadioButtonLabelSpacing), MAKE_PM(PM_LayoutLeftMargin), MAKE_PM(PM_LayoutTopMargin), MAKE_PM(PM_LayoutRightMargin), MAKE_PM(PM_LayoutBottomMargin), MAKE_PM(PM_LayoutHorizontalSpacing), MAKE_PM(PM_LayoutVerticalSpacing), MAKE_PM(PM_TabBar_ScrollButtonOverlap), MAKE_PM(PM_TextCursorWidth), MAKE_PM(PM_TabCloseIndicatorWidth), MAKE_PM(PM_TabCloseIndicatorHeight), MAKE_PM(PM_ScrollView_ScrollBarSpacing), MAKE_PM(PM_SubMenuOverlap) }; PixelMetricModel::PixelMetricModel(QObject *parent) : AbstractStyleElementModel(parent) { } QVariant PixelMetricModel::doData(int row, int column, int role) const { if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (column) { case 0: return pixelMetrics[row].name; case 1: return (isMainStyle() && DynamicProxyStyle::exists()) ? DynamicProxyStyle::instance()->pixelMetric(pixelMetrics[row].pixelMetric) : m_style->pixelMetric(pixelMetrics[row].pixelMetric); } } return QVariant(); } int PixelMetricModel::doColumnCount() const { return 2; } int PixelMetricModel::doRowCount() const { return QStyle::PM_SubMenuOverlap + 1; } QVariant PixelMetricModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Metric"); case 1: return tr("Default Value"); } } return QAbstractItemModel::headerData(section, orientation, role); } Qt::ItemFlags PixelMetricModel::flags(const QModelIndex &index) const { const Qt::ItemFlags baseFlags = QAbstractItemModel::flags(index); if (index.isValid() && index.column() == 1 && isMainStyle()) { return baseFlags | Qt::ItemIsEditable; } return baseFlags; } bool PixelMetricModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || index.column() != 1 || !value.isValid() || !value.canConvert(QVariant::Int) || role != Qt::EditRole) { return false; } DynamicProxyStyle::instance()->setPixelMetric( pixelMetrics[index.row()].pixelMetric, value.toInt()); emit dataChanged(index, index); return true; } gammaray-2.3.0/plugins/styleinspector/pixelmetricmodel.h000066400000000000000000000040011255003167400235770ustar00rootroot00000000000000/* pixelmetricmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_PIXELMETRICMODEL_H #define GAMMARAY_STYLEINSPECTOR_PIXELMETRICMODEL_H #include "abstractstyleelementmodel.h" namespace GammaRay { /** * Lists all pixel metric values of a given QStyle. */ class PixelMetricModel : public AbstractStyleElementModel { Q_OBJECT public: explicit PixelMetricModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; protected: QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; int doColumnCount() const Q_DECL_OVERRIDE; int doRowCount() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PIXELMETRICMODEL_H gammaray-2.3.0/plugins/styleinspector/primitivemodel.cpp000066400000000000000000000120741255003167400236260ustar00rootroot00000000000000/* primitivemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "primitivemodel.h" #include "styleoption.h" #include "styleinspectorinterface.h" #include #include #include #include using namespace GammaRay; struct primitive_element_t { const char *name; QStyle::PrimitiveElement primitive; QStyleOption * (*styleOptionFactory)(); }; #define MAKE_PE( primitive ) { #primitive , QStyle:: primitive, &StyleOption::makeStyleOption } #define MAKE_PE_X( primitive, factory ) { #primitive, QStyle:: primitive, &StyleOption:: factory } static const primitive_element_t primititveElements[] = { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) MAKE_PE(PE_Q3CheckListController), MAKE_PE(PE_Q3CheckListExclusiveIndicator), MAKE_PE(PE_Q3CheckListIndicator), MAKE_PE(PE_Q3DockWindowSeparator), MAKE_PE(PE_Q3Separator), #endif MAKE_PE_X(PE_Frame, makeFrameStyleOption), MAKE_PE(PE_FrameDefaultButton), MAKE_PE_X(PE_FrameDockWidget, makeFrameStyleOption), MAKE_PE(PE_FrameFocusRect), MAKE_PE_X(PE_FrameGroupBox, makeFrameStyleOption), MAKE_PE_X(PE_FrameLineEdit, makeFrameStyleOption), MAKE_PE_X(PE_FrameMenu, makeFrameStyleOption), MAKE_PE(PE_FrameStatusBarItem), MAKE_PE_X(PE_FrameTabWidget, makeTabWidgetFrameStyleOption), MAKE_PE_X(PE_FrameWindow, makeFrameStyleOption), MAKE_PE(PE_FrameButtonBevel), MAKE_PE(PE_FrameButtonTool), MAKE_PE_X(PE_FrameTabBarBase, makeTabBarBaseStyleOption), MAKE_PE_X(PE_PanelButtonCommand, makeButtonStyleOption), MAKE_PE(PE_PanelButtonBevel), MAKE_PE(PE_PanelButtonTool), MAKE_PE(PE_PanelMenuBar), MAKE_PE(PE_PanelToolBar), MAKE_PE_X(PE_PanelLineEdit, makeFrameStyleOption), MAKE_PE(PE_IndicatorArrowDown), MAKE_PE(PE_IndicatorArrowLeft), MAKE_PE(PE_IndicatorArrowRight), MAKE_PE(PE_IndicatorArrowUp), MAKE_PE(PE_IndicatorBranch), MAKE_PE(PE_IndicatorButtonDropDown), MAKE_PE(PE_IndicatorViewItemCheck), MAKE_PE_X(PE_IndicatorCheckBox, makeButtonStyleOption), MAKE_PE(PE_IndicatorDockWidgetResizeHandle), MAKE_PE_X(PE_IndicatorHeaderArrow, makeHeaderStyleOption), MAKE_PE(PE_IndicatorMenuCheckMark), MAKE_PE(PE_IndicatorProgressChunk), MAKE_PE_X(PE_IndicatorRadioButton, makeButtonStyleOption), MAKE_PE_X(PE_IndicatorSpinDown, makeSpinBoxStyleOption), MAKE_PE_X(PE_IndicatorSpinMinus, makeSpinBoxStyleOption), MAKE_PE_X(PE_IndicatorSpinPlus, makeSpinBoxStyleOption), MAKE_PE_X(PE_IndicatorSpinUp, makeSpinBoxStyleOption), MAKE_PE(PE_IndicatorToolBarHandle), MAKE_PE(PE_IndicatorToolBarSeparator), MAKE_PE(PE_PanelTipLabel), MAKE_PE_X(PE_IndicatorTabTear, makeTabStyleOption), MAKE_PE(PE_PanelScrollAreaCorner), MAKE_PE(PE_Widget), MAKE_PE(PE_IndicatorColumnViewArrow), MAKE_PE(PE_IndicatorItemViewItemDrop), MAKE_PE_X(PE_PanelItemViewItem, makeItemViewStyleOption), MAKE_PE(PE_PanelItemViewRow), MAKE_PE(PE_PanelStatusBar), MAKE_PE(PE_IndicatorTabClose), MAKE_PE(PE_PanelMenu) }; PrimitiveModel::PrimitiveModel(QObject *parent) : AbstractStyleElementStateTable(parent) { } QVariant PrimitiveModel::doData(int row, int column, int role) const { if (role == Qt::DecorationRole) { QPixmap pixmap(m_interface->cellSizeHint()); QPainter painter(&pixmap); Util::drawTransparencyPattern(&painter, pixmap.rect()); painter.scale(m_interface->cellZoom(), m_interface->cellZoom()); QScopedPointer opt((primititveElements[row].styleOptionFactory)()); fillStyleOption(opt.data(), column); m_style->drawPrimitive(primititveElements[row].primitive, opt.data(), &painter); return pixmap; } return AbstractStyleElementStateTable::doData(row, column, role); } int PrimitiveModel::doRowCount() const { return sizeof(primititveElements) / sizeof(primititveElements[0]) ; } QVariant PrimitiveModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical && role == Qt::DisplayRole) { return primititveElements[section].name; } return AbstractStyleElementStateTable::headerData(section, orientation, role); } gammaray-2.3.0/plugins/styleinspector/primitivemodel.h000066400000000000000000000034141255003167400232710ustar00rootroot00000000000000/* primitivemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_PRIMITIVEMODEL_H #define GAMMARAY_STYLEINSPECTOR_PRIMITIVEMODEL_H #include "abstractstyleelementstatetable.h" namespace GammaRay { /** * Model for primitive style elements. */ class PrimitiveModel : public AbstractStyleElementStateTable { Q_OBJECT public: explicit PrimitiveModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; int doRowCount() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PRIMITIVEMODEL_H gammaray-2.3.0/plugins/styleinspector/standardiconmodel.cpp000066400000000000000000000112471255003167400242700ustar00rootroot00000000000000/* standardiconmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "standardiconmodel.h" #include using namespace GammaRay; StandardIconModel::StandardIconModel(QObject *parent) : AbstractStyleElementModel(parent) { } QVariant StandardIconModel::dataForStandardIcon(QStyle::StandardPixmap stdPix, const QString &name, int column, int role) const { if (column == 0) { if (role == Qt::DisplayRole) { return name; } } else if (column == 1) { if (role == Qt::DecorationRole) { return m_style->standardIcon(stdPix); } else if (role == Qt::DisplayRole) { return VariantHandler::displayString(m_style->standardIcon(stdPix)); } } return QVariant(); } #define MAKE_SP(stdPix) \ if (row == QStyle:: stdPix) \ return dataForStandardIcon(QStyle:: stdPix, QLatin1String(#stdPix), column, role) QVariant StandardIconModel::doData(int row, int column, int role) const { MAKE_SP(SP_TitleBarMenuButton); MAKE_SP(SP_TitleBarMinButton); MAKE_SP(SP_TitleBarMaxButton); MAKE_SP(SP_TitleBarCloseButton); MAKE_SP(SP_TitleBarNormalButton); MAKE_SP(SP_TitleBarShadeButton); MAKE_SP(SP_TitleBarUnshadeButton); MAKE_SP(SP_TitleBarContextHelpButton); MAKE_SP(SP_DockWidgetCloseButton); MAKE_SP(SP_MessageBoxInformation); MAKE_SP(SP_MessageBoxWarning); MAKE_SP(SP_MessageBoxCritical); MAKE_SP(SP_MessageBoxQuestion); MAKE_SP(SP_DesktopIcon); MAKE_SP(SP_TrashIcon); MAKE_SP(SP_ComputerIcon); MAKE_SP(SP_DriveFDIcon); MAKE_SP(SP_DriveHDIcon); MAKE_SP(SP_DriveCDIcon); MAKE_SP(SP_DriveDVDIcon); MAKE_SP(SP_DriveNetIcon); MAKE_SP(SP_DirOpenIcon); MAKE_SP(SP_DirClosedIcon); MAKE_SP(SP_DirLinkIcon); MAKE_SP(SP_FileIcon); MAKE_SP(SP_FileLinkIcon); MAKE_SP(SP_ToolBarHorizontalExtensionButton); MAKE_SP(SP_ToolBarVerticalExtensionButton); MAKE_SP(SP_FileDialogStart); MAKE_SP(SP_FileDialogEnd); MAKE_SP(SP_FileDialogToParent); MAKE_SP(SP_FileDialogNewFolder); MAKE_SP(SP_FileDialogDetailedView); MAKE_SP(SP_FileDialogInfoView); MAKE_SP(SP_FileDialogContentsView); MAKE_SP(SP_FileDialogListView); MAKE_SP(SP_FileDialogBack); MAKE_SP(SP_DirIcon); MAKE_SP(SP_DialogOkButton); MAKE_SP(SP_DialogCancelButton); MAKE_SP(SP_DialogHelpButton); MAKE_SP(SP_DialogOpenButton); MAKE_SP(SP_DialogSaveButton); MAKE_SP(SP_DialogCloseButton); MAKE_SP(SP_DialogApplyButton); MAKE_SP(SP_DialogResetButton); MAKE_SP(SP_DialogDiscardButton); MAKE_SP(SP_DialogYesButton); MAKE_SP(SP_DialogNoButton); MAKE_SP(SP_ArrowUp); MAKE_SP(SP_ArrowDown); MAKE_SP(SP_ArrowLeft); MAKE_SP(SP_ArrowRight); MAKE_SP(SP_ArrowBack); MAKE_SP(SP_ArrowForward); MAKE_SP(SP_DirHomeIcon); MAKE_SP(SP_CommandLink); MAKE_SP(SP_VistaShield); MAKE_SP(SP_BrowserReload); MAKE_SP(SP_BrowserStop); MAKE_SP(SP_MediaPlay); MAKE_SP(SP_MediaStop); MAKE_SP(SP_MediaPause); MAKE_SP(SP_MediaSkipForward); MAKE_SP(SP_MediaSkipBackward); MAKE_SP(SP_MediaSeekForward); MAKE_SP(SP_MediaSeekBackward); MAKE_SP(SP_MediaVolume); MAKE_SP(SP_MediaVolumeMuted); return QVariant(); } int StandardIconModel::doColumnCount() const { return 2; } int StandardIconModel::doRowCount() const { return QStyle::SP_MediaVolumeMuted + 1; } QVariant StandardIconModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Name"); case 1: return tr("Icon"); } } return QAbstractItemModel::headerData(section, orientation, role); } gammaray-2.3.0/plugins/styleinspector/standardiconmodel.h000066400000000000000000000040271255003167400237330ustar00rootroot00000000000000/* standardiconmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STANDARDICONMODEL_H #define GAMMARAY_STYLEINSPECTOR_STANDARDICONMODEL_H #include "abstractstyleelementmodel.h" #include namespace GammaRay { /** * Lists all standard icons of a style. */ class StandardIconModel : public AbstractStyleElementModel { Q_OBJECT public: explicit StandardIconModel(QObject *parent = 0); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: QVariant doData(int row, int column, int role) const Q_DECL_OVERRIDE; int doColumnCount() const Q_DECL_OVERRIDE; int doRowCount() const Q_DECL_OVERRIDE; private: QVariant dataForStandardIcon(QStyle::StandardPixmap stdPix, const QString &name, int column, int role) const; }; } #endif // GAMMARAY_STANDARDICONMODEL_H gammaray-2.3.0/plugins/styleinspector/styleelementproxymodel.cpp000066400000000000000000000032521255003167400254300ustar00rootroot00000000000000/* styleelementproxymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleelementproxymodel.h" using namespace GammaRay; StyleElementProxyModel::StyleModelProxy(QObject *parent) : QIdentityProxyModel(parent) , m_sizeHint(64, 64) { } void StyleElementProxyModel::setWidth(int width) { m_sizeHint.setWidth(width); } void StyleElementProxyModel::setHeight(int height) { m_sizeHint.setHeight(height); } QVariant StyleElementProxyModel::data(const QModelIndex &proxyIndex, int role) const { if (role == Qt::SizeHintRole) { return m_sizeHint; } return QAbstractProxyModel::data(proxyIndex, role); } gammaray-2.3.0/plugins/styleinspector/styleelementproxymodel.h000066400000000000000000000035501255003167400250760ustar00rootroot00000000000000/* styleelementproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEELEMENTPROXYMODEL_H #define GAMMARAY_STYLEINSPECTOR_STYLEELEMENTPROXYMODEL_H #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) #include typedef QSortFilterProxyModel QIdentityProxyModel; #else #include #endif #include namespace GammaRay { class StyleElementProxyModel : public QIdentityProxyModel { Q_OBJECT public: explicit StyleModelProxy(QObject *parent = 0); virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const; public slots: void setWidth(int width); void setHeight(int height); void setZoomFactor(int zoom); private: QSize m_sizeHint; }; } #endif // GAMMARAY_STYLEELEMENTPROXYMODEL_H gammaray-2.3.0/plugins/styleinspector/styleelementstatetablepage.cpp000066400000000000000000000062431255003167400262160ustar00rootroot00000000000000/* styleelementstatetablepage.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleelementstatetablepage.h" #include "ui_styleelementstatetablepage.h" #include "abstractstyleelementstatetable.h" #include "styleinspectorclient.h" #include static QObject* createStyleInspectorClient(const QString & /*name*/, QObject *parent) { return new GammaRay::StyleInspectorClient(parent); } using namespace GammaRay; StyleElementStateTablePage::StyleElementStateTablePage(QWidget *parent) : QWidget(parent) , ui(new Ui::StyleElementStateTablePage) , m_interface(0) { ObjectBroker::registerClientObjectFactoryCallback(createStyleInspectorClient); m_interface = ObjectBroker::object(); ui->setupUi(this); ui->tableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed); ui->tableView->verticalHeader()->setResizeMode(QHeaderView::Fixed); connect(ui->widthBox, SIGNAL(valueChanged(int)), m_interface, SLOT(setCellWidth(int))); connect(ui->widthBox, SIGNAL(valueChanged(int)), SLOT(updateCellSize())); connect(ui->heightBox, SIGNAL(valueChanged(int)), m_interface, SLOT(setCellHeight(int))); connect(ui->heightBox, SIGNAL(valueChanged(int)), SLOT(updateCellSize())); connect(ui->zoomSlider, SIGNAL(valueChanged(int)), m_interface, SLOT(setCellZoom(int))); connect(ui->zoomSlider, SIGNAL(valueChanged(int)), SLOT(updateCellSize())); updateCellSize(); } void StyleElementStateTablePage::showEvent(QShowEvent *show) { ui->widthBox->setValue(m_interface->cellWidth()); ui->heightBox->setValue(m_interface->cellHeight()); ui->zoomSlider->setValue(m_interface->cellZoom()); QWidget::showEvent(show); } StyleElementStateTablePage::~StyleElementStateTablePage() { delete ui; } void StyleElementStateTablePage::setModel(QAbstractItemModel *model) { ui->tableView->setModel(model); } void StyleElementStateTablePage::updateCellSize() { ui->tableView->verticalHeader()->setDefaultSectionSize(m_interface->cellSizeHint().height() + 4); ui->tableView->horizontalHeader()->setDefaultSectionSize(m_interface->cellSizeHint().width() + 4); } gammaray-2.3.0/plugins/styleinspector/styleelementstatetablepage.h000066400000000000000000000037171255003167400256660ustar00rootroot00000000000000/* styleelementstatetablepage.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEELEMENTSTATETABLEPAGE_H #define GAMMARAY_STYLEINSPECTOR_STYLEELEMENTSTATETABLEPAGE_H #include class QAbstractItemModel; namespace GammaRay { class StyleInspectorInterface; namespace Ui { class StyleElementStateTablePage; } /** * Tab page for showing a style element x state table and corresponding config UI. */ class StyleElementStateTablePage : public QWidget { Q_OBJECT public: explicit StyleElementStateTablePage(QWidget *parent = 0); ~StyleElementStateTablePage(); void setModel(QAbstractItemModel *model); protected: void showEvent(QShowEvent *show) Q_DECL_OVERRIDE; private slots: void updateCellSize(); private: Ui::StyleElementStateTablePage *ui; StyleInspectorInterface *m_interface; }; } #endif // GAMMARAY_STYLEELEMENTSTATETABLEPAGE_H gammaray-2.3.0/plugins/styleinspector/styleelementstatetablepage.ui000066400000000000000000000054761255003167400260600ustar00rootroot00000000000000 GammaRay::StyleElementStateTablePage 0 0 400 300 0 QAbstractItemView::NoSelection false Cell &Width: widthBox px 999 Cell &Height: heightBox px 999 &Zoom: zoomSlider 1 8 1 Qt::Horizontal Qt::Horizontal 40 20 gammaray-2.3.0/plugins/styleinspector/styleinspector.cpp000066400000000000000000000074561255003167400236740ustar00rootroot00000000000000/* styleinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleinspector.h" #include "complexcontrolmodel.h" #include "controlmodel.h" #include "pixelmetricmodel.h" #include "primitivemodel.h" #include "standardiconmodel.h" #include #include #include #include #include #include #include using namespace GammaRay; StyleInspector::StyleInspector(ProbeInterface *probe, QObject *parent) : StyleInspectorInterface(parent), m_primitiveModel(new PrimitiveModel(this)), m_controlModel(new ControlModel(this)), m_complexControlModel(new ComplexControlModel(this)), m_pixelMetricModel(new PixelMetricModel(this)), m_standardIconModel(new StandardIconModel(this)), m_standardPaletteModel(new PaletteModel(this)) { ObjectTypeFilterProxyModel *styleFilter = new ObjectTypeFilterProxyModel(this); styleFilter->setSourceModel(probe->objectListModel()); SingleColumnObjectProxyModel *singleColumnProxy = new SingleColumnObjectProxyModel(this); singleColumnProxy->setSourceModel(styleFilter); probe->registerModel("com.kdab.GammaRay.StyleList", singleColumnProxy); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(singleColumnProxy); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(styleSelected(QItemSelection))); probe->registerModel("com.kdab.GammaRay.StyleInspector.PrimitiveModel", m_primitiveModel); probe->registerModel("com.kdab.GammaRay.StyleInspector.ControlModel", m_controlModel); probe->registerModel("com.kdab.GammaRay.StyleInspector.ComplexControlModel", m_complexControlModel); probe->registerModel("com.kdab.GammaRay.StyleInspector.PixelMetricModel", m_pixelMetricModel); probe->registerModel("com.kdab.GammaRay.StyleInspector.StandardIconModel", m_standardIconModel); probe->registerModel("com.kdab.GammaRay.StyleInspector.PaletteModel", m_standardPaletteModel); } StyleInspector::~StyleInspector() { } void StyleInspector::styleSelected(const QItemSelection &selection) { if (selection.isEmpty()) return; const QModelIndex index = selection.first().topLeft(); QObject *obj = index.data(ObjectModel::ObjectRole).value(); QStyle *style = qobject_cast(obj); m_primitiveModel->setStyle(style); m_controlModel->setStyle(style); m_complexControlModel->setStyle(style); m_pixelMetricModel->setStyle(style); m_standardIconModel->setStyle(style); m_standardPaletteModel->setPalette(style ? style->standardPalette() : qApp->palette()); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(StyleInspectorFactory) #endif gammaray-2.3.0/plugins/styleinspector/styleinspector.h000066400000000000000000000047701255003167400233350ustar00rootroot00000000000000/* styleinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEINSPECTOR_H #define GAMMARAY_STYLEINSPECTOR_STYLEINSPECTOR_H #include #include "styleinspectorinterface.h" #include #include class QItemSelection; namespace GammaRay { class ComplexControlModel; class ControlModel; class PaletteModel; class PixelMetricModel; class PrimitiveModel; class StandardIconModel; class StyleInspector : public StyleInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::StyleInspectorInterface) public: explicit StyleInspector(ProbeInterface *probe, QObject *parent = 0); virtual ~StyleInspector(); private slots: void styleSelected(const QItemSelection &selection); private: PrimitiveModel *m_primitiveModel; ControlModel *m_controlModel; ComplexControlModel *m_complexControlModel; PixelMetricModel *m_pixelMetricModel; StandardIconModel *m_standardIconModel; PaletteModel *m_standardPaletteModel; }; class StyleInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_styleinspector.json") public: explicit StyleInspectorFactory(QObject *parent = 0) : QObject(parent) { } virtual QString name() const { return tr("Style"); } }; } #endif // GAMMARAY_STYLEINSPECTOR_H gammaray-2.3.0/plugins/styleinspector/styleinspectorclient.cpp000066400000000000000000000041211255003167400250550ustar00rootroot00000000000000/* styleinspectorclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleinspectorclient.h" #include using namespace GammaRay; StyleInspectorClient::StyleInspectorClient(QObject *parent) : StyleInspectorInterface(parent) { // make sure the remote server side uses our initial values setCellHeight(cellHeight()); setCellWidth(cellWidth()); setCellZoom(cellZoom()); } StyleInspectorClient::~StyleInspectorClient() { } void StyleInspectorClient::setCellHeight(int height) { StyleInspectorInterface::setCellHeight(height); Endpoint::instance()->invokeObject(objectName(), "setCellHeight", QVariantList() << height); } void StyleInspectorClient::setCellWidth(int width) { StyleInspectorInterface::setCellWidth(width); Endpoint::instance()->invokeObject(objectName(), "setCellWidth", QVariantList() << width); } void StyleInspectorClient::setCellZoom(int zoom) { StyleInspectorInterface::setCellZoom(zoom); Endpoint::instance()->invokeObject(objectName(), "setCellZoom", QVariantList() << zoom); } gammaray-2.3.0/plugins/styleinspector/styleinspectorclient.h000066400000000000000000000033051255003167400245250ustar00rootroot00000000000000/* styleinspectorclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORCLIENT_H #define GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORCLIENT_H #include "styleinspectorinterface.h" namespace GammaRay { class StyleInspectorClient : public StyleInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::StyleInspectorInterface) public: explicit StyleInspectorClient(QObject *parent = 0); ~StyleInspectorClient(); void setCellHeight(int height) Q_DECL_OVERRIDE; void setCellWidth(int width) Q_DECL_OVERRIDE; void setCellZoom(int zoom) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_STYLEINSPECTORCLIENT_H gammaray-2.3.0/plugins/styleinspector/styleinspectorinterface.cpp000066400000000000000000000042371255003167400255470ustar00rootroot00000000000000/* styleinspectorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleinspectorinterface.h" #include #include using namespace GammaRay; StyleInspectorInterface::StyleInspectorInterface(QObject *parent) : QObject(parent) , m_cellHeight(64) , m_cellWidth(64) , m_cellZoom(1) { ObjectBroker::registerObject(this); } StyleInspectorInterface::~StyleInspectorInterface() { } int StyleInspectorInterface::cellHeight() const { return m_cellHeight; } int StyleInspectorInterface::cellWidth() const { return m_cellWidth; } int StyleInspectorInterface::cellZoom() const { return m_cellZoom; } QSize StyleInspectorInterface::cellSizeHint() const { return QSize(m_cellWidth * m_cellZoom, m_cellHeight * m_cellZoom); } void StyleInspectorInterface::setCellHeight(int height) { m_cellHeight = height; emit cellSizeChanged(); } void StyleInspectorInterface::setCellWidth(int width) { m_cellWidth = width; emit cellSizeChanged(); } void StyleInspectorInterface::setCellZoom(int zoom) { m_cellZoom = zoom; emit cellSizeChanged(); } gammaray-2.3.0/plugins/styleinspector/styleinspectorinterface.h000066400000000000000000000037361255003167400252170ustar00rootroot00000000000000/* styleinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORINTERFACE_H #define GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORINTERFACE_H #include class QSize; namespace GammaRay { class StyleInspectorInterface : public QObject { Q_OBJECT public: explicit StyleInspectorInterface(QObject *parent = 0); virtual ~StyleInspectorInterface(); int cellHeight() const; int cellWidth() const; int cellZoom() const; QSize cellSizeHint() const; signals: void cellSizeChanged(); public slots: virtual void setCellHeight(int height); virtual void setCellWidth(int width); virtual void setCellZoom(int zoom); private: int m_cellHeight; int m_cellWidth; int m_cellZoom; }; } Q_DECLARE_INTERFACE(GammaRay::StyleInspectorInterface, "com.kdab.GammaRay.StyleInspectorInterface") #endif // GAMMARAY_STYLEINSPECTORINTERFACE_H gammaray-2.3.0/plugins/styleinspector/styleinspectorwidget.cpp000066400000000000000000000057071255003167400250750ustar00rootroot00000000000000/* styleinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleinspectorwidget.h" #include "ui_styleinspectorwidget.h" #include using namespace GammaRay; StyleInspectorWidget::StyleInspectorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::StyleInspectorWidget) { ui->setupUi(this); ui->styleSelector->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleList")); connect(ui->styleSelector, SIGNAL(currentIndexChanged(int)), SLOT(styleSelected(int))); ui->primitivePage->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.PrimitiveModel")); ui->controlPage->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.ControlModel")); ui->complexControlPage->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.ComplexControlModel")); ui->pixelMetricView->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.PixelMetricModel")); ui->pixelMetricView->header()->setResizeMode(QHeaderView::ResizeToContents); ui->standardIconView->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.StandardIconModel")); ui->standardIconView->header()->setResizeMode(QHeaderView::ResizeToContents); ui->standardPaletteView->setModel(ObjectBroker::model("com.kdab.GammaRay.StyleInspector.PaletteModel")); ui->standardIconView->header()->setResizeMode(QHeaderView::ResizeToContents); // TODO this will fail due to lazy model population if (ui->styleSelector->count()) { styleSelected(0); } } StyleInspectorWidget::~StyleInspectorWidget() { delete ui; } void StyleInspectorWidget::styleSelected(int index) { QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(ui->styleSelector->model()); selectionModel->select(ui->styleSelector->model()->index(index, 0), QItemSelectionModel::ClearAndSelect); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(StyleInspectorUiFactory) #endif gammaray-2.3.0/plugins/styleinspector/styleinspectorwidget.h000066400000000000000000000036201255003167400245320ustar00rootroot00000000000000/* styleinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORWIDGET_H #define GAMMARAY_STYLEINSPECTOR_STYLEINSPECTORWIDGET_H #include #include namespace GammaRay { namespace Ui { class StyleInspectorWidget; } class StyleInspectorWidget : public QWidget { Q_OBJECT public: explicit StyleInspectorWidget(QWidget *parent = 0); virtual ~StyleInspectorWidget(); private slots: void styleSelected(int index); private: Ui::StyleInspectorWidget *ui; }; class StyleInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_styleinspector.json") }; } #endif // GAMMARAY_STYLEINSPECTORWIDGET_H gammaray-2.3.0/plugins/styleinspector/styleinspectorwidget.ui000066400000000000000000000077151255003167400247310ustar00rootroot00000000000000 GammaRay::StyleInspectorWidget 0 0 400 300 0 0 &Style: styleSelector 0 Primitives Controls Complex Controls Pixel Metric false true Standard Icons false true Standard Palette false true GammaRay::StyleElementStateTablePage QWidget
styleelementstatetablepage.h
1
gammaray-2.3.0/plugins/styleinspector/styleoption.cpp000066400000000000000000000135731255003167400231730ustar00rootroot00000000000000/* styleoption.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "styleoption.h" #include using namespace GammaRay; struct style_state_t { const char *name; QStyle::State state; }; #define MAKE_STATE( state ) { #state, QStyle:: state } static const style_state_t styleStates[] = { MAKE_STATE(State_None), MAKE_STATE(State_Enabled), MAKE_STATE(State_Raised), MAKE_STATE(State_Sunken), MAKE_STATE(State_Off), MAKE_STATE(State_NoChange), MAKE_STATE(State_On), MAKE_STATE(State_DownArrow), MAKE_STATE(State_Horizontal), MAKE_STATE(State_HasFocus), MAKE_STATE(State_Top), MAKE_STATE(State_Bottom), MAKE_STATE(State_FocusAtBorder), MAKE_STATE(State_AutoRaise), MAKE_STATE(State_MouseOver), MAKE_STATE(State_UpArrow), MAKE_STATE(State_Selected), MAKE_STATE(State_Active), MAKE_STATE(State_Window), MAKE_STATE(State_Open), MAKE_STATE(State_Children), MAKE_STATE(State_Item), MAKE_STATE(State_Sibling), MAKE_STATE(State_Editing), MAKE_STATE(State_KeyboardFocusChange), MAKE_STATE(State_ReadOnly), MAKE_STATE(State_Small), MAKE_STATE(State_Mini) }; int StyleOption::stateCount() { return sizeof(styleStates) / sizeof(style_state_t); } QString StyleOption::stateDisplayName(int index) { return QString::fromLatin1(styleStates[index].name).mid(6); // remove the State_ prefix } QStyle::State StyleOption::prettyState(int index) { QStyle::State s = styleStates[index].state; if (s == QStyle::State_None) { return s; } return s | QStyle::State_Enabled; // enable by default, else we usually see disabled stuff only } QStyleOption *StyleOption::makeStyleOption() { return new QStyleOption; } QStyleOption *StyleOption::makeStyleOptionComplex() { return new QStyleOptionComplex; } QStyleOption *StyleOption::makeButtonStyleOption() { QStyleOptionButton *opt = new QStyleOptionButton; opt->features = QStyleOptionButton::None; opt->text = QLatin1String("Label"); return opt; } QStyleOption *StyleOption::makeComboBoxStyleOption() { QStyleOptionComboBox *opt = new QStyleOptionComboBox; opt->frame = true; opt->currentText = QLatin1String("Current Text"); return opt; } QStyleOption *StyleOption::makeFrameStyleOption() { QStyleOptionFrameV3 *opt = new QStyleOptionFrameV3; opt->lineWidth = 1; opt->midLineWidth = 0; opt->frameShape = QFrame::StyledPanel; return opt; } QStyleOption *StyleOption::makeGroupBoxStyleOption() { QStyleOptionGroupBox *opt = new QStyleOptionGroupBox; opt->lineWidth = 1; opt->midLineWidth = 0; opt->text = QLatin1String("Label"); return opt; } QStyleOption *StyleOption::makeHeaderStyleOption() { QStyleOptionHeader *opt = new QStyleOptionHeader; opt->orientation = Qt::Horizontal; opt->text = QLatin1String("Label"); return opt; } QStyleOption *StyleOption::makeItemViewStyleOption() { QStyleOptionViewItemV4 *opt = new QStyleOptionViewItemV4; opt->text = QLatin1String("Text"); opt->features = QStyleOptionViewItemV2::HasDisplay; return opt; } QStyleOption *StyleOption::makeMenuStyleOption() { QStyleOptionMenuItem *opt = new QStyleOptionMenuItem; opt->text = QLatin1String("Label"); return opt; } QStyleOption *StyleOption::makeProgressBarStyleOption() { QStyleOptionProgressBarV2 *opt = new QStyleOptionProgressBarV2; opt->minimum = 0; opt->maximum = 100; opt->progress = 42; return opt; } QStyleOption *StyleOption::makeSliderStyleOption() { QStyleOptionSlider *opt = new QStyleOptionSlider; opt->minimum = 0; opt->maximum = 100; opt->sliderValue = 42; opt->tickInterval = 5; return opt; } QStyleOption *StyleOption::makeSpinBoxStyleOption() { QStyleOptionSpinBox *opt = new QStyleOptionSpinBox; opt->frame = true; return opt; } QStyleOption *StyleOption::makeTabStyleOption() { QStyleOptionTabV3 *opt = new QStyleOptionTabV3; opt->text = QLatin1String("Label"); return opt; } QStyleOption *StyleOption::makeTabBarBaseStyleOption() { return new QStyleOptionTabBarBaseV2; } QStyleOption *StyleOption::makeTabWidgetFrameStyleOption() { QStyleOptionTabWidgetFrameV2 *opt = new QStyleOptionTabWidgetFrameV2; opt->lineWidth = 1; return opt; } QStyleOption *StyleOption::makeTitleBarStyleOption() { QStyleOptionTitleBar *opt = new QStyleOptionTitleBar; opt->text = QLatin1String("Title"); opt->titleBarFlags = Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; return opt; } QStyleOption *StyleOption::makeToolBoxStyleOption() { QStyleOptionToolBoxV2 *opt = new QStyleOptionToolBoxV2; opt->text = QLatin1String("Label"); return opt; } QStyleOption * StyleOption::makeToolButtonStyleOption() { QStyleOptionToolButton *opt = new QStyleOptionToolButton; opt->text = QLatin1String("Label"); opt->toolButtonStyle = Qt::ToolButtonFollowStyle; return opt; } gammaray-2.3.0/plugins/styleinspector/styleoption.h000066400000000000000000000043671255003167400226410ustar00rootroot00000000000000/* styleoption.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STYLEINSPECTOR_STYLEOPTION_H #define GAMMARAY_STYLEINSPECTOR_STYLEOPTION_H #include class QStyleOption; class QString; namespace GammaRay { /** * Various helper methods for dealing with QStyleOption. */ namespace StyleOption { int stateCount(); QString stateDisplayName(int index); QStyle::State prettyState(int index); QStyleOption *makeStyleOption(); QStyleOption *makeStyleOptionComplex(); QStyleOption *makeButtonStyleOption(); QStyleOption *makeComboBoxStyleOption(); QStyleOption *makeFrameStyleOption(); QStyleOption *makeGroupBoxStyleOption(); QStyleOption *makeHeaderStyleOption(); QStyleOption *makeItemViewStyleOption(); QStyleOption *makeMenuStyleOption(); QStyleOption *makeProgressBarStyleOption(); QStyleOption *makeSliderStyleOption(); QStyleOption *makeSpinBoxStyleOption(); QStyleOption *makeTabStyleOption(); QStyleOption *makeTabBarBaseStyleOption(); QStyleOption *makeTabWidgetFrameStyleOption(); QStyleOption *makeTitleBarStyleOption(); QStyleOption *makeToolBoxStyleOption(); QStyleOption *makeToolButtonStyleOption(); } } #endif // GAMMARAY_STYLEOPTION_H gammaray-2.3.0/plugins/timertop/000077500000000000000000000000001255003167400166415ustar00rootroot00000000000000gammaray-2.3.0/plugins/timertop/CMakeLists.txt000066400000000000000000000016501255003167400214030ustar00rootroot00000000000000# probe part if(BUILD_TIMER_PLUGIN) set(gammaray_timertop_plugin_srcs timertop.cpp timermodel.cpp timerinfo.cpp functioncalltimer.cpp ) gammaray_add_plugin(gammaray_timertop_plugin gammaray_timertop.desktop ${gammaray_timertop_plugin_srcs} ) target_link_libraries(gammaray_timertop_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) if (LINUX) target_link_libraries(pthread) endif() if(NOT WIN32 AND NOT APPLE) target_link_libraries(gammaray_timertop_plugin rt) endif() endif() # ui part if(GAMMARAY_BUILD_UI) set(gammaray_timertop_plugin_ui_srcs timertopwidget.cpp ) qt4_wrap_ui(gammaray_timertop_plugin_ui_srcs timertopwidget.ui ) gammaray_add_plugin(gammaray_timertop_ui_plugin gammaray_timertop_ui.desktop ${gammaray_timertop_plugin_ui_srcs} ) target_link_libraries(gammaray_timertop_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_ui ) endif() gammaray-2.3.0/plugins/timertop/functioncalltimer.cpp000066400000000000000000000052651255003167400230770ustar00rootroot00000000000000/* functioncalltimer.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "functioncalltimer.h" #ifdef Q_OS_WIN #include #endif #if defined(Q_OS_MAC) && defined(__MACH__) #include #include #endif using namespace GammaRay; #ifndef Q_OS_WIN static void portableGetTimeUnix(timespec &t) { #if defined(Q_OS_MAC) clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); t.tv_sec = mts.tv_sec; t.tv_nsec = mts.tv_nsec; #else clock_gettime(CLOCK_REALTIME, &t); #endif } #endif FunctionCallTimer::FunctionCallTimer() : m_startTime() , m_active(false) { } bool FunctionCallTimer::start() { if (m_active) { return false; } #if defined(Q_OS_WIN) LARGE_INTEGER startTime; bool ret = QueryPerformanceCounter(&startTime); if (!ret) { return false; } m_startTime = startTime.QuadPart; #else portableGetTimeUnix(m_startTime); #endif m_active = true; return true; } bool FunctionCallTimer::active() const { return m_active; } int FunctionCallTimer::stop() { Q_ASSERT(m_active); m_active = false; #if defined(Q_OS_WIN) LARGE_INTEGER endTime; LARGE_INTEGER frequency; QueryPerformanceCounter(&endTime); QueryPerformanceFrequency(&frequency); int elapsed = ((endTime.QuadPart - m_startTime) * 1000000) / frequency.QuadPart; #else timespec endTime; portableGetTimeUnix(endTime); int elapsed = (endTime.tv_nsec - m_startTime.tv_nsec) / 1000; elapsed += (endTime.tv_sec - m_startTime.tv_sec) * 1000000; #endif return elapsed; } gammaray-2.3.0/plugins/timertop/functioncalltimer.h000066400000000000000000000030471255003167400225400ustar00rootroot00000000000000/* functioncalltimer.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TIMERTOP_FUNCTIONCALLTIMER_H #define GAMMARAY_TIMERTOP_FUNCTIONCALLTIMER_H #include #include namespace GammaRay { class FunctionCallTimer { public: FunctionCallTimer(); bool start(); bool active() const; int stop(); private: #ifndef Q_OS_WIN timespec m_startTime; #else qint64 m_startTime; #endif bool m_active; }; } #endif // GAMMARAY_FUNCTIONCALLTIMER_H gammaray-2.3.0/plugins/timertop/gammaray_timertop.desktop000066400000000000000000000002421255003167400237530ustar00rootroot00000000000000[Desktop Entry] Name=Timers X-GammaRay-Types="QTimer;QQmlTimer;QUnifiedTimer" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_timertop_plugin gammaray-2.3.0/plugins/timertop/gammaray_timertop.json000066400000000000000000000001611255003167400232530ustar00rootroot00000000000000{ "id": "gammaray_timertop", "name": "Timers", "types": [ "QTimer", "QQmlTimer", "QUnifiedTimer" ] } gammaray-2.3.0/plugins/timertop/gammaray_timertop_ui.desktop000066400000000000000000000002111255003167400244440ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_timertop X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_timertop_ui_plugin gammaray-2.3.0/plugins/timertop/timerinfo.cpp000066400000000000000000000125401255003167400213430ustar00rootroot00000000000000/* timerinfo.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "timerinfo.h" #include #include using namespace GammaRay; static const int maxTimeoutEvents = 1000; static const int maxTimeSpan = 10000; TimerInfo::TimerInfo(QObject* timer) : m_type(QQmlTimerType), m_totalWakeups(0), m_timer(timer), m_timerId(-1), m_lastReceiver(0) { if (QTimer *t = qobject_cast(timer)) { m_type = QTimerType; m_timerId = t->timerId(); } } TimerInfo::TimerInfo(int timerId) : m_type(QObjectType), m_totalWakeups(0), m_timerId(timerId) { } TimerInfo::Type TimerInfo::type() const { return m_type; } void TimerInfo::addEvent(const TimeoutEvent &timeoutEvent) { m_timeoutEvents.append(timeoutEvent); removeOldEvents(); m_totalWakeups++; } int TimerInfo::numEvents() const { return m_timeoutEvents.size(); } QObject* TimerInfo::timerObject() const { return m_timer; } QTimer *TimerInfo::timer() const { if (m_type != QTimerType) return 0; return qobject_cast(m_timer); } int TimerInfo::timerId() const { return m_timerId; } FunctionCallTimer *TimerInfo::functionCallTimer() { return &m_functionCallTimer; } QString TimerInfo::wakeupsPerSec() const { int totalWakeups = 0; int start = 0; int end = m_timeoutEvents.size() - 1; for (int i = end; i >= 0; i--) { const TimeoutEvent &event = m_timeoutEvents.at(i); if (event.timeStamp.msecsTo(QTime::currentTime()) > maxTimeSpan) { start = i; break; } totalWakeups++; } if (totalWakeups > 0 && end > start) { const QTime startTime = m_timeoutEvents[start].timeStamp; const QTime endTime = m_timeoutEvents[end].timeStamp; const int timeSpan = startTime.msecsTo(endTime); const float wakeupsPerSec = totalWakeups / (float)timeSpan * 1000.0f; return QString::number(wakeupsPerSec, 'f', 1); } return "0"; } QString TimerInfo::timePerWakeup() const { if (m_type == QObjectType) { return "N/A"; } int totalWakeups = 0; int totalTime = 0; for (int i = m_timeoutEvents.size() - 1; i >= 0; i--) { const TimeoutEvent &event = m_timeoutEvents.at(i); if (event.timeStamp.msecsTo(QTime::currentTime()) > maxTimeSpan) { break; } totalWakeups++; totalTime += event.executionTime; } if (totalWakeups > 0) { return QString::number(totalTime / (float)totalWakeups, 'f', 1); } return "N/A"; } QString TimerInfo::maxWakeupTime() const { if (m_type == QObjectType) { return "N/A"; } int max = 0; for (int i = 0; i < m_timeoutEvents.size(); i++) { const TimeoutEvent &event = m_timeoutEvents.at(i); if (event.executionTime > max) { max = event.executionTime; } } return QString::number(max); } int TimerInfo::totalWakeups() const { return m_totalWakeups; } QString TimerInfo::state() const { switch (type()) { case QTimerType: { const QTimer *t = timer(); if (!t) return QObject::tr("None"); if (!t->isActive()) return QObject::tr("Inactive"); if (t->isSingleShot()) return QObject::tr("Singleshot (%1 ms)").arg(t->interval()); return QObject::tr("Repeating (%1 ms)").arg(t->interval()); } case QQmlTimerType: { const QObject *obj = timerObject(); if (!obj) return QObject::tr("None"); const int interval = obj->property("interval").toInt(); if (!obj->property("running").toBool()) return QObject::tr("Inactive (%1 ms)").arg(interval); if (obj->property("repeat").toBool()) return QObject::tr("Repeating (%1 ms)").arg(interval); return QObject::tr("Singleshot (%1 ms)").arg(interval); } case QObjectType: return "N/A"; } Q_ASSERT(false); return QString(); } void TimerInfo::removeOldEvents() { if (m_timeoutEvents.size() > maxTimeoutEvents) { m_timeoutEvents.removeFirst(); } } void TimerInfo::setLastReceiver(QObject *receiver) { m_lastReceiver = receiver; } QString TimerInfo::displayName() const { switch (m_type) { case QTimerType: case QQmlTimerType: return Util::displayString(timerObject()); case QObjectType: if (m_lastReceiver) { return Util::displayString(m_lastReceiver); } else { return QObject::tr("Unknown QObject"); } } Q_ASSERT(false); return QString(); } gammaray-2.3.0/plugins/timertop/timerinfo.h000066400000000000000000000050731255003167400210130ustar00rootroot00000000000000/* timerinfo.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TIMERTOP_TIMERINFO_H #define GAMMARAY_TIMERTOP_TIMERINFO_H #include "functioncalltimer.h" #include #include #include #include #include namespace GammaRay { class TimerInfo { public: enum Type { QTimerType, QObjectType, QQmlTimerType }; struct TimeoutEvent { QTime timeStamp; int executionTime; }; explicit TimerInfo(QObject *timer); explicit TimerInfo(int timerId); Type type() const; void addEvent(const TimeoutEvent &timeoutEvent); void setLastReceiver(QObject *receiver); int numEvents() const; QTimer *timer() const; QObject *timerObject() const; int timerId() const; FunctionCallTimer *functionCallTimer(); QString wakeupsPerSec() const; QString timePerWakeup() const; QString maxWakeupTime() const; int totalWakeups() const; QString state() const; QString displayName() const; private: Type m_type; int m_totalWakeups; // Only for QTimer/QQmlTimers timers QPointer m_timer; int m_timerId; FunctionCallTimer m_functionCallTimer; QList m_timeoutEvents; // Only for free timers, QObject that received the timeout event QPointer m_lastReceiver; void removeOldEvents(); }; typedef QSharedPointer TimerInfoPtr; } Q_DECLARE_METATYPE(GammaRay::TimerInfoPtr) #endif // GAMMARAY_TIMERINFO_H gammaray-2.3.0/plugins/timertop/timermodel.cpp000066400000000000000000000326731255003167400215210ustar00rootroot00000000000000/* timermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "timermodel.h" #include #include #include #include #include #include #include #include static const char timerInfoPropertyName[] = "GammaRay TimerInfo"; using namespace GammaRay; using namespace std; static TimerModel *s_timerModel = 0; static bool processCallback() { ///TODO: multi-threading support if (!TimerModel::isInitialized() || QThread::currentThread() != qApp->thread()) { return false; } return true; } static void signal_begin_callback(QObject *caller, int method_index, void **argv) { Q_UNUSED(argv); if (!processCallback()) { return; } ///TODO: support threads living in other threads if (caller->thread() != qApp->thread()) { return; } TimerModel::instance()->preSignalActivate(caller, method_index); } static void signal_end_callback(QObject *caller, int method_index) { // NOTE: here and below the caller may be invalid, e.g. if it was deleted from a slot if (!processCallback()) { return; } TimerModel::instance()->postSignalActivate(caller, method_index); } TimerModel::TimerModel(QObject *parent) : QAbstractTableModel(parent), m_sourceModel(0), m_probe(0), m_pendingChanedRowsTimer(new QTimer(this)), m_timeoutIndex(QTimer::staticMetaObject.indexOfSignal("timeout()")), m_qmlTimerTriggeredIndex(-1) { m_pendingChanedRowsTimer->setInterval(5000); m_pendingChanedRowsTimer->setSingleShot(true); connect(m_pendingChanedRowsTimer, SIGNAL(timeout()), this, SLOT(flushEmitPendingChangedRows())); } TimerModel::~TimerModel() { s_timerModel = 0; } bool TimerModel::isInitialized() { return s_timerModel != 0; } TimerModel *TimerModel::instance() { if (!s_timerModel) { s_timerModel = new TimerModel; } Q_ASSERT(s_timerModel); return s_timerModel; } TimerInfoPtr TimerModel::findOrCreateFreeTimerInfo(int timerId) { // First, return the timer info if it already exists foreach (const TimerInfoPtr &freeTimer, m_freeTimers) { if (freeTimer->timerId() == timerId) { return freeTimer; } } // Create a new free timer, and emit the correct update signals TimerInfoPtr timerInfo(new TimerInfo(timerId)); beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_freeTimers.append(timerInfo); endInsertRows(); return timerInfo; } TimerInfoPtr TimerModel::findOrCreateQTimerTimerInfo(QObject *timer) { if (!timer) { return TimerInfoPtr(); } QVariant timerInfoVariant = timer->property(timerInfoPropertyName); if (!timerInfoVariant.isValid()) { const TimerInfoPtr info = TimerInfoPtr(new TimerInfo(timer)); if (m_qmlTimerTriggeredIndex < 0 && info->type() == TimerInfo::QQmlTimerType) { m_qmlTimerTriggeredIndex = timer->metaObject()->indexOfMethod("triggered()"); } timerInfoVariant.setValue(info); if (timer->thread() == QThread::currentThread()) // ### FIXME: we shouldn't use setProperty() in the first place... timer->setProperty(timerInfoPropertyName, timerInfoVariant); } const TimerInfoPtr timerInfo = timerInfoVariant.value(); Q_ASSERT(timerInfo->timerObject() == timer); return timerInfo; } TimerInfoPtr TimerModel::findOrCreateQTimerTimerInfo(int timerId) { for (int row = 0; row < m_sourceModel->rowCount(); row++) { const QModelIndex sourceIndex = m_sourceModel->index(row, 0); QObject *const timerObject = sourceIndex.data(ObjectModel::ObjectRole).value(); QTimer * const timer = qobject_cast(timerObject); if (timer && timer->timerId() == timerId) { return findOrCreateQTimerTimerInfo(timer); } } return TimerInfoPtr(); } TimerInfoPtr TimerModel::findOrCreateTimerInfo(const QModelIndex &index) { if (index.row() < m_sourceModel->rowCount()){ const QModelIndex sourceIndex = m_sourceModel->index(index.row(), 0); QObject *const timerObject = sourceIndex.data(ObjectModel::ObjectRole).value(); return findOrCreateQTimerTimerInfo(timerObject); } else { const int freeListIndex = index.row() - m_sourceModel->rowCount(); Q_ASSERT(freeListIndex >= 0); if (freeListIndex < m_freeTimers.size()) { return m_freeTimers.at(freeListIndex); } } return TimerInfoPtr(); } int TimerModel::rowFor(QObject *timer) { for (int i = 0; i < rowCount(); i++) { const TimerInfoPtr timerInfo = findOrCreateTimerInfo(index(i, 0)); if (timerInfo && timerInfo->timerObject() == timer) { return i; } } return -1; } void TimerModel::preSignalActivate(QObject *caller, int methodIndex) { if (!(methodIndex == m_timeoutIndex && qobject_cast(caller)) && !(methodIndex == m_qmlTimerTriggeredIndex && caller->inherits("QQmlTimer"))) { return; } const TimerInfoPtr timerInfo = findOrCreateQTimerTimerInfo(caller); if (!timerInfo) { // Ok, likely a GammaRay timer //cout << "TimerModel::preSignalActivate(): Unable to find timer " // << (void*)timer << " (" << timer->objectName().toStdString() << ")!" << endl; return; } if (!timerInfo->functionCallTimer()->start()) { cout << "TimerModel::preSignalActivate(): Recursive timeout for timer " << (void*)caller << " (" << caller->objectName().toStdString() << ")!" << endl; return; } Q_ASSERT(!m_currentSignals.contains(caller)); m_currentSignals[caller] = timerInfo; } void TimerModel::postSignalActivate(QObject *caller, int methodIndex) { QHash::iterator it = m_currentSignals.find(caller); if (it == m_currentSignals.end()) { // Ok, likely a GammaRay timer // cout << "TimerModel::postSignalActivate(): Unable to find timer " // << (void*)caller << " (" << caller->objectName().toStdString() << ")!" << endl; return; } const TimerInfoPtr timerInfo = *it; Q_ASSERT(timerInfo); if (!(timerInfo->type() == TimerInfo::QTimerType && methodIndex == m_timeoutIndex) && !(timerInfo->type() == TimerInfo::QQmlTimerType && methodIndex == m_qmlTimerTriggeredIndex)) { return; } m_currentSignals.erase(it); if (!timerInfo->timerObject()) { // timer got killed in a slot return; } Q_ASSERT(caller == timerInfo->timerObject()); if (!timerInfo->functionCallTimer()->active()) { cout << "TimerModel::postSignalActivate(): Timer not active: " << (void*)caller << " (" << caller->objectName().toStdString() << ")!" << endl; return; } TimerInfo::TimeoutEvent event; event.timeStamp = QTime::currentTime(); event.executionTime = timerInfo->functionCallTimer()->stop(); timerInfo->addEvent(event); const int row = rowFor(timerInfo->timerObject()); emitTimerObjectChanged(row); } void TimerModel::setProbe(ProbeInterface *probe) { m_probe = probe; SignalSpyCallbackSet callbacks; callbacks.signalBeginCallback = signal_begin_callback; callbacks.signalEndCallback = signal_end_callback; probe->registerSignalSpyCallbackSet(callbacks); } void TimerModel::setSourceModel(QAbstractItemModel *sourceModel) { Q_ASSERT(!m_sourceModel); m_sourceModel = sourceModel; qApp->installEventFilter(this); connect(m_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(slotBeginInsertRows(QModelIndex,int,int))); connect(m_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(slotEndInsertRows())); connect(m_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(slotBeginRemoveRows(QModelIndex,int,int))); connect(m_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotEndRemoveRows())); connect(m_sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(slotBeginReset())); connect(m_sourceModel, SIGNAL(modelReset()), this, SLOT(slotEndReset())); connect(m_sourceModel, SIGNAL(layoutAboutToBeChanged()), this, SLOT(slotBeginReset())); connect(m_sourceModel, SIGNAL(layoutChanged()), this, SLOT(slotEndReset())); reset(); } int TimerModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return LastRole - FirstRole - 1; } int TimerModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); if (!m_sourceModel || parent.isValid()) { return 0; } return m_sourceModel->rowCount() + m_freeTimers.count(); } QVariant TimerModel::data(const QModelIndex &index, int role) const { if (!m_sourceModel) { return QVariant(); } if (role == Qt::DisplayRole && index.isValid() && index.column() >= 0 && index.column() < columnCount()) { const TimerInfoPtr timerInfo = const_cast(this)->findOrCreateTimerInfo(index); switch ((Roles)(index.column() + FirstRole + 1)) { case ObjectNameRole: return timerInfo->displayName(); case StateRole: return timerInfo->state(); case TotalWakeupsRole: return timerInfo->totalWakeups(); case WakeupsPerSecRole: return timerInfo->wakeupsPerSec(); case TimePerWakeupRole: return timerInfo->timePerWakeup(); case MaxTimePerWakeupRole: return timerInfo->maxWakeupTime(); case TimerIdRole: return timerInfo->timerId(); case FirstRole: case LastRole: break; } } return QVariant(); } QVariant TimerModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch ((Roles)(section + FirstRole + 1)) { case ObjectNameRole: return tr("Object Name"); case StateRole: return tr("State"); case TotalWakeupsRole: return tr("Total Wakeups"); case WakeupsPerSecRole: return tr("Wakeups/Sec"); case TimePerWakeupRole: return tr("Time/Wakeup [uSecs]"); case MaxTimePerWakeupRole: return tr("Max Wakeup Time [uSecs]"); case TimerIdRole: return tr("Timer ID"); case FirstRole: case LastRole: break; } } return QAbstractTableModel::headerData(section, orientation, role); } bool TimerModel::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::Timer) { QTimerEvent * const timerEvent = static_cast(event); // If there is a QTimer associated with this timer ID, don't handle it here, it will be handled // by the signal hooks for QTimer::timeout() if (findOrCreateQTimerTimerInfo(timerEvent->timerId())) { return false; } // check if object is owned by GammaRay itself if (m_probe && m_probe->filterObject(watched)) { return false; } const TimerInfoPtr timerInfo = findOrCreateFreeTimerInfo(timerEvent->timerId()); TimerInfo::TimeoutEvent timeoutEvent; timeoutEvent.timeStamp = QTime::currentTime(); timeoutEvent.executionTime = -1; timerInfo->addEvent(timeoutEvent); timerInfo->setLastReceiver(watched); emitFreeTimerChanged(m_freeTimers.indexOf(timerInfo)); } return false; } void TimerModel::slotBeginRemoveRows(const QModelIndex &parent, int start, int end) { Q_UNUSED(parent); flushEmitPendingChangedRows(); beginRemoveRows(QModelIndex(), start, end); } void TimerModel::slotEndRemoveRows() { endRemoveRows(); } void TimerModel::slotBeginInsertRows(const QModelIndex &parent, int start, int end) { Q_UNUSED(parent); flushEmitPendingChangedRows(); beginInsertRows(QModelIndex(), start, end); } void TimerModel::slotEndInsertRows() { endInsertRows(); } void TimerModel::slotBeginReset() { m_pendingChangedTimerObjects.clear(); m_pendingChangedFreeTimers.clear(); beginResetModel(); } void TimerModel::slotEndReset() { endResetModel(); } void TimerModel::emitTimerObjectChanged(int row) { if (row < 0 || row >= rowCount()) return; m_pendingChangedTimerObjects.insert(row); if (!m_pendingChanedRowsTimer->isActive()) m_pendingChanedRowsTimer->start(); } void TimerModel::emitFreeTimerChanged(int row) { if (row < 0 || row >= m_freeTimers.count()) return; m_pendingChangedFreeTimers.insert(row); if (!m_pendingChanedRowsTimer->isActive()) m_pendingChanedRowsTimer->start(); } void TimerModel::flushEmitPendingChangedRows() { foreach (int row, m_pendingChangedTimerObjects) { emit dataChanged(index(row, 0), index(row, LastRole - FirstRole - 2)); } m_pendingChangedTimerObjects.clear(); foreach (int row, m_pendingChangedFreeTimers) { emit dataChanged(index(m_sourceModel->rowCount() + row, 0), index(m_sourceModel->rowCount() + row, LastRole - FirstRole - 2)); } m_pendingChangedFreeTimers.clear(); } gammaray-2.3.0/plugins/timertop/timermodel.h000066400000000000000000000077211255003167400211620ustar00rootroot00000000000000/* timermodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TIMERTOP_TIMERMODEL_H #define GAMMARAY_TIMERTOP_TIMERMODEL_H #include "timerinfo.h" #include #include #include class QTimer; namespace GammaRay { class ProbeInterface; class TimerModel : public QAbstractTableModel { Q_OBJECT public: virtual ~TimerModel(); /// @return True in case instance() would return a valid pointer, else false static bool isInitialized(); static TimerModel *instance(); // For the spy callbacks void preSignalActivate(QObject *caller, int methodIndex); void postSignalActivate(QObject *caller, int methodIndex); enum Roles { FirstRole = UserRole + 1, ObjectNameRole, StateRole, TotalWakeupsRole, WakeupsPerSecRole, TimePerWakeupRole, MaxTimePerWakeupRole, TimerIdRole, LastRole }; /// if set, filters out object owned by the probe void setProbe(ProbeInterface *probe); void setSourceModel(QAbstractItemModel *sourceModel); int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool eventFilter(QObject * watched, QEvent * event) Q_DECL_OVERRIDE; private slots: void slotBeginRemoveRows(const QModelIndex &parent, int start, int end); void slotEndRemoveRows(); void slotBeginInsertRows(const QModelIndex &parent, int start, int end); void slotEndInsertRows(); void slotBeginReset(); void slotEndReset(); void flushEmitPendingChangedRows(); private: explicit TimerModel(QObject *parent = 0); // Finds only QTimers based on the timer ID, not free timers. TimerInfoPtr findOrCreateQTimerTimerInfo(int timerId); // Finds both QTimer and free timers TimerInfoPtr findOrCreateTimerInfo(const QModelIndex &index); // Finds QTimer timers TimerInfoPtr findOrCreateQTimerTimerInfo(QObject* timer); // Finds QObject timers TimerInfoPtr findOrCreateFreeTimerInfo(int timerId); int rowFor(QObject *timer) ; void emitTimerObjectChanged(int row); void emitFreeTimerChanged(int row); QAbstractItemModel *m_sourceModel; QList m_freeTimers; ProbeInterface *m_probe; // current timer signals that are being processed QHash m_currentSignals; // pending dataChanged() signals QSet m_pendingChangedTimerObjects; QSet m_pendingChangedFreeTimers; QTimer *m_pendingChanedRowsTimer; // the method index of the timeout() signal of a QTimer const int m_timeoutIndex; int m_qmlTimerTriggeredIndex; }; } #endif gammaray-2.3.0/plugins/timertop/timertop.cpp000066400000000000000000000066621255003167400212220ustar00rootroot00000000000000/* timertop.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "timertop.h" #include "timermodel.h" #include #include #include using namespace GammaRay; // // TODO list for timer plugin // // BUG: Some QTimers appear as free timers // BUG: QTimeLine class name not shown // BUG: No thread safety yet // Related: Protect against timer deletion // BUG: Sorting in the view doesn't work well // BUG: Only top-level timers are shown (bug in probe) // ! Delete old free timers // ! Wakeup time for QTimers // ! Add button to view object info // ! Test timer added/removed at runtime // Automatic column resizing // Filter line edit // Buttons to kill or slow down timer and start timer // Add clear button that removes all free timers and resets statistics for normal timers // Add big fat "total wakeups / sec" label to the status bar // Retrieve receiver name from connection model // Add to view as column: receivers: slotXYZ and 3 others (shown in tooltip) // Move signal hook to probe interface // Then maybe add general signal profiler plugin, or even visualization // Flash delegate when timer triggered // Color cell in view redish, depending on how active the timer is class TimerFilterModel : public ObjectTypeFilterProxyModel { public: explicit TimerFilterModel(QObject *parent) : ObjectTypeFilterProxyModel(parent) {} bool filterAcceptsObject(QObject *object) const { if (object && object->inherits("QQmlTimer")) return true; return ObjectTypeFilterProxyModel::filterAcceptsObject(object); } }; TimerTop::TimerTop(ProbeInterface *probe, QObject *parent) : QObject(parent), m_updateTimer(new QTimer(this)) { Q_ASSERT(probe); QSortFilterProxyModel* const filterModel = new TimerFilterModel(this); filterModel->setDynamicSortFilter(true); filterModel->setSourceModel(probe->objectListModel()); TimerModel::instance()->setParent(this); // otherwise it's not filtered out TimerModel::instance()->setProbe(probe); TimerModel::instance()->setSourceModel(filterModel); probe->registerModel("com.kdab.GammaRay.TimerModel", TimerModel::instance()); } QStringList TimerTopFactory::supportedTypes() const { return QStringList() << "QObject" << "QTimer"; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(TimerTopFactory) #endif gammaray-2.3.0/plugins/timertop/timertop.h000066400000000000000000000037111255003167400206570ustar00rootroot00000000000000/* timertop.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TIMERTOP_TIMERTOP_H #define GAMMARAY_TIMERTOP_TIMERTOP_H #include #include namespace GammaRay { namespace Ui { class TimerTop; } class TimerTop : public QObject { Q_OBJECT public: explicit TimerTop(ProbeInterface *probe, QObject *parent = 0); private: QTimer *m_updateTimer; }; class TimerTopFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_timertop.json") public: explicit TimerTopFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("Timers"); } QStringList supportedTypes() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_SCENEINSPECTOR_H gammaray-2.3.0/plugins/timertop/timertopwidget.cpp000066400000000000000000000042671255003167400224250ustar00rootroot00000000000000/* timertopwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "timertopwidget.h" #include "ui_timertopwidget.h" #include "timermodel.h" #include #include #include #include using namespace GammaRay; TimerTopWidget::TimerTopWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TimerTopWidget), m_updateTimer(new QTimer(this)) { ui->setupUi(this); QSortFilterProxyModel * const sortModel = new QSortFilterProxyModel(this); sortModel->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.TimerModel")); sortModel->setDynamicSortFilter(true); ui->timerView->setModel(sortModel); ui->timerView->sortByColumn(TimerModel::WakeupsPerSecRole - TimerModel::FirstRole - 1, Qt::DescendingOrder); new DeferredResizeModeSetter(ui->timerView->header(), 0, QHeaderView::ResizeToContents); new DeferredResizeModeSetter(ui->timerView->header(), 1, QHeaderView::ResizeToContents); } TimerTopWidget::~TimerTopWidget() { } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(TimerTopUiFactory) #endif gammaray-2.3.0/plugins/timertop/timertopwidget.h000066400000000000000000000034721255003167400220670ustar00rootroot00000000000000/* timertopwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Thomas McGuire Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TIMERTOP_TIMERTOPWIDGET_H #define GAMMARAY_TIMERTOP_TIMERTOPWIDGET_H #include #include class QTimer; namespace GammaRay { namespace Ui { class TimerTopWidget; } class TimerTopWidget : public QWidget { Q_OBJECT public: explicit TimerTopWidget(QWidget *parent = 0); ~TimerTopWidget(); private: QScopedPointer ui; QTimer *m_updateTimer; }; class TimerTopUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_timertop.json") }; } #endif // GAMMARAY_TIMERTOPWIDGET_H gammaray-2.3.0/plugins/timertop/timertopwidget.ui000066400000000000000000000016021255003167400222460ustar00rootroot00000000000000 GammaRay::TimerTopWidget 0 0 400 300 0 true false true true gammaray-2.3.0/plugins/translatorinspector/000077500000000000000000000000001255003167400211165ustar00rootroot00000000000000gammaray-2.3.0/plugins/translatorinspector/CMakeLists.txt000066400000000000000000000017601255003167400236620ustar00rootroot00000000000000gammaray_add_plugin(gammaray_translatorinspector gammaray_translatorinspector.desktop translatorinspector.cpp translatorinspectorinterface.cpp translatorwrapper.cpp translatorsmodel.cpp ) target_link_libraries(gammaray_translatorinspector gammaray_core Qt5::Core Qt5::Gui) if(GAMMARAY_BUILD_UI) qt5_wrap_ui(translatorinspector_ui_srcs translatorinspectorwidget.ui ) gammaray_add_plugin(gammaray_translatorinspector_ui gammaray_translatorinspector_ui.desktop translatorinspectorwidget.cpp translatorinspectorinterface.cpp ${translatorinspector_ui_srcs} ) target_link_libraries(gammaray_translatorinspector_ui gammaray_ui) endif() if(Qt5Widgets_FOUND) add_executable(translator_test main.cpp) qt5_use_modules(translator_test Widgets) add_custom_target(translator_test_qm COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/translation.qm ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translation.qm ) add_dependencies(translator_test translator_test_qm) endif() gammaray-2.3.0/plugins/translatorinspector/gammaray_translatorinspector.desktop000066400000000000000000000002261255003167400305070ustar00rootroot00000000000000[Desktop Entry] Name=Translators X-GammaRay-Types=QTranslator X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_translatorinspector gammaray-2.3.0/plugins/translatorinspector/gammaray_translatorinspector.json000066400000000000000000000001521255003167400300050ustar00rootroot00000000000000{ "id": "gammaray_translationinspector", "name": "Translations", "types": [ "QTranslator" ] } gammaray-2.3.0/plugins/translatorinspector/gammaray_translatorinspector_ui.desktop000066400000000000000000000002301255003167400311770ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_translatorinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_translatorinspector_ui gammaray-2.3.0/plugins/translatorinspector/main.cpp000066400000000000000000000061671255003167400225600ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0) : QWidget(parent) { m_label1 = new QLabel(this); m_label2 = new QLabel(this); m_label3 = new QLabel(this); m_button = new QPushButton(this); m_layout = new QVBoxLayout; m_layout->addWidget(m_label1); m_layout->addWidget(m_label2); m_layout->addWidget(m_label3); m_layout->addWidget(m_button); setLayout(m_layout); connect(m_button, SIGNAL(clicked()), SLOT(openFonts())); retranslate(); qApp->installEventFilter(this); } void retranslate() { m_label1->setText(tr("One")); m_label2->setText(tr("Two")); m_label3->setText(tr("Three")); m_button->setText(tr("&Fonts")); } private slots: void openFonts() { QFontDialog dialog(this); dialog.exec(); } protected: bool eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::LanguageChange) { retranslate(); } return QWidget::eventFilter(object, event); } private: QLabel *m_label1; QLabel *m_label2; QLabel *m_label3; QPushButton *m_button; QVBoxLayout *m_layout; }; void loadTranslation(const QString &filename, const QString &name) { Q_ASSERT(QDir().exists(filename)); QTranslator *translator = new QTranslator; translator->setObjectName(name); translator->load(filename); qApp->installTranslator(translator); } int main(int argc, char *argv[]) { QApplication app(argc, argv); loadTranslation(app.applicationDirPath() + "/translation.qm", "App translator"); loadTranslation(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_sv.qm", "Qt translator"); Widget widget; widget.show(); return app.exec(); } #include "main.moc" gammaray-2.3.0/plugins/translatorinspector/translation.qm000066400000000000000000000002451255003167400240140ustar00rootroot00000000000000<¸dĘďś•Í!ż`ˇ˝ÝBVE[ßHZřµ"ilEnOneWidgetTreThreeWidgetTvĺTwoWidgetgammaray-2.3.0/plugins/translatorinspector/translation.ts000066400000000000000000000011041255003167400240200ustar00rootroot00000000000000 Widget One En Two TvĂĄ Three Tre gammaray-2.3.0/plugins/translatorinspector/translatorinspector.cpp000066400000000000000000000123331255003167400257440ustar00rootroot00000000000000/* translatorinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "translatorinspector.h" #include #include #include #include #include #include #include #include #include "translatorwrapper.h" #include "translatorsmodel.h" using namespace GammaRay; TranslatorInspector::TranslatorInspector(ProbeInterface *probe, QObject *parent) : TranslatorInspectorInterface("com.kdab.GammaRay.TranslatorInspector", parent), m_probe(probe) { m_translatorsModel = new TranslatorsModel(this); probe->registerModel("com.kdab.GammaRay.TranslatorsModel", m_translatorsModel); m_translationsModel = new QIdentityProxyModel(this); probe->registerModel("com.kdab.GammaRay.TranslationsModel", m_translationsModel); m_selectionModel = ObjectBroker::selectionModel(m_translatorsModel); connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged(QItemSelection))); m_translationsSelectionModel = ObjectBroker::selectionModel(m_translationsModel); m_fallbackWrapper = new TranslatorWrapper(new FallbackTranslator(this), this); m_translatorsModel->registerTranslator(m_fallbackWrapper); QCoreApplicationPrivate *obj = static_cast( QCoreApplicationPrivate::get(qApp)); obj->translators.append(m_fallbackWrapper); qApp->installEventFilter(this); sendLanguageChangeEvent(); } void TranslatorInspector::sendLanguageChangeEvent() { QEvent event(QEvent::LanguageChange); qApp->sendEvent(qApp, &event); } void TranslatorInspector::resetTranslations() { const QItemSelection translatorsSelection = m_selectionModel->selection(); if (translatorsSelection.isEmpty()) { return; } TranslatorWrapper *translator = m_translatorsModel->translator(translatorsSelection.first().topLeft()); Q_ASSERT(translator); const QItemSelection translationsSelection = m_translationsSelectionModel->selection(); if (translationsSelection.isEmpty()) { return; } translator->model()->resetTranslations( translationsSelection.first().topLeft(), translationsSelection.last().bottomRight()); } bool TranslatorInspector::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::LanguageChange) { QCoreApplicationPrivate *obj = static_cast( QCoreApplicationPrivate::get(qApp)); for (int i = 0; i < obj->translators.size(); ++i) { if (obj->translators.at(i)->metaObject()->className() == TranslatorWrapper::staticMetaObject.className()) { continue; // it's already setup correctly } else { /* wrap the translator set with installTranslator in a TranslatorWrapper * and make sure we use the TranslatorWrapper instead of the original * translator */ TranslatorWrapper *wrapper = new TranslatorWrapper(obj->translators[i], this); obj->translators[i] = wrapper; m_translatorsModel->registerTranslator(wrapper); connect(wrapper, &TranslatorWrapper::destroyed, #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) m_translationsModel, #endif [wrapper, this](QObject *) { m_translatorsModel->unregisterTranslator(wrapper); }); } } for (auto it = obj->translators.begin(); it != obj->translators.end(); ++it) { TranslatorWrapper *wrapper = qobject_cast(*it); Q_ASSERT(wrapper); wrapper->model()->resetAllUnchanged(); } } return QObject::eventFilter(object, event); } void TranslatorInspector::selectionChanged(const QItemSelection &selection) { m_translationsModel->setSourceModel(0); if (!selection.isEmpty()) { TranslatorWrapper *translator = m_translatorsModel->translator(selection.first().topLeft()); if (translator) { m_translationsModel->setSourceModel(translator->model()); } } } gammaray-2.3.0/plugins/translatorinspector/translatorinspector.h000066400000000000000000000053551255003167400254170ustar00rootroot00000000000000/* translatorinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TRANSLATORINSPECTOR_H #define TRANSLATORINSPECTOR_H #include "translatorinspectorinterface.h" #include #include #include QT_BEGIN_NAMESPACE class QItemSelectionModel; class QItemSelection; class QAbstractProxyModel; QT_END_NAMESPACE namespace GammaRay { class TranslatorsModel; class TranslatorWrapper; class FallbackTranslator; class TranslatorInspector : public TranslatorInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::TranslatorInspectorInterface) public: explicit TranslatorInspector(GammaRay::ProbeInterface *probe, QObject *parent = 0); public slots: void sendLanguageChangeEvent() Q_DECL_OVERRIDE; void resetTranslations() Q_DECL_OVERRIDE; private slots: void selectionChanged(const QItemSelection &selection); protected: bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; private: QItemSelectionModel *m_selectionModel; QItemSelectionModel *m_translationsSelectionModel; TranslatorsModel *m_translatorsModel; QAbstractProxyModel *m_translationsModel; ProbeInterface *m_probe; TranslatorWrapper *m_fallbackWrapper; }; class TranslatorInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_translatorinspector.json") public: explicit TranslatorInspectorFactory(QObject *parent = 0) : QObject(parent) {} inline QString name() const { return tr("Translators"); } }; } #endif gammaray-2.3.0/plugins/translatorinspector/translatorinspectorinterface.cpp000066400000000000000000000030331255003167400276220ustar00rootroot00000000000000/* translatorinspectorinterface.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "translatorinspectorinterface.h" #include using namespace GammaRay; TranslatorInspectorInterface::TranslatorInspectorInterface(const QString &name, QObject *parent) : QObject(parent), m_name(name) { ObjectBroker::registerObject(name, this); } TranslatorInspectorInterface::~TranslatorInspectorInterface() {} gammaray-2.3.0/plugins/translatorinspector/translatorinspectorinterface.h000066400000000000000000000034251255003167400272740ustar00rootroot00000000000000/* translatorinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TRANSLATORINSPECTORINTERFACE_H #define TRANSLATORINSPECTORINTERFACE_H #include namespace GammaRay { class TranslatorInspectorInterface : public QObject { Q_OBJECT public: explicit TranslatorInspectorInterface(const QString &name, QObject *parent); virtual ~TranslatorInspectorInterface(); const QString &name() const { return m_name; } public slots: virtual void sendLanguageChangeEvent() = 0; virtual void resetTranslations() = 0; private: QString m_name; }; } Q_DECLARE_INTERFACE(GammaRay::TranslatorInspectorInterface, "com.kdab.GammaRay.TranslatorInspectorInterface") #endif gammaray-2.3.0/plugins/translatorinspector/translatorinspectorwidget.cpp000066400000000000000000000063011255003167400271460ustar00rootroot00000000000000/* translatorinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "translatorinspectorwidget.h" #include "ui_translatorinspectorwidget.h" #include #include #include using namespace GammaRay; TranslatorInspectorClient::TranslatorInspectorClient(const QString &name, QObject *parent) : TranslatorInspectorInterface(name, parent) { } void TranslatorInspectorClient::sendLanguageChangeEvent() { Endpoint::instance()->invokeObject(name(), "sendLanguageChangeEvent"); } void TranslatorInspectorClient::resetTranslations() { Endpoint::instance()->invokeObject(name(), "resetTranslations"); } TranslatorInspectorWidget::TranslatorInspectorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TranslatorInspectorWidget) { ui->setupUi(this); QAbstractItemModel *translators = ObjectBroker::model("com.kdab.GammaRay.TranslatorsModel"); ui->translatorList->setModel(translators); ui->translatorList->setSelectionModel(ObjectBroker::selectionModel(translators)); m_inspector = ObjectBroker::object("com.kdab.GammaRay.TranslatorInspector"); connect(ui->languageChangeButton, SIGNAL(clicked()), m_inspector, SLOT(sendLanguageChangeEvent())); connect(ui->resetTranslationsButton, SIGNAL(clicked()), m_inspector, SLOT(resetTranslations())); // searching for translations { QSortFilterProxyModel *translationsFilter = new QSortFilterProxyModel(this); translationsFilter->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.TranslationsModel")); ui->translationsView->setModel(translationsFilter); ui->translationsSearchLine->setProxy(translationsFilter); ui->translationsView->setSelectionModel(ObjectBroker::selectionModel(translationsFilter)); } } TranslatorInspectorWidget::~TranslatorInspectorWidget() { } static QObject* translatorInspectorClientFactory(const QString &name, QObject *parent) { return new TranslatorInspectorClient(name, parent); } void TranslatorInspectorWidgetFactory::initUi() { ObjectBroker::registerClientObjectFactoryCallback(translatorInspectorClientFactory); } gammaray-2.3.0/plugins/translatorinspector/translatorinspectorwidget.h000066400000000000000000000044651255003167400266240ustar00rootroot00000000000000/* translatorinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TRANSLATORINSPECTORWIDGET_H #define TRANSLATORINSPECTORWIDGET_H #include #include #include "translatorinspectorinterface.h" namespace GammaRay { namespace Ui { class TranslatorInspectorWidget; } class TranslatorInspectorClient : public TranslatorInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::TranslatorInspectorInterface) public: explicit TranslatorInspectorClient(const QString &name, QObject *parent = 0); public slots: void sendLanguageChangeEvent() Q_DECL_OVERRIDE; void resetTranslations() Q_DECL_OVERRIDE; }; class TranslatorInspectorWidget : public QWidget { Q_OBJECT public: explicit TranslatorInspectorWidget(QWidget *parent); ~TranslatorInspectorWidget(); private: QScopedPointer ui; TranslatorInspectorInterface *m_inspector; }; class TranslatorInspectorWidgetFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_translatorinspector.json") public: void initUi() Q_DECL_OVERRIDE; }; } #endif gammaray-2.3.0/plugins/translatorinspector/translatorinspectorwidget.ui000066400000000000000000000035541255003167400270100ustar00rootroot00000000000000 GammaRay::TranslatorInspectorWidget 0 0 400 300 Form Qt::Horizontal QAbstractItemView::ContiguousSelection false Reset selected Send QEvent::LanguageChange KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/plugins/translatorinspector/translatorsmodel.cpp000066400000000000000000000101711255003167400252170ustar00rootroot00000000000000/* translatorsmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "translatorsmodel.h" #include #include "translatorwrapper.h" using namespace GammaRay; TranslatorsModel::TranslatorsModel(QObject *parent) : QAbstractTableModel(parent) { } int TranslatorsModel::columnCount(const QModelIndex &) const { return 3; } int TranslatorsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_translators.size(); } QVariant TranslatorsModel::data(const QModelIndex &index, int role) const { if (role == TranslatorRole) { return QVariant::fromValue(m_translators.at(index.row())); } TranslatorWrapper *trans = m_translators.at(index.row()); Q_ASSERT(trans); if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::shortDisplayString(trans->translator()); } else if (index.column() == 1) { return QString(trans->translator()->metaObject()->className()); } else if (index.column() == 2) { return trans->model()->rowCount(QModelIndex()); } } else if (role == Qt::ToolTipRole) { return Util::tooltipForObject(trans->translator()); } return QVariant(); } QVariant TranslatorsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return tr("Object"); } else if (section == 1) { return tr("Type"); } else if (section == 2) { return tr("Translations"); } } return QVariant(); } Qt::ItemFlags TranslatorsModel::flags(const QModelIndex &index) const { Q_UNUSED(index); return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } TranslatorWrapper *TranslatorsModel::translator(const QModelIndex &index) const { return m_translators.at(index.row()); } void TranslatorsModel::sourceDataChanged() { const int row = m_translators.indexOf(qobject_cast(sender())->translator()); if (row == -1) { return; } const QModelIndex index = this->index(row, 2, QModelIndex()); if (!index.isValid()) { return; } // needed to make sure these things also update emit dataChanged(index, index, QVector() << Qt::DisplayRole << Qt::EditRole); } void TranslatorsModel::registerTranslator(TranslatorWrapper *translator) { beginInsertRows(QModelIndex(), m_translators.size(), m_translators.size()); m_translators.append(translator); endInsertRows(); connect(translator->model(), SIGNAL(rowCountChanged()), SLOT(sourceDataChanged())); } void TranslatorsModel::unregisterTranslator(TranslatorWrapper *translator) { const int index = m_translators.indexOf(translator); if (index == -1) { qWarning("TranslatorsModel::unregisterTranslator: translator %s is not registered", qPrintable(Util::addressToString(translator))); return; } disconnect(translator->model(), 0, this, 0); beginRemoveRows(QModelIndex(), index, index); m_translators.removeAt(index); endRemoveRows(); } gammaray-2.3.0/plugins/translatorinspector/translatorsmodel.h000066400000000000000000000043261255003167400246710ustar00rootroot00000000000000/* translatorsmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TRANSLATORSMODEL_H #define TRANSLATORSMODEL_H #include namespace GammaRay { class TranslatorWrapper; class TranslatorsModel : public QAbstractTableModel { Q_OBJECT public: explicit TranslatorsModel(QObject *parent = 0); enum ExtraRoles { TranslatorRole = Qt::UserRole }; int columnCount( const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &proxyIndex, int role) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; TranslatorWrapper *translator(const QModelIndex &index) const; public slots: void registerTranslator(TranslatorWrapper *translator); void unregisterTranslator(TranslatorWrapper *translator); private slots: void sourceDataChanged(); private: QList m_translators; }; } #endif gammaray-2.3.0/plugins/translatorinspector/translatorwrapper.cpp000066400000000000000000000171121255003167400254160ustar00rootroot00000000000000/* translatorwrapper.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "translatorwrapper.h" #include using namespace GammaRay; TranslationsModel::TranslationsModel(TranslatorWrapper *translator) : QAbstractListModel(translator), m_translator(translator) { connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(rowCountChanged())); connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(rowCountChanged())); } int TranslationsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_nodes.size(); } int TranslationsModel::columnCount(const QModelIndex &) const { return 4; } QVariant TranslationsModel::data(const QModelIndex &index, int role) const { if (index.parent().isValid()) { return QVariant(); } Row node = m_nodes.at(index.row()); if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.column()) { case 0: return node.context; case 1: return node.sourceText; case 2: return node.disambiguation; case 3: return node.translation; } } if (role == Qt::FontRole && index.column() == 3 && node.isOverriden) { QFont font; font.setItalic(true); return font; } return QVariant(); } bool TranslationsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::EditRole && index.column() == 3) { Row &node = m_nodes[index.row()]; if (node.translation == value.toString()) { return true; } node.translation = value.toString(); node.isOverriden = true; emit dataChanged(index, index, QVector() << Qt::DisplayRole << Qt::EditRole); return true; } return false; } QVariant TranslationsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Context"); case 1: return tr("Source Text"); case 2: return tr("Disambiguation"); case 3: return tr("Translation"); } } return QVariant(); } Qt::ItemFlags TranslationsModel::flags(const QModelIndex &index) const { if (index.column() == 3) { return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } } void TranslationsModel::resetTranslations(const QModelIndex &first, const QModelIndex &last) { if (!first.isValid() || !last.isValid()) { return; } int top = first.row(); int bottom = last.row(); beginRemoveRows(QModelIndex(), top, bottom); for (int i = 0; i < (bottom - top + 1); ++i) { m_nodes.remove(top); } endRemoveRows(); } QString TranslationsModel::translation(const QByteArray &context, const QByteArray &sourceText, const QByteArray &disambiguation, const int n, const QString &default_) { QModelIndex existingIndex = findNode(context, sourceText, disambiguation, n, true); Row &row = m_nodes[existingIndex.row()]; if (!row.isOverriden) { setTranslation(existingIndex, default_); } return row.translation; } void TranslationsModel::resetAllUnchanged() { for (int i = 0; i < m_nodes.size(); ++i) { if (!m_nodes[i].isOverriden) { resetTranslations(index(i), index(i)); } } } void TranslationsModel::setTranslation(const QModelIndex &index, const QString &translation) { if (!index.isValid()) { return; } if (m_nodes[index.row()].isOverriden) { return; } m_nodes[index.row()].translation = translation; emit dataChanged(index, index); } QModelIndex TranslationsModel::findNode(const QByteArray &context, const QByteArray &sourceText, const QByteArray &disambiguation, const int n, const bool create) { Q_UNUSED(n); // QUESTION make use of n? for (int i = 0; i < m_nodes.size(); ++i) { const Row node = m_nodes.at(i); if (node.context == context && node.sourceText == sourceText && node.disambiguation == disambiguation) { return index(i, 0); } } if (create) { Row node; node.context = context; node.sourceText = sourceText; node.disambiguation = disambiguation; const int newRow = m_nodes.size(); beginInsertRows(QModelIndex(), newRow, newRow); m_nodes.append(node); endInsertRows(); return index(newRow, 0); } return QModelIndex(); } TranslatorWrapper::TranslatorWrapper(QObject *parent) : QTranslator(parent), m_wrapped(0), m_model(new TranslationsModel(this)) { } TranslatorWrapper::TranslatorWrapper(QTranslator *wrapped, QObject *parent) : QTranslator(parent), m_wrapped(wrapped), m_model(new TranslationsModel(this)) { connect(wrapped, SIGNAL(destroyed()), SLOT(deleteLater())); } bool TranslatorWrapper::isEmpty() const { return translator()->isEmpty(); } QString TranslatorWrapper::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const { const QString translation = translateInternal(context, sourceText, disambiguation, n); if (QByteArray(context).startsWith("GammaRay::")) { //krazy:exclude=strings return translation; } // it's not for this translator if (translation.isNull()) { return translation; } return m_model->translation(context, sourceText, disambiguation, n, translation); } QString TranslatorWrapper::translateInternal(const char *context, const char *sourceText, const char *disambiguation, int n) const { return translator()->translate(context, sourceText, disambiguation, n); } const QTranslator *TranslatorWrapper::translator() const { return m_wrapped == 0 ? this : m_wrapped; } FallbackTranslator::FallbackTranslator(QObject *parent) : QTranslator(parent) { setObjectName("Fallback Translator"); } QString FallbackTranslator::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const { Q_UNUSED(context); Q_UNUSED(disambiguation); Q_UNUSED(n); return QString::fromUtf8(sourceText); } gammaray-2.3.0/plugins/translatorinspector/translatorwrapper.h000066400000000000000000000101031255003167400250540ustar00rootroot00000000000000/* translatorwrapper.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Jan Dalheimer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TRANSLATORWRAPPER_H #define TRANSLATORWRAPPER_H #include #include namespace GammaRay { class TranslatorWrapper; class TranslationsModel : public QAbstractListModel { Q_OBJECT public: explicit TranslationsModel(TranslatorWrapper *translator); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; void resetTranslations(const QModelIndex &first, const QModelIndex &last); QString translation(const QByteArray &context, const QByteArray &sourceText, const QByteArray &disambiguation, const int n, const QString &default_); void resetAllUnchanged(); TranslatorWrapper *translator() const { return m_translator; } signals: void rowCountChanged(); private: friend class TranslatorWrapper; TranslatorWrapper *m_translator; struct Row { Row() : isOverriden(false) {} QByteArray context; QByteArray sourceText; QByteArray disambiguation; QString translation; bool isOverriden; }; QVector m_nodes; QModelIndex findNode(const QByteArray &context, const QByteArray &sourceText, const QByteArray &disambiguation, const int n, const bool create); void setTranslation(const QModelIndex &index, const QString &translation); }; class TranslatorWrapper : public QTranslator { Q_OBJECT public: explicit TranslatorWrapper(QObject *parent = 0); explicit TranslatorWrapper(QTranslator *wrapped, QObject *parent = 0); TranslationsModel *model() const { return m_model; } bool isEmpty() const Q_DECL_OVERRIDE; QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const Q_DECL_OVERRIDE; const QTranslator *translator() const; private: QTranslator *m_wrapped; TranslationsModel *m_model; QString translateInternal(const char *context, const char *sourceText, const char *disambiguation, int n) const; }; class FallbackTranslator : public QTranslator { Q_OBJECT public: explicit FallbackTranslator(QObject *parent = 0); bool isEmpty() const Q_DECL_OVERRIDE { return false; } QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const Q_DECL_OVERRIDE; private: #ifndef Q_NO_USING_KEYWORD // hide using QTranslator::load; #endif }; } #endif gammaray-2.3.0/plugins/webinspector/000077500000000000000000000000001255003167400175025ustar00rootroot00000000000000gammaray-2.3.0/plugins/webinspector/CMakeLists.txt000066400000000000000000000020001255003167400222320ustar00rootroot00000000000000# probe part set(gammaray_webinspector_plugin_srcs webinspector.cpp webviewmodel.cpp ) gammaray_add_plugin(gammaray_webinspector_plugin gammaray_webinspector.desktop ${gammaray_webinspector_plugin_srcs} ) target_link_libraries(gammaray_webinspector_plugin ${QT_QTCORE_LIBRARIES} gammaray_core ) if(HAVE_QT_WEBKIT1) target_link_libraries(gammaray_webinspector_plugin ${QT_QTWEBKIT_LIBRARIES} ${Qt5WebKitWidgets_LIBRARIES} ) if(GAMMARAY_BUILD_UI) # ui part set(gammaray_webinspector_ui_plugin_srcs webinspectorwidget.cpp ) qt4_wrap_ui(gammaray_webinspector_ui_plugin_srcs webinspectorwidget.ui) gammaray_add_plugin(gammaray_webinspector_ui_plugin gammaray_webinspector_ui.desktop ${gammaray_webinspector_ui_plugin_srcs} ) target_link_libraries(gammaray_webinspector_ui_plugin ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTWEBKIT_LIBRARIES} ${Qt5WebKitWidgets_LIBRARIES} gammaray_common ) endif() endif() gammaray-2.3.0/plugins/webinspector/gammaray_webinspector.desktop000066400000000000000000000002451255003167400254600ustar00rootroot00000000000000[Desktop Entry] Name=Web Inspector X-GammaRay-Types="QWebPage;QQuickWebView" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_webinspector_plugin gammaray-2.3.0/plugins/webinspector/gammaray_webinspector.json000066400000000000000000000001611255003167400247550ustar00rootroot00000000000000{ "id": "gammaray_webinspector", "name": "Web Inspector", "types": [ "QWebPage", "QQuickWebView" ] } gammaray-2.3.0/plugins/webinspector/gammaray_webinspector_ui.desktop000066400000000000000000000002211255003167400261470ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_webinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_webinspector_ui_plugin gammaray-2.3.0/plugins/webinspector/webinspector.cpp000066400000000000000000000072341255003167400227200ustar00rootroot00000000000000/* webinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "webinspector.h" #include "webviewmodel.h" #include #include #include #include #include #include #include #ifdef HAVE_QT_WEBKIT1 #include #endif using namespace GammaRay; WebInspector::WebInspector(ProbeInterface *probe, QObject *parent) : QObject(parent) { WebViewModel *webViewModel = new WebViewModel(this); webViewModel->setSourceModel(probe->objectListModel()); probe->registerModel("com.kdab.GammaRay.WebPages", webViewModel); connect(probe->probe(), SIGNAL(objectCreated(QObject*)), SLOT(objectAdded(QObject*))); const QUrl serverUrl = Endpoint::instance()->serverAddress(); QString serverAddress("0.0.0.0"); if (serverUrl.scheme() == "tcp") serverAddress = serverUrl.host(); qputenv("QTWEBKIT_INSPECTOR_SERVER", serverAddress.toLocal8Bit() + ':' + QByteArray::number(Endpoint::defaultPort() + 1)); } void WebInspector::objectAdded(QObject* obj) { // both of the following cases seem to be needed, the web view object changes depending on // you have "import QtWebKit.experimental 1.0" or not... QObject *experimental = 0; if (obj->inherits("QQuickWebView")) { experimental = obj->property("experimental").value(); } if (obj->inherits("QQuickWebViewExperimental")) experimental = obj; if (!experimental) return; // FIXME: this conversion fails with "QMetaProperty::read: Unable to handle unregistered datatype 'QWebPreferences*' for property 'QQuickWebViewExperimental::preferences'" // if we don't have "import QtWebKit.experimental 1.0" QObject *prefs = experimental->property("preferences").value(); if (!prefs) return; prefs->setProperty("developerExtrasEnabled", true); } WebInspectorFactory::WebInspectorFactory(QObject* parent): QObject(parent) { } QString WebInspectorFactory::id() const { return WebInspector::staticMetaObject.className(); } void WebInspectorFactory::init(ProbeInterface* probe) { new WebInspector(probe, probe->probe()); } QStringList WebInspectorFactory::supportedTypes() const { QStringList types; #ifdef HAVE_QT_WEBKIT1 types.push_back(QWebPage::staticMetaObject.className()); #endif types.push_back("QQuickWebView"); return types; } QString WebInspectorFactory::name() const { return tr("Web Pages"); } bool WebInspectorFactory::isHidden() const { return false; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(WebInspectorFactory) #endif gammaray-2.3.0/plugins/webinspector/webinspector.h000066400000000000000000000037531255003167400223670ustar00rootroot00000000000000/* webinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WEBINSPECTOR_WEBINSPECTOR_H #define GAMMARAY_WEBINSPECTOR_WEBINSPECTOR_H #include namespace GammaRay { class WebInspector : public QObject { Q_OBJECT public: explicit WebInspector(GammaRay::ProbeInterface *probe, QObject *parent = 0); private slots: void objectAdded(QObject *obj); }; class WebInspectorFactory : public QObject, public ToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_webinspector.json") public: explicit WebInspectorFactory(QObject *parent = 0); QString id() const Q_DECL_OVERRIDE; QString name() const Q_DECL_OVERRIDE; void init(ProbeInterface* probe) Q_DECL_OVERRIDE; QStringList supportedTypes() const Q_DECL_OVERRIDE; bool isHidden() const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_WEBINSPECTOR_H gammaray-2.3.0/plugins/webinspector/webinspectorwidget.cpp000066400000000000000000000055641255003167400241300ustar00rootroot00000000000000/* webinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "webinspectorwidget.h" #include "webviewmodel.h" #include "ui_webinspectorwidget.h" #include #include #include using namespace GammaRay; WebInspectorWidget::WebInspectorWidget(QWidget* parent) : QWidget(parent), ui(new Ui::WebInspectorWidget) { ui->setupUi(this); ui->webPageComboBox->setModel(ObjectBroker::model("com.kdab.GammaRay.WebPages")); connect(ui->webPageComboBox, SIGNAL(activated(int)), SLOT(webPageSelected(int))); } WebInspectorWidget::~WebInspectorWidget() { } void WebInspectorWidget::webPageSelected(int index) { QObject *obj = ui->webPageComboBox->itemData(index, ObjectModel::ObjectRole).value(); // Wk 1, local if (QWebPage *page = qobject_cast(obj)) { page->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); ui->webInspector->setPage(page); // webinspector needs a show event to actually show anything, just setting the page is not enough... ui->webInspector->hide(); ui->webInspector->show(); ui->stack->setCurrentWidget(ui->wk1LocalPage); } else if (ui->webPageComboBox->itemData(index, WebViewModel::WebKitVersionRole).toInt() == 2) { const QUrl serverUrl = Endpoint::instance()->serverAddress(); if (serverUrl.scheme() == QLatin1String("tcp")) { QUrl inspectorUrl; inspectorUrl.setScheme("http"); inspectorUrl.setHost(serverUrl.host()); inspectorUrl.setPort(Endpoint::defaultPort() + 1); ui->webView->setUrl(inspectorUrl); ui->stack->setCurrentWidget(ui->wk2Page); } } // WK1, remote else { ui->stack->setCurrentWidget(ui->wk1RemotePage); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(WebInspectorUiFactory) #endif gammaray-2.3.0/plugins/webinspector/webinspectorwidget.h000066400000000000000000000035611255003167400235700ustar00rootroot00000000000000/* webinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WEBINSPECTOR_WEBINSPECTORWIDGET_H #define GAMMARAY_WEBINSPECTOR_WEBINSPECTORWIDGET_H #include #include #include namespace GammaRay { namespace Ui { class WebInspectorWidget; } class WebInspectorWidget : public QWidget { Q_OBJECT public: explicit WebInspectorWidget(QWidget *parent = 0); ~WebInspectorWidget(); private slots: void webPageSelected(int index); private: QScopedPointer ui; }; class WebInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_webinspector.json") }; } #endif gammaray-2.3.0/plugins/webinspector/webinspectorwidget.ui000066400000000000000000000036461255003167400237620ustar00rootroot00000000000000 GammaRay::WebInspectorWidget 0 0 727 530 Sorry, WebKit1 introspection is not available remotely/out-of-process. Qt::AlignCenter about:blank QWebView QWidget
QtWebKitWidgets/QWebView
QWebInspector QWidget
qwebinspector.h
gammaray-2.3.0/plugins/webinspector/webviewmodel.cpp000066400000000000000000000047271255003167400227110ustar00rootroot00000000000000/* webviewmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "webviewmodel.h" #include "common/objectmodel.h" #ifdef HAVE_QT_WEBKIT1 #include #endif using namespace GammaRay; WebViewModel::WebViewModel(QObject* parent): ObjectFilterProxyModelBase(parent) { } WebViewModel::~WebViewModel() { } QVariant WebViewModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); if ((role != Qt::DisplayRole && role != WebKitVersionRole) || index.column() != 0) return QSortFilterProxyModel::data(index, role); const QObject *obj = index.data(ObjectModel::ObjectRole).value(); #ifdef HAVE_QT_WEBKIT1 const bool isWk1 = qobject_cast(obj); #else const bool isWk1 = false; #endif if (role == Qt::DisplayRole) return QString(Util::displayString(obj) + (isWk1 ? " [WebKit1]" : " [WebKit2]")); if (role == WebKitVersionRole) return isWk1 ? 1 : 2; Q_ASSERT(!"WTF?"); return QVariant(); } QMap< int, QVariant > WebViewModel::itemData(const QModelIndex& index) const { QMap d = ObjectFilterProxyModelBase::itemData(index); d.insert(WebKitVersionRole, data(index, WebKitVersionRole)); return d; } bool WebViewModel::filterAcceptsObject(QObject* object) const { return #ifdef HAVE_QT_WEBKIT1 qobject_cast(object) || #endif object->inherits("QQuickWebView"); } gammaray-2.3.0/plugins/webinspector/webviewmodel.h000066400000000000000000000034161255003167400223500ustar00rootroot00000000000000/* webviewmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WEBINSPECTOR_WEBVIEWMODEL_H #define GAMMARAY_WEBINSPECTOR_WEBVIEWMODEL_H #include namespace GammaRay { class WebViewModel : public ObjectFilterProxyModelBase { Q_OBJECT public: explicit WebViewModel(QObject *parent = 0); ~WebViewModel(); enum Role { WebKitVersionRole = ObjectModel::UserRole }; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMap< int, QVariant > itemData(const QModelIndex& index) const Q_DECL_OVERRIDE; bool filterAcceptsObject(QObject* object) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_WEBVIEWMODEL_H gammaray-2.3.0/plugins/widgetinspector/000077500000000000000000000000001255003167400202105ustar00rootroot00000000000000gammaray-2.3.0/plugins/widgetinspector/CMakeLists.txt000066400000000000000000000044751255003167400227620ustar00rootroot00000000000000if(NOT Qt5Gui_VERSION VERSION_LESS 5.5.0) # QPaintBuffer was removed in 5.5 include_directories(${CMAKE_SOURCE_DIR}/3rdparty/qt/5.5/) endif() # probe plugin set(gammaray_widgetinspector_plugin_srcs widgetinspector.cpp widgetinspectorinterface.cpp widgetinspectorserver.cpp overlaywidget.cpp widgettreemodel.cpp paintbufferreplaywidget.cpp modelutils.cpp ) if(HAVE_PRIVATE_QT_HEADERS) set(gammaray_widgetinspector_plugin_srcs ${gammaray_widgetinspector_plugin_srcs} paintbuffermodel.cpp ) endif() if(NOT Qt5Gui_VERSION VERSION_LESS 5.5.0) list(APPEND gammaray_widgetinspector_plugin_srcs ${CMAKE_SOURCE_DIR}/3rdparty/qt/5.5/private/qpaintbuffer.cpp) endif() if(NOT Qt5Gui_VERSION VERSION_LESS 5.5.0) list(APPEND gammaray_widgetinspector_plugin_srcs ${CMAKE_SOURCE_DIR}/3rdparty/qt/5.5/private/qpaintbuffer.cpp) endif() gammaray_add_plugin(gammaray_widgetinspector_plugin gammaray_widgetinspector.desktop ${gammaray_widgetinspector_plugin_srcs} ) target_link_libraries(gammaray_widgetinspector_plugin ${QT_QTGUI_LIBRARIES} gammaray_core ) # probe export actions add_library(gammaray_widget_export_actions SHARED widgetinspector_export_actions.cpp uiextractor.cpp ) set_target_properties(gammaray_widget_export_actions PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${PROBE_PLUGIN_INSTALL_DIR}" ) set(EXTRA_LIBS) if(HAVE_QT_DESIGNER) list(APPEND EXTRA_LIBS ${QT_QTDESIGNER_LIBRARIES}) endif() target_link_libraries(gammaray_widget_export_actions ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTSVG_LIBRARIES} ${Qt5PrintSupport_LIBRARIES} ${EXTRA_LIBS} ) install(TARGETS gammaray_widget_export_actions DESTINATION ${PROBE_PLUGIN_INSTALL_DIR}) # UI plugin if(GAMMARAY_BUILD_UI) set(gammaray_widgetinspector_ui_plugin_srcs widgetinspectorinterface.cpp widgetinspectorclient.cpp widgetinspectorwidget.cpp widgetpreviewwidget.cpp paintbufferviewer.cpp paintbufferreplaywidget.cpp ) qt4_wrap_ui(gammaray_widgetinspector_ui_plugin_srcs widgetinspectorwidget.ui paintbufferviewer.ui ) gammaray_add_plugin(gammaray_widgetinspector_ui_plugin gammaray_widgetinspector_ui.desktop ${gammaray_widgetinspector_ui_plugin_srcs} ) target_link_libraries(gammaray_widgetinspector_ui_plugin ${QT_QTGUI_LIBRARIES} gammaray_ui ) endif() gammaray-2.3.0/plugins/widgetinspector/gammaray_widgetinspector.desktop000066400000000000000000000002401255003167400266670ustar00rootroot00000000000000[Desktop Entry] Name=Widgets X-GammaRay-Types="QWidget;QApplication" X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolFactory Exec=gammaray_widgetinspector_plugin gammaray-2.3.0/plugins/widgetinspector/gammaray_widgetinspector.json000066400000000000000000000001541255003167400261730ustar00rootroot00000000000000{ "id": "gammaray_widgetinspector", "name": "Widgets", "types": [ "QWidget", "QApplication" ] } gammaray-2.3.0/plugins/widgetinspector/gammaray_widgetinspector_ui.desktop000066400000000000000000000002271255003167400273710ustar00rootroot00000000000000[Desktop Entry] X-GammaRay-Id=gammaray_widgetinspector X-GammaRay-ServiceTypes=com.kdab.GammaRay.ToolUiFactory Exec=gammaray_widgetinspector_ui_plugin gammaray-2.3.0/plugins/widgetinspector/modelutils.cpp000066400000000000000000000046271255003167400231060ustar00rootroot00000000000000/* modelutils.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelutils.h" #include using namespace GammaRay; QModelIndexList ModelUtils::match(const QAbstractItemModel* model, const QModelIndex& start, int role, bool (*accept)(const QVariant&), int hits, Qt::MatchFlags flags) { if (!model || !start.isValid() || role < 0) return QModelIndexList(); const QModelIndex parentIndex = model->parent(start); bool recurse = flags & Qt::MatchRecursive; bool wrap = flags & Qt::MatchWrap; bool allHits = (hits == -1); int from = start.row(); int to = model->rowCount(parentIndex); QModelIndexList result; // iterates twice if wrapping for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) { QModelIndex idx = model->index(r, start.column(), parentIndex); if (!idx.isValid()) continue; const QVariant v = model->data(idx, role); if (accept(v)) result << idx; // search the hierarchy if (recurse && model->hasChildren(idx)) { result += match(model, model->index(0, idx.column(), idx), role, accept, (allHits ? -1 : hits - result.count()), flags); } } // prepare for the next iteration from = 0; to = start.row(); } return result; } gammaray-2.3.0/plugins/widgetinspector/modelutils.h000066400000000000000000000036231255003167400225460ustar00rootroot00000000000000/* modelutils.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELUTILS_H #define GAMMARAY_MODELUTILS_H #include namespace GammaRay { namespace ModelUtils { /** * Return a list of items that are accepted by an acceptor function * This class extends the functionality provided in QAbstractItemModel::match(...) * * If (accept(v)) for an item v in the model returns true, it will be appended * to the result list * * @param accept Function in the form 'bool f(const QVariant&)' * * @see QAbstractItemModel::match(...) */ QModelIndexList match(const QAbstractItemModel* model, const QModelIndex& start, int role, bool (*accept)(const QVariant&), int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchWrap)); } } #endif // GAMMARAY_MODELUTILS_H gammaray-2.3.0/plugins/widgetinspector/overlaywidget.cpp000066400000000000000000000125201255003167400236010ustar00rootroot00000000000000/* overlaywidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Tobias Koenig Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "overlaywidget.h" #include #include #include #include #include using namespace GammaRay; static QWidget *toplevelWidget(QWidget *widget) { QWidget *parent = widget; while (parent->parentWidget() && (qobject_cast(parent->parentWidget()) == 0) && (qobject_cast(parent) == 0)) { parent = parent->parentWidget(); } return parent; } OverlayWidget::OverlayWidget() : m_currentToplevelWidget(0), m_currentWidget(0), m_drawLayoutOutlineOnly(true) { setAttribute(Qt::WA_TransparentForMouseEvents); setFocusPolicy(Qt::NoFocus); } void OverlayWidget::placeOn(QWidget *widget) { if (widget == 0) { if (m_currentWidget) { m_currentWidget->removeEventFilter(this); } if (m_currentToplevelWidget) { m_currentToplevelWidget->removeEventFilter(this); } m_currentToplevelWidget = 0; m_currentWidget = 0; m_widgetRect = QRect(); m_layoutPath = QPainterPath(); update(); return; } QWidget *toplevel = toplevelWidget(widget); Q_ASSERT(toplevel); if (m_currentWidget) { m_currentWidget->removeEventFilter(this); } m_currentWidget = widget; if (toplevel != m_currentToplevelWidget) { if (m_currentToplevelWidget) { m_currentToplevelWidget->removeEventFilter(this); } m_currentToplevelWidget = toplevel; setParent(toplevel); move(0, 0); resize(toplevel->size()); m_currentToplevelWidget->installEventFilter(this); show(); } m_currentWidget->installEventFilter(this); updatePositions(); } bool OverlayWidget::eventFilter(QObject *receiver, QEvent *event) { if (receiver == m_currentToplevelWidget) { if (event->type() == QEvent::Resize) { resizeOverlay(); updatePositions(); } } else if (receiver == m_currentWidget) { if (event->type() == QEvent::Resize || event->type() == QEvent::Move) { resizeOverlay(); updatePositions(); } } return false; } void OverlayWidget::updatePositions() { if (!m_currentWidget || !m_currentToplevelWidget) { return; } if (!m_currentWidget->isVisible() || m_currentWidget->isHidden()) { m_widgetColor = Qt::green; } else { m_widgetColor = Qt::red; } const QPoint parentPos = m_currentWidget->mapTo(m_currentToplevelWidget, QPoint(0, 0)); m_widgetRect = QRect(parentPos.x(), parentPos.y(), m_currentWidget->width(), m_currentWidget->height()).adjusted(0, 0, -1, -1); m_layoutPath = QPainterPath(); if (m_currentWidget->layout() && qstrcmp(m_currentWidget->layout()->metaObject()->className(), "QMainWindowLayout") != 0) { const QRect layoutGeometry = m_currentWidget->layout()->geometry(); const QRect mappedOuterRect = QRect(m_currentWidget->mapTo(m_currentToplevelWidget, layoutGeometry.topLeft()), layoutGeometry.size()); QPainterPath outerPath; outerPath.addRect(mappedOuterRect.adjusted(1, 1, -2, -2)); QPainterPath innerPath; for (int i = 0; i < m_currentWidget->layout()->count(); ++i) { QLayoutItem *item = m_currentWidget->layout()->itemAt(i); if (item->widget() && !item->widget()->isVisible()) continue; const QRect mappedInnerRect = QRect(m_currentWidget->mapTo(m_currentToplevelWidget, item->geometry().topLeft()), item->geometry().size()); innerPath.addRect(mappedInnerRect); } m_layoutPath.setFillRule(Qt::OddEvenFill); m_layoutPath = outerPath.subtracted(innerPath); if (m_layoutPath.isEmpty()) { m_layoutPath = outerPath; m_layoutPath.addPath(innerPath); m_drawLayoutOutlineOnly = true; } else { m_drawLayoutOutlineOnly = false; } } update(); } void OverlayWidget::resizeOverlay() { if (m_currentToplevelWidget) { move(0, 0); resize(m_currentToplevelWidget->size()); } } void OverlayWidget::paintEvent(QPaintEvent *) { QPainter p(this); p.setPen(m_widgetColor); p.drawRect(m_widgetRect); QBrush brush(Qt::BDiagPattern); brush.setColor(Qt::blue); if (!m_drawLayoutOutlineOnly) { p.fillPath(m_layoutPath, brush); } p.setPen(Qt::blue); p.drawPath(m_layoutPath); } gammaray-2.3.0/plugins/widgetinspector/overlaywidget.h000066400000000000000000000034171255003167400232530ustar00rootroot00000000000000/* overlaywidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Tobias Koenig Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_OVERLAYWIDGET_H #define GAMMARAY_WIDGETINSPECTOR_OVERLAYWIDGET_H #include namespace GammaRay { class OverlayWidget : public QWidget { Q_OBJECT public: OverlayWidget(); void placeOn(QWidget *widget); bool eventFilter(QObject *receiver, QEvent *event) Q_DECL_OVERRIDE; protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: void resizeOverlay(); void updatePositions(); QWidget *m_currentToplevelWidget; QWidget *m_currentWidget; QRect m_widgetRect; QColor m_widgetColor; QPainterPath m_layoutPath; bool m_drawLayoutOutlineOnly; }; } #endif gammaray-2.3.0/plugins/widgetinspector/paintbuffermodel.cpp000066400000000000000000000105631255003167400242470ustar00rootroot00000000000000/* paintbuffermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #ifdef HAVE_PRIVATE_QT_HEADERS #include "paintbuffermodel.h" using namespace GammaRay; struct cmd_t { QPaintBufferPrivate::Command cmd; const char *name; }; #define CMD(cmd) { QPaintBufferPrivate::Cmd_ ## cmd, #cmd } static const cmd_t cmdTypes[] = { CMD(Save), CMD(Restore), CMD(SetBrush), CMD(SetBrushOrigin), CMD(SetClipEnabled), CMD(SetCompositionMode), CMD(SetOpacity), CMD(SetPen), CMD(SetRenderHints), CMD(SetTransform), CMD(SetBackgroundMode), CMD(ClipPath), CMD(ClipRect), CMD(ClipRegion), CMD(ClipVectorPath), CMD(DrawVectorPath), CMD(FillVectorPath), CMD(StrokeVectorPath), CMD(DrawConvexPolygonF), CMD(DrawConvexPolygonI), CMD(DrawEllipseF), CMD(DrawEllipseI), CMD(DrawLineF), CMD(DrawLineI), CMD(DrawPath), CMD(DrawPointsF), CMD(DrawPointsI), CMD(DrawPolygonF), CMD(DrawPolygonI), CMD(DrawPolylineF), CMD(DrawPolylineI), CMD(DrawRectF), CMD(DrawRectI), CMD(FillRectBrush), CMD(FillRectColor), CMD(DrawText), CMD(DrawTextItem), CMD(DrawImagePos), CMD(DrawImageRect), CMD(DrawPixmapPos), CMD(DrawPixmapRect), CMD(DrawTiledPixmap), CMD(SystemStateChanged), CMD(Translate), CMD(DrawStaticText) }; class PaintBufferPrivacyViolater : public QPainterReplayer { public: QPaintBufferPrivate *extract() const { return d; } }; PaintBufferModel::PaintBufferModel(QObject *parent) : QAbstractTableModel(parent), m_privateBuffer(0) { } void PaintBufferModel::setPaintBuffer(const QPaintBuffer &buffer) { beginResetModel(); m_buffer = buffer; PaintBufferPrivacyViolater p; p.processCommands(buffer, 0, 0, -1); // end < begin -> no processing m_privateBuffer = p.extract(); endResetModel(); } QPaintBuffer PaintBufferModel::buffer() const { return m_buffer; } QVariant PaintBufferModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_privateBuffer) { return QVariant(); } if (role == Qt::DisplayRole) { const QPaintBufferCommand cmd = m_privateBuffer->commands.at(index.row()); switch (index.column()) { case 0: return cmdTypes[cmd.id].name; case 1: { #ifndef QT_NO_DEBUG_STREAM QString desc = m_buffer.commandDescription(index.row()); const QString prefix = QLatin1String("Cmd_") + QLatin1String(cmdTypes[cmd.id].name); if (desc.startsWith(prefix)) { desc = desc.mid(prefix.length()); } if (desc.startsWith(QLatin1String(": ")) || desc.startsWith(QLatin1String(", "))) { desc = desc.mid(2); } return desc; #endif } } } return QVariant(); } int PaintBufferModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); #ifndef QT_NO_DEBUG_STREAM return 2; #else return 1; #endif } int PaintBufferModel::rowCount(const QModelIndex &parent) const { if (!m_privateBuffer || parent.isValid()) { return 0; } return m_privateBuffer->commands.size(); } QVariant PaintBufferModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Command"); case 1: return tr("Arguments"); } } return QAbstractItemModel::headerData(section, orientation, role); } #endif gammaray-2.3.0/plugins/widgetinspector/paintbuffermodel.h000066400000000000000000000042771255003167400237210ustar00rootroot00000000000000/* paintbuffermodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERMODEL_H #define GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERMODEL_H #include #ifdef HAVE_PRIVATE_QT_HEADERS #include #include class QPaintBuffer; namespace GammaRay { /** * Model that shows commands stored in a QPaintBuffer. */ class PaintBufferModel : public QAbstractTableModel { Q_OBJECT public: explicit PaintBufferModel(QObject *parent = 0); void setPaintBuffer(const QPaintBuffer &buffer); QPaintBuffer buffer() const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QPaintBuffer m_buffer; QPaintBufferPrivate *m_privateBuffer; }; } #endif #endif // GAMMARAY_PAINTBUFFERMODEL_H gammaray-2.3.0/plugins/widgetinspector/paintbufferreplaywidget.cpp000066400000000000000000000040051255003167400256410ustar00rootroot00000000000000/* paintbufferreplaywidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "paintbufferreplaywidget.h" #include using namespace GammaRay; PaintBufferReplayWidget::PaintBufferReplayWidget(QWidget *parent) : QWidget(parent), m_zoomFactor(1) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } void PaintBufferReplayWidget::setZoomFactor(int zoom) { m_zoomFactor = zoom; resize(sizeHint()); update(); } void PaintBufferReplayWidget::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; resize(sizeHint()); update(); } QSize PaintBufferReplayWidget::sizeHint() const { const QSize size = m_pixmap.size(); return QSize(size.width() * m_zoomFactor, size.height() * m_zoomFactor); } void PaintBufferReplayWidget::paintEvent(QPaintEvent * /*event*/) { QPainter p(this); p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.scale(m_zoomFactor, m_zoomFactor); p.drawPixmap(QPoint(0, 0), m_pixmap); } gammaray-2.3.0/plugins/widgetinspector/paintbufferreplaywidget.h000066400000000000000000000034751255003167400253200ustar00rootroot00000000000000/* paintbufferreplaywidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERREPLAYWIDGET_H #define GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERREPLAYWIDGET_H #include #include namespace GammaRay { /** * A widget painting a certain sub-set of a QPaintBuffer. */ class PaintBufferReplayWidget : public QWidget { Q_OBJECT public: explicit PaintBufferReplayWidget(QWidget *parent = 0); QSize sizeHint() const Q_DECL_OVERRIDE; public slots: void setZoomFactor(int zoom); void setPixmap(const QPixmap &pixmap); protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: QPixmap m_pixmap; int m_zoomFactor; }; } #endif // GAMMARAY_PAINTBUFFERREPLAYWIDGET_H gammaray-2.3.0/plugins/widgetinspector/paintbufferviewer.cpp000066400000000000000000000037201255003167400244450ustar00rootroot00000000000000/* paintbufferviewer.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "paintbufferviewer.h" #include "ui_paintbufferviewer.h" #include "widgetinspectorinterface.h" #include using namespace GammaRay; PaintBufferViewer::PaintBufferViewer(QWidget *parent) : QDialog(parent) , ui(new Ui::PaintBufferViewer) { ui->setupUi(this); ui->commandView->setModel(ObjectBroker::model("com.kdab.GammaRay.PaintBufferModel")); ui->commandView->setSelectionModel(ObjectBroker::selectionModel(ui->commandView->model())); ui->splitter->setStretchFactor(0, 0); ui->splitter->setStretchFactor(1, 1); connect(ObjectBroker::object(), SIGNAL(paintAnalyzed(QPixmap)), ui->replayWidget, SLOT(setPixmap(QPixmap))); connect(ui->zoomSlider, SIGNAL(valueChanged(int)), ui->replayWidget, SLOT(setZoomFactor(int))); } PaintBufferViewer::~PaintBufferViewer() { } gammaray-2.3.0/plugins/widgetinspector/paintbufferviewer.h000066400000000000000000000032651255003167400241160ustar00rootroot00000000000000/* paintbufferviewer.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERVIEWER_H #define GAMMARAY_WIDGETINSPECTOR_PAINTBUFFERVIEWER_H #include #include class QAbstractItemModel; namespace GammaRay { class WidgetInspectorInterface; namespace Ui { class PaintBufferViewer; } /** * A widget to look at the command list in a QPaintBuffer. */ class PaintBufferViewer : public QDialog { Q_OBJECT public: explicit PaintBufferViewer(QWidget *parent = 0); virtual ~PaintBufferViewer(); private: QScopedPointer ui; }; } #endif gammaray-2.3.0/plugins/widgetinspector/paintbufferviewer.ui000066400000000000000000000056771255003167400243150ustar00rootroot00000000000000 GammaRay::PaintBufferViewer 0 0 591 378 0 Qt::Horizontal false &Zoom: zoomSlider 1 8 1 Qt::Horizontal Qt::Horizontal 40 20 true Qt::AlignCenter 0 0 227 341 GammaRay::PaintBufferReplayWidget QWidget
paintbufferreplaywidget.h
1
gammaray-2.3.0/plugins/widgetinspector/uiextractor.cpp000066400000000000000000000043441255003167400232720ustar00rootroot00000000000000/* uiextractor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "uiextractor.h" #ifdef HAVE_QT_DESIGNER #include #include #include #include using namespace GammaRay; bool UiExtractor::checkProperty(QObject *obj, const QString &prop) const { const QMetaObject *mo = obj->metaObject(); const QMetaProperty mp = mo->property(mo->indexOfProperty(prop.toLatin1())); // TODO come up with some more aggressive filtering if (mp.isValid() && mp.isDesignable(obj) && mp.isStored(obj) && mp.isWritable()) { const QVariant value = mp.read(obj); // try to figure out the default by resetting to it if (mp.isResettable()) { mp.reset(obj); if (mp.read(obj) == value) { return false; } mp.write(obj, value); return true; } // some guessing for non-resettable properties if (value.isNull() || !value.isValid()) { return false; } if (value.type() == QVariant::String) { return !value.toString().isEmpty(); } else if (value.type() == QVariant::Locale) { return value.toLocale() != QLocale::system(); } return true; } return false; } #endif gammaray-2.3.0/plugins/widgetinspector/uiextractor.h000066400000000000000000000027551255003167400227430ustar00rootroot00000000000000/* uiextractor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_UIEXTRACTOR_H #define GAMMARAY_WIDGETINSPECTOR_UIEXTRACTOR_H #include #ifdef HAVE_QT_DESIGNER #include namespace GammaRay { class UiExtractor : public QFormBuilder { protected: bool checkProperty(QObject *obj, const QString &prop) const Q_DECL_OVERRIDE; }; } #endif #endif // GAMMARAY_UIEXTRACTOR_H gammaray-2.3.0/plugins/widgetinspector/widgetinspector.cpp000066400000000000000000000024371255003167400241340ustar00rootroot00000000000000/* widgetinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "widgetinspector.h" #include using namespace GammaRay; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(WidgetInspectorFactory) #endif gammaray-2.3.0/plugins/widgetinspector/widgetinspector.h000066400000000000000000000034341255003167400235770ustar00rootroot00000000000000/* widgetinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTOR_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTOR_H #include "widgetinspectorserver.h" #include #include namespace GammaRay { class WidgetInspectorFactory : public QObject, public StandardToolFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolFactory" FILE "gammaray_widgetinspector.json") public: explicit WidgetInspectorFactory(QObject *parent = 0) : QObject(parent) { } inline QString name() const { return tr("Widgets"); } }; } #endif // GAMMARAY_WIDGETINSPECTOR_H gammaray-2.3.0/plugins/widgetinspector/widgetinspector_export_actions.cpp000066400000000000000000000047501255003167400272550ustar00rootroot00000000000000/* widgetinspector_export_actions.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file widgetinspector_export_actions.cpp * dlopen hack to avoid dependencies on QtSvg and QtDesigner in the main probe. */ #include #include "uiextractor.h" #ifdef HAVE_QT_SVG #include #endif #ifdef HAVE_QT_PRINTSUPPORT #include #endif #include #include #include extern "C" { #ifdef HAVE_QT_SVG Q_DECL_EXPORT void gammaray_save_widget_to_svg(QWidget *widget, const QString &fileName) { QSvgGenerator svg; svg.setFileName(fileName); svg.setSize(widget->size()); svg.setViewBox(QRect(QPoint(0, 0), widget->size())); QPainter painter(&svg); widget->render(&painter); painter.end(); } #endif #ifdef HAVE_QT_DESIGNER Q_DECL_EXPORT void gammaray_save_widget_to_ui(QWidget *widget, const QString &fileName) { QFile file(fileName); if (file.open(QFile::WriteOnly)) { GammaRay::UiExtractor formBuilder; formBuilder.save(&file, widget); } } #endif #ifdef HAVE_QT_PRINTSUPPORT Q_DECL_EXPORT void gammaray_save_widget_to_pdf(QWidget *widget, const QString &fileName) { QPrinter printer(QPrinter::ScreenResolution); printer.setOutputFileName(fileName); printer.setOutputFormat(QPrinter::PdfFormat); printer.setPageMargins(0, 0, 0, 0, QPrinter::DevicePixel); printer.setPaperSize(widget->size(), QPrinter::DevicePixel); widget->render(&printer); } #endif } gammaray-2.3.0/plugins/widgetinspector/widgetinspectorclient.cpp000066400000000000000000000037271255003167400253360ustar00rootroot00000000000000/* * widgetinspectorclient.cpp * * This file is part of GammaRay, the Qt application inspection and * manipulation tool. * * Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * Author: Milian Wolff * * Licensees holding valid commercial KDAB GammaRay licenses may use this file in * accordance with GammaRay Commercial License Agreement provided with the Software. * * Contact info@kdab.com if any conditions of this licensing are not clear to you. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "widgetinspectorclient.h" #include using namespace GammaRay; WidgetInspectorClient::WidgetInspectorClient(QObject *parent) : WidgetInspectorInterface(parent) { } WidgetInspectorClient::~WidgetInspectorClient() { } #define WRAP_REMOTE(func, type) \ void WidgetInspectorClient::func(type arg) \ { \ Endpoint::instance()->invokeObject(objectName(), #func, QVariantList() << arg); \ } WRAP_REMOTE(saveAsImage, const QString &) WRAP_REMOTE(saveAsPdf, const QString &) WRAP_REMOTE(saveAsSvg, const QString &) WRAP_REMOTE(saveAsUiFile, const QString &) void WidgetInspectorClient::analyzePainting() { Endpoint::instance()->invokeObject(objectName(), "analyzePainting"); } void WidgetInspectorClient::checkFeatures() { Endpoint::instance()->invokeObject(objectName(), "checkFeatures"); } gammaray-2.3.0/plugins/widgetinspector/widgetinspectorclient.h000066400000000000000000000036651255003167400250040ustar00rootroot00000000000000/* * widgetinspectorclient.h * * This file is part of GammaRay, the Qt application inspection and * manipulation tool. * * Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * Author: Milian Wolff * * Licensees holding valid commercial KDAB GammaRay licenses may use this file in * accordance with GammaRay Commercial License Agreement provided with the Software. * * Contact info@kdab.com if any conditions of this licensing are not clear to you. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORCLIENT_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORCLIENT_H #include namespace GammaRay { class WidgetInspectorClient : public WidgetInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::WidgetInspectorInterface) public: explicit WidgetInspectorClient(QObject *parent); ~WidgetInspectorClient(); private: void saveAsImage(const QString &fileName) Q_DECL_OVERRIDE; void saveAsSvg(const QString &fileName) Q_DECL_OVERRIDE; void saveAsPdf(const QString &fileName) Q_DECL_OVERRIDE; void saveAsUiFile(const QString &fileName) Q_DECL_OVERRIDE; void analyzePainting() Q_DECL_OVERRIDE; void checkFeatures() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_WIDGETINSPECTORCLIENT_H gammaray-2.3.0/plugins/widgetinspector/widgetinspectorinterface.cpp000066400000000000000000000026711255003167400260150ustar00rootroot00000000000000/* widgetinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "widgetinspectorinterface.h" #include using namespace GammaRay; WidgetInspectorInterface::WidgetInspectorInterface(QObject *parent) : QObject(parent) { ObjectBroker::registerObject(this); } WidgetInspectorInterface::~WidgetInspectorInterface() { } gammaray-2.3.0/plugins/widgetinspector/widgetinspectorinterface.h000066400000000000000000000041671255003167400254640ustar00rootroot00000000000000/* widgetinspectorinterface.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORINTERFACE_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORINTERFACE_H #include class QPixmap; namespace GammaRay { class WidgetInspectorInterface : public QObject { Q_OBJECT public: explicit WidgetInspectorInterface(QObject *parent = 0); virtual ~WidgetInspectorInterface(); public slots: virtual void checkFeatures() = 0; virtual void saveAsImage(const QString &fileName) = 0; virtual void saveAsSvg(const QString &fileName) = 0; virtual void saveAsPdf(const QString &fileName) = 0; virtual void saveAsUiFile(const QString &fileName) = 0; virtual void analyzePainting() = 0; signals: void widgetPreviewAvailable(const QPixmap &pixmap); void paintAnalyzed(const QPixmap &pixmap); void features(bool svg, bool print, bool designer, bool privateHeaders); }; } Q_DECLARE_INTERFACE(GammaRay::WidgetInspectorInterface, "com.kdab.GammaRay.WidgetInspector") #endif // GAMMARAY_WIDGETINSPECTORINTERFACE_H gammaray-2.3.0/plugins/widgetinspector/widgetinspectorserver.cpp000066400000000000000000000350601255003167400253610ustar00rootroot00000000000000/* widgetinspectorserver.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "widgetinspectorserver.h" #include "overlaywidget.h" #include "paintbufferviewer.h" #include "widgettreemodel.h" #include "paintbuffermodel.h" #include "modelutils.h" #include "core/propertycontroller.h" #include "core/metaobject.h" #include "core/metaobjectrepository.h" #include "core/varianthandler.h" #include "core/probesettings.h" #include "core/objecttypefilterproxymodel.h" #include "core/probeinterface.h" #include "core/probeguard.h" #include "common/objectbroker.h" #include "common/settempvalue.h" #include "common/metatypedeclarations.h" #include "common/objectmodel.h" #include "common/paths.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_PRIVATE_QT_HEADERS #include #endif Q_DECLARE_METATYPE(const QStyle *) using namespace GammaRay; using namespace std; WidgetInspectorServer::WidgetInspectorServer(ProbeInterface *probe, QObject *parent) : WidgetInspectorInterface(parent) , m_propertyController(new PropertyController(objectName(), this)) , m_updatePreviewTimer(new QTimer(this)) , m_paintBufferModel(0) , m_paintAnalyzerTimer(new QTimer(this)) , m_probe(probe) { registerWidgetMetaTypes(); registerVariantHandlers(); probe->installGlobalEventFilter(this); m_updatePreviewTimer->setSingleShot(true); m_updatePreviewTimer->setInterval(100); connect(m_updatePreviewTimer, SIGNAL(timeout()), SLOT(updateWidgetPreview())); m_paintAnalyzerTimer->setSingleShot(true); m_paintAnalyzerTimer->setInterval(100); connect(m_paintAnalyzerTimer, SIGNAL(timeout()), SLOT(updatePaintAnalyzer())); recreateOverlayWidget(); WidgetTreeModel *widgetFilterProxy = new WidgetTreeModel(this); widgetFilterProxy->setSourceModel(probe->objectTreeModel()); probe->registerModel("com.kdab.GammaRay.WidgetTree", widgetFilterProxy); m_widgetSelectionModel = ObjectBroker::selectionModel(widgetFilterProxy); connect(m_widgetSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(widgetSelected(QItemSelection))); #ifdef HAVE_PRIVATE_QT_HEADERS m_paintBufferModel = new PaintBufferModel(this); probe->registerModel("com.kdab.GammaRay.PaintBufferModel", m_paintBufferModel); connect(ObjectBroker::selectionModel(m_paintBufferModel), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(eventuallyUpdatePaintAnalyzer())); #endif // TODO this needs to be delayed until there actually is something to select selectDefaultItem(); if (!m_probe->hasReliableObjectTracking()) { connect(m_probe->probe(), SIGNAL(objectCreated(QObject*)), SLOT(objectCreated(QObject*))); discoverObjects(); } } WidgetInspectorServer::~WidgetInspectorServer() { disconnect(m_overlayWidget, SIGNAL(destroyed(QObject*)), this, SLOT(recreateOverlayWidget())); delete m_overlayWidget.data(); } static bool isMainWindowSubclassAcceptor(const QVariant &v) { return qobject_cast(v.value()); } void WidgetInspectorServer::selectDefaultItem() { const QAbstractItemModel *viewModel = m_widgetSelectionModel->model(); const QModelIndexList matches = ModelUtils::match( viewModel, viewModel->index(0, 0), ObjectModel::ObjectRole, isMainWindowSubclassAcceptor); if (!matches.isEmpty()) { m_widgetSelectionModel->select(matches.first(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } } void WidgetInspectorServer::widgetSelected(const QItemSelection &selection) { ProbeGuard guard; m_propertyController->setObject(0); if (selection.isEmpty()) return; const QModelIndex index = selection.first().topLeft(); QWidget *widget = 0; if (index.isValid()) { QObject *obj = index.data(ObjectModel::ObjectRole).value(); m_propertyController->setObject(obj); widget = qobject_cast(obj); QLayout *layout = qobject_cast(obj); if (!widget && layout) { widget = layout->parentWidget(); } } if (m_selectedWidget == widget) { return; } m_selectedWidget = widget; if (m_selectedWidget && (qobject_cast(m_selectedWidget) || m_selectedWidget->inherits("QDesktopScreenWidget"))) { m_overlayWidget->placeOn(0); return; } if (m_selectedWidget == m_overlayWidget) { // this should not happen, but apparently our object recovery is slightly too good sometimes ;) return; } m_overlayWidget->placeOn(m_selectedWidget); if (!m_selectedWidget) { return; } updateWidgetPreview(); } bool WidgetInspectorServer::eventFilter(QObject *object, QEvent *event) { if (object == m_selectedWidget && event->type() == QEvent::Paint) { // delay pixmap grabbing such that the object can update itself beforehand // also use a timer to prevent aggregation of previews if (!m_updatePreviewTimer->isActive()) { m_updatePreviewTimer->start(); } } // make modal dialogs non-modal so that the gammaray window is still reachable // TODO: should only be done in in-process mode if (event->type() == QEvent::Show) { QDialog *dlg = qobject_cast(object); if (dlg) { dlg->setWindowModality(Qt::NonModal); } } if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEv = static_cast(event); if (mouseEv->button() == Qt::LeftButton && mouseEv->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { QWidget *widget = QApplication::widgetAt(mouseEv->globalPos()); if (widget) { // also select the corresponding model if a view was selected if (QAbstractItemView *view = Util::findParentOfType(object)) { m_probe->selectObject(view->model()); } else if (QComboBox *box = Util::findParentOfType(object)) { m_probe->selectObject(box->model()); } m_probe->selectObject(widget, widget->mapFromGlobal(mouseEv->globalPos())); widgetSelected(widget); } } } return QObject::eventFilter(object, event); } void WidgetInspectorServer::updateWidgetPreview() { if (!m_selectedWidget) { return; } emit widgetPreviewAvailable(pixmapForWidget(m_selectedWidget)); } QPixmap WidgetInspectorServer::pixmapForWidget(QWidget *widget) { // prevent "recursion", i.e. infinite update loop, in our eventFilter Util::SetTempValue > guard(m_selectedWidget, 0); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return QPixmap::grabWidget(widget); #else return widget->grab(); #endif } void WidgetInspectorServer::recreateOverlayWidget() { ProbeGuard guard; m_overlayWidget = new OverlayWidget; m_overlayWidget->hide(); // the target application might have destroyed the overlay widget // (e.g. because the parent of the overlay got destroyed). // just recreate a new one in this case connect(m_overlayWidget, SIGNAL(destroyed(QObject*)), this, SLOT(recreateOverlayWidget())); } void WidgetInspectorServer::widgetSelected(QWidget *widget) { const QAbstractItemModel *model = m_widgetSelectionModel->model(); const QModelIndexList indexList = model->match(model->index(0, 0), ObjectModel::ObjectRole, QVariant::fromValue(widget), 1, Qt::MatchExactly | Qt::MatchRecursive); if (indexList.isEmpty()) { return; } const QModelIndex index = indexList.first(); m_widgetSelectionModel->select( index, QItemSelectionModel::Select | QItemSelectionModel::Clear | QItemSelectionModel::Rows | QItemSelectionModel::Current); } // TODO the following actions should actually store the file on the client! void WidgetInspectorServer::saveAsImage(const QString& fileName) { if (fileName.isEmpty() || !m_selectedWidget) { return; } m_overlayWidget->hide(); QPixmap pixmap = pixmapForWidget(m_selectedWidget); m_overlayWidget->show(); pixmap.save(fileName); } void WidgetInspectorServer::saveAsSvg(const QString &fileName) { if (fileName.isEmpty() || !m_selectedWidget) { return; } m_overlayWidget->hide(); callExternalExportAction("gammaray_save_widget_to_svg", m_selectedWidget, fileName); m_overlayWidget->show(); } void WidgetInspectorServer::saveAsPdf(const QString &fileName) { if (fileName.isEmpty() || !m_selectedWidget) { return; } m_overlayWidget->hide(); callExternalExportAction("gammaray_save_widget_to_pdf", m_selectedWidget, fileName); m_overlayWidget->show(); } void WidgetInspectorServer::saveAsUiFile(const QString &fileName) { if (fileName.isEmpty() || !m_selectedWidget) { return; } callExternalExportAction("gammaray_save_widget_to_ui", m_selectedWidget, fileName); } void WidgetInspectorServer::callExternalExportAction(const char *name, QWidget *widget, const QString &fileName) { if (!m_externalExportActions.isLoaded()) { m_externalExportActions.setFileName( Paths::currentProbePath() + QLatin1String("/libgammaray_widget_export_actions")); m_externalExportActions.load(); } void(*function)(QWidget *, const QString &) = reinterpret_cast(m_externalExportActions.resolve(name)); if (!function) { cerr << Q_FUNC_INFO << ' ' << qPrintable(m_externalExportActions.errorString()) << endl; return; } function(widget, fileName); } void WidgetInspectorServer::analyzePainting() { if (!m_selectedWidget) { return; } #ifdef HAVE_PRIVATE_QT_HEADERS QPaintBuffer buffer; m_overlayWidget->hide(); buffer.setBoundingRect(m_selectedWidget->rect()); m_selectedWidget->render(&buffer); m_overlayWidget->show(); m_paintBufferModel->setPaintBuffer(buffer); eventuallyUpdatePaintAnalyzer(); #endif } void WidgetInspectorServer::eventuallyUpdatePaintAnalyzer() { #ifdef HAVE_PRIVATE_QT_HEADERS m_paintAnalyzerTimer->start(); #endif } void WidgetInspectorServer::updatePaintAnalyzer() { #ifdef HAVE_PRIVATE_QT_HEADERS // didn't manage painting on the widget directly, even with the correct // translation it is always clipping as if the widget was at 0,0 of its parent const QSize sourceSize = m_paintBufferModel->buffer().boundingRect().size().toSize(); QPixmap pixmap(sourceSize); QPainter painter(&pixmap); Util::drawTransparencyPattern(&painter, QRect(QPoint(0, 0), sourceSize)); int start = m_paintBufferModel->buffer().frameStartIndex(0); // include selected row or paint all if nothing is selected const QModelIndex index = ObjectBroker::selectionModel(m_paintBufferModel)->currentIndex(); int end = index.isValid() ? index.row() + 1 : m_paintBufferModel->rowCount(); int depth = m_paintBufferModel->buffer().processCommands(&painter, start, start + end); for (; depth > 0; --depth) { painter.restore(); } painter.end(); emit paintAnalyzed(pixmap); #endif } void WidgetInspectorServer::checkFeatures() { emit features( #ifdef HAVE_QT_SVG true, #else false, #endif #ifdef HAVE_QT_PRINTSUPPORT true, #else false, #endif #ifdef HAVE_QT_DESIGNER true, #else false, #endif #ifdef HAVE_PRIVATE_QT_HEADERS true #else false #endif ); } void WidgetInspectorServer::registerWidgetMetaTypes() { MetaObject *mo = 0; MO_ADD_METAOBJECT2(QWidget, QObject, QPaintDevice); MO_ADD_PROPERTY_RO(QWidget, QWidget*, focusProxy); MO_ADD_METAOBJECT1(QStyle, QObject); MO_ADD_PROPERTY_RO(QStyle, const QStyle*, proxy); MO_ADD_PROPERTY_RO(QStyle, QPalette, standardPalette); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MO_ADD_METAOBJECT1(QApplication, QGuiApplication); MO_ADD_PROPERTY_ST(QApplication, QWidget*, activeModalWidget); MO_ADD_PROPERTY_ST(QApplication, QWidget*, activePopupWidget); MO_ADD_PROPERTY_ST(QApplication, QWidget*, activeWindow); MO_ADD_PROPERTY_ST(QApplication, int, colorSpec); MO_ADD_PROPERTY_ST(QApplication, QDesktopWidget*, desktop); MO_ADD_PROPERTY_ST(QApplication, QWidget*, focusWidget); MO_ADD_PROPERTY_ST(QApplication, QStyle*, style); #endif } static QString sizePolicyPolicyToString(QSizePolicy::Policy policy) { const int index = QSizePolicy::staticMetaObject.indexOfEnumerator("Policy"); const QMetaEnum metaEnum = QSizePolicy::staticMetaObject.enumerator(index); return QString::fromLatin1(metaEnum.valueToKey(policy)); } static QString sizePolicyToString(const QSizePolicy &policy) { return QString::fromLatin1("%1 x %2"). arg(sizePolicyPolicyToString(policy.horizontalPolicy())). arg(sizePolicyPolicyToString(policy.verticalPolicy())); } void WidgetInspectorServer::registerVariantHandlers() { VariantHandler::registerStringConverter(sizePolicyToString); #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) VariantHandler::registerStringConverter(Util::displayString); VariantHandler::registerStringConverter(Util::displayString); #endif } void WidgetInspectorServer::discoverObjects() { if (qApp) { foreach (QWidget *widget, qApp->topLevelWidgets()) m_probe->discoverObject(widget); } } void WidgetInspectorServer::objectCreated(QObject* object) { if (!object) return; if (qobject_cast(object)) discoverObjects(); if (QAbstractItemView* view = qobject_cast(object)) m_probe->discoverObject(view->model()); } gammaray-2.3.0/plugins/widgetinspector/widgetinspectorserver.h000066400000000000000000000062741255003167400250330ustar00rootroot00000000000000/* widgetinspectorserver.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORSERVER_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORSERVER_H #include #include #include class QModelIndex; class QItemSelection; class QItemSelectionModel; class QTimer; namespace GammaRay { class ProbeInterface; class PropertyController; class OverlayWidget; class PaintBufferModel; class WidgetInspectorServer : public WidgetInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::WidgetInspectorInterface) public: explicit WidgetInspectorServer(ProbeInterface *probe, QObject *parent = 0); ~WidgetInspectorServer(); void selectDefaultItem(); protected: bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; private: void callExternalExportAction(const char *name, QWidget *widget, const QString &fileName); QPixmap pixmapForWidget(QWidget *widget); void registerWidgetMetaTypes(); void registerVariantHandlers(); void discoverObjects(); private slots: void widgetSelected(const QItemSelection &selection); void widgetSelected(QWidget *widget); void objectCreated(QObject *object); void recreateOverlayWidget(); void saveAsImage(const QString &fileName) Q_DECL_OVERRIDE; void saveAsSvg(const QString &fileName) Q_DECL_OVERRIDE; void saveAsPdf(const QString &fileName) Q_DECL_OVERRIDE; void saveAsUiFile(const QString &fileName) Q_DECL_OVERRIDE; void analyzePainting() Q_DECL_OVERRIDE; void eventuallyUpdatePaintAnalyzer(); void updatePaintAnalyzer(); void updateWidgetPreview(); void checkFeatures() Q_DECL_OVERRIDE; private: QPointer m_overlayWidget; QLibrary m_externalExportActions; PropertyController *m_propertyController; QItemSelectionModel *m_widgetSelectionModel; QPointer m_selectedWidget; QTimer *m_updatePreviewTimer; PaintBufferModel *m_paintBufferModel; QTimer *m_paintAnalyzerTimer; ProbeInterface *m_probe; }; } #endif // GAMMARAY_WIDGETINSPECTORSERVER_H gammaray-2.3.0/plugins/widgetinspector/widgetinspectorwidget.cpp000066400000000000000000000145151255003167400253400ustar00rootroot00000000000000/* widgetinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "widgetinspectorwidget.h" #include "paintbufferviewer.h" #include "widgetinspectorinterface.h" #include "widgetinspectorclient.h" #include "ui_widgetinspectorwidget.h" #include "common/objectbroker.h" #include "common/objectmodel.h" #include "kde/krecursivefilterproxymodel.h" #include "ui/deferredresizemodesetter.h" #include #include #include using namespace GammaRay; static QObject* createWidgetInspectorClient(const QString &/*name*/, QObject *parent) { return new WidgetInspectorClient(parent); } WidgetInspectorWidget::WidgetInspectorWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::WidgetInspectorWidget) , m_inspector(0) { ObjectBroker::registerClientObjectFactoryCallback(createWidgetInspectorClient); m_inspector = ObjectBroker::object(); ui->setupUi(this); ui->widgetPropertyWidget->setObjectBaseName(m_inspector->objectName()); KRecursiveFilterProxyModel *widgetSearchProxy = new KRecursiveFilterProxyModel(this); widgetSearchProxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.WidgetTree")); ui->widgetTreeView->setModel(widgetSearchProxy); ui->widgetTreeView->setSelectionModel(ObjectBroker::selectionModel(widgetSearchProxy)); new DeferredResizeModeSetter(ui->widgetTreeView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(ui->widgetTreeView->header(), 1, QHeaderView::Interactive); ui->widgetSearchLine->setProxy(widgetSearchProxy); connect(ui->widgetTreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(widgetSelected(QItemSelection))); connect(ui->actionSaveAsImage, SIGNAL(triggered()), SLOT(saveAsImage())); connect(ui->actionSaveAsSvg, SIGNAL(triggered()), SLOT(saveAsSvg())); connect(ui->actionSaveAsPdf, SIGNAL(triggered()), SLOT(saveAsPdf())); connect(ui->actionSaveAsUiFile, SIGNAL(triggered()), SLOT(saveAsUiFile())); connect(ui->actionAnalyzePainting, SIGNAL(triggered()), SLOT(analyzePainting())); connect(m_inspector, SIGNAL(widgetPreviewAvailable(QPixmap)), SLOT(widgetPreviewAvailable(QPixmap))); connect(m_inspector, SIGNAL(features(bool,bool,bool,bool)), this, SLOT(setFeatures(bool,bool,bool,bool))); // NOTE: we must add actions in the ctor... addAction(ui->actionSaveAsImage); addAction(ui->actionSaveAsSvg); addAction(ui->actionSaveAsPdf); addAction(ui->actionSaveAsUiFile); addAction(ui->actionAnalyzePainting); setActionsEnabled(false); m_inspector->checkFeatures(); } WidgetInspectorWidget::~WidgetInspectorWidget() { } void WidgetInspectorWidget::setFeatures(bool svg, bool print, bool designer, bool privateHeaders) { if (!svg) { delete ui->actionSaveAsSvg; ui->actionSaveAsSvg = 0; } if (!print) { delete ui->actionSaveAsPdf; ui->actionSaveAsPdf = 0; } if (!designer) { delete ui->actionSaveAsUiFile; ui->actionSaveAsUiFile = 0; } if (!privateHeaders) { delete ui->actionAnalyzePainting; ui->actionAnalyzePainting = 0; } setActionsEnabled(ui->widgetTreeView->selectionModel()->hasSelection()); } void WidgetInspectorWidget::widgetSelected(const QItemSelection& selection) { QModelIndex index; if (selection.size() > 0) index = selection.first().topLeft(); if (index.isValid()) { setActionsEnabled(true); // in case selection was triggered remotely ui->widgetTreeView->scrollTo(index); } else { setActionsEnabled(false); } } void WidgetInspectorWidget::widgetPreviewAvailable(const QPixmap &preview) { ui->widgetPreviewWidget->setPixmap(preview); } void WidgetInspectorWidget::setActionsEnabled(bool enabled) { foreach (QAction *action, actions()) { action->setEnabled(enabled); } } void WidgetInspectorWidget::saveAsImage() { const QString fileName = QFileDialog::getSaveFileName( this, tr("Save As Image"), QString(), tr("Image Files (*.png *.jpg)")); if (fileName.isEmpty()) return; m_inspector->saveAsImage(fileName); } void WidgetInspectorWidget::saveAsSvg() { const QString fileName = QFileDialog::getSaveFileName( this, tr("Save As SVG"), QString(), tr("Scalable Vector Graphics (*.svg)")); if (fileName.isEmpty()) return; m_inspector->saveAsSvg(fileName); } void WidgetInspectorWidget::saveAsPdf() { const QString fileName = QFileDialog::getSaveFileName( this, tr("Save As PDF"), QString(), tr("PDF (*.pdf)")); if (fileName.isEmpty()) return; m_inspector->saveAsPdf(fileName); } void WidgetInspectorWidget::saveAsUiFile() { const QString fileName = QFileDialog::getSaveFileName( this, tr("Save As Qt Designer UI File"), QString(), tr("Qt Designer UI File (*.ui)")); if (fileName.isEmpty()) return; m_inspector->saveAsUiFile(fileName); } void WidgetInspectorWidget::analyzePainting() { m_inspector->analyzePainting(); PaintBufferViewer *viewer = new PaintBufferViewer(this); viewer->setWindowTitle(tr("Analyze Painting")); viewer->setAttribute(Qt::WA_DeleteOnClose); viewer->setModal(true); viewer->show(); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN(WidgetInspectorUiFactory) #endif gammaray-2.3.0/plugins/widgetinspector/widgetinspectorwidget.h000066400000000000000000000045451255003167400250070ustar00rootroot00000000000000/* widgetinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORWIDGET_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETINSPECTORWIDGET_H #include #include class QItemSelection; class QModelIndex; namespace GammaRay { class WidgetInspectorInterface; namespace Ui { class WidgetInspectorWidget; } class WidgetInspectorWidget : public QWidget { Q_OBJECT public: explicit WidgetInspectorWidget(QWidget *parent = 0); ~WidgetInspectorWidget(); private: void setActionsEnabled(bool enabled); private slots: void widgetSelected(const QItemSelection &selection); void saveAsImage(); void saveAsSvg(); void saveAsPdf(); void saveAsUiFile(); void widgetPreviewAvailable(const QPixmap &preview); void analyzePainting(); void setFeatures(bool svg, bool print, bool designer, bool privateHeaders); private: QScopedPointer ui; WidgetInspectorInterface *m_inspector; }; class WidgetInspectorUiFactory : public QObject, public StandardToolUiFactory { Q_OBJECT Q_INTERFACES(GammaRay::ToolUiFactory) Q_PLUGIN_METADATA(IID "com.kdab.GammaRay.ToolUiFactory" FILE "gammaray_widgetinspector.json") }; } #endif // GAMMARAY_WIDGETINSPECTOR_H gammaray-2.3.0/plugins/widgetinspector/widgetinspectorwidget.ui000066400000000000000000000062521255003167400251720ustar00rootroot00000000000000 GammaRay::WidgetInspectorWidget 0 0 732 528 Qt::Horizontal Qt::Vertical Preview Save as &Image... Save currently selected widget as image. Save as &SVG... Renders the currently selected image as SVG vector graphic. Save as &PDF... Renders the currently selected widget in to a PDF file. Save as &UI file... Saves the currently selected widget as a Qt designer UI file. &Analyze Painting... KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
GammaRay::PropertyWidget QWidget
ui/propertywidget.h
1
GammaRay::WidgetPreviewWidget QWidget
widgetpreviewwidget.h
1
gammaray-2.3.0/plugins/widgetinspector/widgetpreviewwidget.cpp000066400000000000000000000037061255003167400250130ustar00rootroot00000000000000/* widgetpreviewwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "widgetpreviewwidget.h" #include #include using namespace GammaRay; WidgetPreviewWidget::WidgetPreviewWidget(QWidget *parent) : QWidget(parent) { } void WidgetPreviewWidget::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; update(); } void WidgetPreviewWidget::paintEvent(QPaintEvent * /*event*/) { QPainter painter(this); const qreal scale = qMin(1.0, qMin((qreal)width() / (qreal)m_pixmap.width(), (qreal)height() / (qreal)m_pixmap.height())); const qreal targetWidth = m_pixmap.width() * scale; const qreal targetHeight = m_pixmap.height() * scale; painter.drawPixmap((width() - targetWidth) / 2, (height() - targetHeight) / 2, targetWidth, targetHeight, m_pixmap); } gammaray-2.3.0/plugins/widgetinspector/widgetpreviewwidget.h000066400000000000000000000031431255003167400244530ustar00rootroot00000000000000/* widgetpreviewwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETPREVIEWWIDGET_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETPREVIEWWIDGET_H #include #include namespace GammaRay { class WidgetPreviewWidget : public QWidget { Q_OBJECT public: explicit WidgetPreviewWidget(QWidget *parent = 0); void setPixmap(const QPixmap &pixmap); protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: QPixmap m_pixmap; }; } #endif // GAMMARAY_WIDGETPREVIEWWIDGET_H gammaray-2.3.0/plugins/widgetinspector/widgettreemodel.cpp000066400000000000000000000040551255003167400241040ustar00rootroot00000000000000/* widgettreemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "widgettreemodel.h" #include #include #include #include using namespace GammaRay; WidgetTreeModel::WidgetTreeModel(QObject *parent) : ObjectFilterProxyModelBase(parent) { } QVariant WidgetTreeModel::data(const QModelIndex &index, int role) const { if (index.isValid() && role == Qt::ForegroundRole) { QObject *obj = index.data(ObjectModel::ObjectRole).value(); QWidget *widget = qobject_cast(obj); if (!widget) { QLayout *layout = qobject_cast(obj); if (layout) { widget = layout->parentWidget(); } } if (widget && !widget->isVisible()) { return qApp->palette().color(QPalette::Disabled, QPalette::Text); } } return QSortFilterProxyModel::data(index, role); } bool WidgetTreeModel::filterAcceptsObject(QObject *object) const { return object->isWidgetType() || qobject_cast(object); } gammaray-2.3.0/plugins/widgetinspector/widgettreemodel.h000066400000000000000000000033311255003167400235450ustar00rootroot00000000000000/* widgettreemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_WIDGETINSPECTOR_WIDGETTREEMODEL_H #define GAMMARAY_WIDGETINSPECTOR_WIDGETTREEMODEL_H #include namespace GammaRay { /** Widget tree model. * @todo Show layout hierarchy instead of object hierarchy. */ class WidgetTreeModel : public ObjectFilterProxyModelBase { Q_OBJECT public: explicit WidgetTreeModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; protected: bool filterAcceptsObject(QObject *object) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_WIDGETTREEMODEL_H gammaray-2.3.0/resources/000077500000000000000000000000001255003167400153275ustar00rootroot00000000000000gammaray-2.3.0/resources/CMakeLists.txt000066400000000000000000000015601255003167400200710ustar00rootroot00000000000000if(UNIX AND NOT APPLE AND GAMMARAY_BUILD_UI) install( FILES GammaRay-16x16.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/16x16/apps" RENAME GammaRay.png ) install( FILES GammaRay-32x32.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/32x32/apps" RENAME GammaRay.png ) install( FILES GammaRay-48x48.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/48x48/apps" RENAME GammaRay.png ) install( FILES GammaRay-128x128.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/128x128/apps" RENAME GammaRay.png ) install( FILES GammaRay-256x256.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/256x256/apps" RENAME GammaRay.png ) install( FILES GammaRay-512x512.png DESTINATION "${ICON_INSTALL_DIR}/hicolor/512x512/apps" RENAME GammaRay.png ) endif() if(APPLE) install(FILES GammaRay.icns DESTINATION "${RESOURCES_INSTALL_DIR}") endif() gammaray-2.3.0/resources/GammaRay-128x128.png000066400000000000000000000444351255003167400205000ustar00rootroot00000000000000‰PNG  IHDR€€Ă>aËsRGB®ÎébKGD˙˙˙ ˝§“ pHYsÝuÝu¬‡ĂtIMEŰ ("˘Ü: IDATxÚě˝y´dÇUćű‹3ĺxçTĄy¶$Ë’AÖ€m< OŘ€1“ŘŔëMÓđX7óÄŽ=|űŰ{ĂK——./]^şĽtyéňŇĺĄËK——./]^şĽtůWt˙RŘ‘#GŘľ};˝^ďbcĚŤŔśž®żÇZ Đ‘Rî©×ë{Ž;ĆÂÂÂKp˘ËňňňŮyžTń c €=ÍŻ„”ŕRę[gggżü’L\öîÝK­V»Rqź1Ćţ r+ĄJ©ďÜľ}űM/ €ż<ńÄDQÔ˛Ö.ę_˛†+„¸x0!ŢgAJąéxŐżďŻVqď%—\ňʲk×®ťđÔSOý”âׄ(Ą6-N±Đ“ Y˝ÝęţVŻmő)%ĆrÁžď¶¸/Ą,ŻJ)¤RH!Ę…7Ć`Ś!ĎsňS]äÉĎ<ßk„!˝}Ë-ŕŘŞćF<}T#€/<¬ůĐýtďO?ô!ň/} c-Zk666ÄńăÇí3Ď<óÇ'»ř§µ¸ë®»ĂđZcĚ­ő&Ő-ܧC'w›[Şb§ň Uď_3*öŢZ3zľPÝ€­Ť˙±őß× V0¤tßßj2 ˇc-B€6),VHLž#”ÂS.baŞÂ0ü–4M?űš×Ľć_¶ ¸÷Ţ{?–eŮ·şs:rÎŽ//sß#ŹRo4©śbwßú{väĽiŁËÇÖŰZ¬ˇ9=Ggy !%ָϩ@ˇóÜ ĘčCcYńĽµ– ȲܟčŃwp÷…`ËC(ĄČó|<Đ}’ŕ›De« !čv»|âÓźćOnú—^q9Iąź+*ŰZ0VÇ ýnĎť`a±Ć]Mžqö•ßŔÓ÷ŢĺĽr,FŤťőuwDc1Xڵ` ÖB”$몍ˇŮj±ľľćžňž»±N›x±Ö˘ŤaŞÝfmuu$WÖý ¬e8Ň9r¸Őââ .ŕň /ŕßýn’$®š#!Ą|ÝÉžŔčt:ßU«Őţúk‚0…ŕî»ď¶EČTČÁ`0 ž$Ô“×ç»Ň…VÖ˙óç˛ô˘ă("Í2g¤D °´¶íćşoţ&T"¤DHIś$hť#©$R)” * ®×řřďü6‡źyĆ-†1´¦§ ™Ť1źÁ… Ü{µÖLµ›čá„ôfŔZrťłôÜ3€ íV‹z­†±ël‰¨âwÜqÇÜő×_ü”€›nş‰ßú­ßŠ„ťçůׄӇa1¦TĆ„‰¤Ô›M?úAˇÂ!‘ˇĘD!FD J!ĄBykHÚŮ@…!B)¤’Ř,ĂRĄ.nWŞŚáő°Ďż÷Ý|ü·ĹXkâ0P^ F;ßęYżřN‰h˘(FmS#m…Ďî}’Ů…íLOM1?ż@^`ĹŁéĎI|Ęi€wľóť<ţřăďŹă­ő×äôV Ŕ°?d÷EF1RI˛,#Šcşť Â0 ׆öô4é0%iÔRpřą`léj 79ÖH$m$AˇókCż@NĄK@Ëî‹.˘6;ËŃçö05=ÍĘńăŢ8łPAaŚ6€!Ď5łsó¬,-!¤G…`ńŔ~Ö——K­…ÎŮč¬Ăt{Şy˘Hćź]öěŮĂ>8µk×®Ęóüy!ÚŻ&tŰ &ϬCµpaV¦-A­îť9čöű„QÄz§ @cn)dy"“VÓ›F*…P !qśë)Ý®R•¦@Rđ¦úa>đó˙…;Eb­)}a«¨ ĹXJ˙ 4@wuŤőăÇÁ záşK!·Ü'˙łŔu×]Çúúúű‚ xžEűęýMÇ3†é;k5”RDqŚŃ+śŞUÂA°™ÖÎł–˘ô Š“·§í(Z Â8A›Ľ„p…DI Â0b×…ń o~wß|łő,ŕcţĘî/oÜß÷N% óŚCĎ=;ľř>2R”ÎVĂdh|J!ÄżOÓOjŘąžčńV ^,zˇęĆ„Ŕ‚Ĺ037GŁÝÄ‹R?©9:ËÉsgËëqŚŽ˘ńČ؇AŁâŘí~˙| şŕ–X°6‡ˇ‹ŐŤ5z,ň¶÷ţďÜvÓM0oÁ€'“#đfÁ„’ě{j݇7ź€L(ť’Q@§Ó!‚ řš Ó ¬ ¤VHÖ——évÖ‘*D€~żŹ1†,ËŔZÂ0d8 ‘h[8flNŰD¬Üb´ŁzŤ´ß}G;ú®Úh´”Č `aa»Ó8ţ¸Âű Ţk÷ŽźĹ”‘Ź, ‡ź{ťe[ €s÷ĺ˝U~á´ŔN$­'#Ĺ…8Ń{‡ő°E†$IÄp8DJś×ďO¸±^ Ł+ ŽvďA`ŚEJ[Ć+Âx!0€D`„AZ‡@‰kŚ(َ’ÚuÎ#Ąýꤵ•e:«+›U˙ ĽÉÝ˙bLěiUsř“vo2…«Ť&Ď2ş™¦ßZŁŽ@N¬µXaĐÚŚĐBë0>m5)m©3ĆçµűŚśđ‹)<¸čv»;ž©j&;Ę Tw?cŞß’g)Gź{Âđ…vÎTý”5_ďĹßJňÇN1č<§Ńl„&×^Ĺ Â `8`ĄÂhíLD!…¢Ikmh&ĉs3˙ťŁŤF ‰ťř.Ö:çÓú<®Gs±řxäŔ1¦=·ßí|[}×f»/}Ţâů4ăż(ľĘ)žJľWÁR”ťkú˝.*•î‰QĆír ‡Î™ŇZť® čltd0&T&7 ¬łĂ…‚pËkl%5`KumG‰Żţ‹×] •b˙łĎ2=;3Ę÷ż§* žk!L“jRCž¶°•şßę‡mi÷<č2č ÉR¶…aÎrúYN-Nô†­1Ć©ů@)˘ )Ń>ŤÁ€>¡mRb¬E…*ő¬#‹km@:•\ŞsáLŔčVP Rü{˝V–ŐăK :äÜ‚3->Ěĺ'|Ř'Ýk.’˛Ď ’ťöđB’<N„Ę­ !­VËgćý^k,A' arŕ™5„T ˛őV´&ô‰•"¨äĐťedąö)Z—7ĐF#¬Zk„c¨ź69/¤ßwšÂ%>G÷p{ZXČ VŤ›ŠęGzŃ`Ĺ&ű˙b/§śc<Ŕ"NZH¶:őZݡ€iĆúęÖ¤ °ZŁsŤ6„EIER«a‘,Q%aÇ1ŇcůRŐIÓŚ(ŠBşť(‘Ś\2I(˘(B…!JJvîÚM­Ůdű®3+™HúxŐo´áą§źb÷…`ŤĄŮn#.8ß ‘­ć˝%0ĚNĎ0»°ČÓ+ śjŐHÂYŕb"¨…ł#¶v& ± ţ¬fţ>é0őĄK­®|č§öűX qÓďwář#>ů’gCftNŻ×EH…±–<Ë“„n·ŹR„DJ ×mȵfńđ!j­Gň!ĄqćŔ\ űźyŠ~ŕL‚Öě>ç\íˇäw <ňAźµŐsiĚN?Żv<ĺŕÜ·˙'Śu8šŐ.>¶¶¸Í}xd°&÷·kÁsÓsëë<đé?dµł1®*dŤĆjQÚ`c y–y»o_ŘKë’řëëήg9Yn謮"ĂĐ/–0Jüw’.ck„×îŐÚŇĆăÄq§N %,=F0(‘Q-¬»/ô,e|Yęa2)DIč{ţśČ)$íF\‘ĐIp ëň⹏żŤó¬'ß‹aąBŰ:QślµÁ†.ElĽpa@î±ô<ËËE)A—f¶X©}˛G–»×mF÷Ť©ÁJď§°8Ňc€ŹwâüŁaŻĎńcÇ*¨¨yçŕ9E(7ý:MH'pB€‘'̉ś¶N ĹňożűMtz}î~č ~rźcꔀŠ-‚§M’/Ş@NŃB’$)ĐÚF62´g¦0ZŁ”bĺ8¬­¬8U®$a BI…Ôę5´qD9'LF8Či°F`ŤÂčÜEÚŽŇ _ľ¸Ýż?*&Đ-.R‚G‹‰"a™ś-€ › <ĺXÁJJ/-óţ nĽţ*šŤ„׼ň jIĚ÷Ľĺ5,ĚL“fďşńµ¤Y6öc­Wőĺ‰Ď5é`ŔńŁÇX[^%Y[^eůŘűź~†ýĎ<Ë‘C‡Y>¶äâ­öh­É)Ú^˝ ŽcÂ(&Žb’$!Šc”'eZă˘Gó˘Âó3PHHĹçöůäRő*ý­*L+Řd}šYxźCú0±şzU'đĹ„§śkyýµWňďżď­[YăGżű­|nĎ}üŘ÷ľ•ßý«OňýßţFľ÷­Żçď>ż‡0Ořc˛BăÖť“¦)Fkd ¨ŐëÔ›Mâ8qŻçş|ŻT c´#t3„HĄ\4!%R*âZBE„qâ?Ej×ŘŚďz!$ÇŽ.’¦©3-˘zu¦DzŰ.„Dââý‚ŁPţł|2ę§ś Bpëťňgż•@ÂŹ~Ď›XítXëô©%1K+ë´5úÇWÁb, c„ő €¨Ý& z˝VW¸úQD˝^cfŽ˝+:Ë]ün-ëk¨áŔG aëë(ĄüŽ!·c=»ÇŃ8ý®÷|Di-˝^Ź•ĺe•T‚ś”ÜÎŻţQÁFřHĹá=]ł[]z!Íz‚Öšĺµ.őZŤĹĄeŢý¶×Ń ¸ý+ňS?ţŇ,›myRÎűZSk4čv:>ő;$ Ö×ÖÁŔ°»Agu „ H‡ę%Ję$őA” TŕDŇbł­%*Ś1(„0H+Čc5.ŔÝ †Cl˛űcQ°~·Ë ÖoË<ÂCÁR–ÎâÉâ"§´T6–›o»)ťCvÓgî Y‹ůÄçżDo0$ JŔŻ˙އxď[ŻŁŰŽ ésä·‚l©E%ŮBJ‰5†´×ĺő?ű˙`D1|äżţ7dâ$~ňC8! O‡\űŢD§î»~ţ÷ţ'*©ąĹ/¸xZŹ?Ĺî•’çö=;ŠíO„pÇLF‚•r¤°ŁRR"…ŘŇ>5ŔJ§‡®¦@uîTĄÎ=Q˘Šhú9§Ş{&w»k0łýeŕĐđ>Ň’$N›ÄµÄ‘:ÂŮů9V—\h÷7˙éçš-˛—_IüÜ>TRsĹ~ÓiĎĎ[9ď|ľüĘŇÁĽé§~ž\k¤6:rÜ€Â(°)%GŃąU,Y›…@WµTj€R±‰ŠŕŚ’PlÁ¤:eIˇ>ů˙G!˘Ěu‹čq´ďD—[ną…‚c” á"ýf´Ćh8řÜs( •$úRĐŰŘ  b¨OM4[¤­&¶Ń`07‹>ë,ÔcŹŁ/ľyđ f}ť4аALXo˘B—Á«Ő }rŁQĆeľ|ۧ˘××7X9ľäŔ¤ŞŹb7٠öćZc°ďá'ĆřMa7ő 8uIˇ«ťA>Ůa« ŕV_0&ůĆŢőV“0ŽB°űěłIł%Ň<¬­¬1ÜůHŁ5­ĹD!ę‚óÉ_ő*—öÝ˝›Dč‹/BÜů%‚4C+I­9Ĺmđű´§gJŃjµR%1AśP«ŐĂÝgťMžg\ř˛ËJůŐ”›ŹâĆXĂÔÔ4^r‰ă”„*[Ř0;;ĂüÎťČ^wtJk€“éÖ1™ó!Ůdüvt{ {=Ś…Ď=ç2aD”ÄžŐŁŃFĆ K‰Eo߆ę÷Č_~çŤë4E4jN›\x!ćî»96;‹Í3’ő˛?D*ź)’ZŁN9qžçÜuŰąřŻŕé§ž*yv+»_„ŔZsŢ…ňĚÓOo&Îza°B0čwYÝ}&ÓI¸éĽśŇ>Ŕ×’óßę˝'lÜ @kÇü5Ć"qjUËŚ<…t8@ç9išŃśžˇŃëbŤapÖYČm %z§´v|~a‘ óČ$aúŘqÖĹYž!_I$%: ś/ 3†>¬Ż‘‡ča­ đ" fçČČIÇ+0y†ÎR¬ ĆĂżJâĚęÎ0y~NKRč I쉴Ă$)´ÄÁµć˘ë^Ͷó.… bÇY» ˘á0cjvŽLk¤ŠPqŤc÷|Ž©l†LŽ n7Ç,2}~ç¶… @žˇµášwýy:(Y@Rą(D Ůžć=żţ‡,,,püř’٧yň‰É]®#׹{śąçłtČěÜBĐĂ>ń$âĚÝN¨ulŻŹt0GŹ./“…‘Źń-RE®,Ě›F¬­®˛ĐžBµ&I˝N\oú»EQÇč±Öš0Ž ăšwO#Y0„B©MAŇ)VĄódíüć×+iő DUxôŽ k=óňa†ÇŹ#Ë2t®©7ę z}´É‰’HÉÚ‘E¦° /kµ„ü©§ŘX7I/ΧŃÖ_5SÓSśyîyśuţyěŘ˝›…í;8÷‚sů®_~3łÓLĎΠÎÜMíđaÄŃcěűôͨ$fß'?‰ěő‘OíEďŘé:ut{|ßýEŇ~×7YNgcĂ/¬ô[ÜĹü˘¤Ś źޤx‹«ÝwďÄUVŇ"s(EY¶é·ź.aŕÉ€>ĹĎĘsÍĆĆ€4ÍJÇË™­ü‰‚Jĺ«pŚĺČâÚSm­5ë««čtȵ)ú˿ʱĄŁ„a„¶‚AšşLŁľşŘ‚ Úő-Ěň|ÄđË&ËZěbíůţ®5ě «¦±ľ«™ÁĘqđ«é‘xęEXŽ_'äÔk5” ¨ŐBßOשţ pmŇ´Ö%Ä:i šíµFĐW˙¶ŰmjőşoQ°,Ív ˇb®¸Ë±~\;6a ó۶ŐĺBÔ âf ¬Ął±ÁL˘‚4§¦öĚ4q­ĆůW\ÉÜü<—]~ĹX„˛Ů´ĄĐNĎÎň˛Ëݍ8“vÔVÎ7‘ź™baçN†KGƢ€ŞF=írBÖ;¬®ô¨ŐjIěą‘Î9?JÇŮÜ|YůD@oŁËĆF‡a–łjVĐZ3‚€<Ó¤yćŞů¬ˇßë‚r¤ŃV»MžçdYŠ49ÚúĂÁĐ5„ CŽ;ÂĘňŞ«3 "d¨Pa@¦ A!€4ňÔăŹŃž™á‰''T™vě˘QáWńżÖ9_r)O>ůÄf)WÚŇ_çü3ΠVé2iO›ÚŔÁ;zl…ţĐ$±ŹžF /˝cTôś¸ÉVęăž°;YIÓšž&Ë2Ňţ€ÖôĂÁv’g9µzťÜ‚ dĐ)Ół3¤ý>Ę›ă¤^GkG)ĹňŇ2*P®(DQćđH…PŇűžąS”–YᙼžPÁÜNu/ĂBF‡÷…u}‰¤“Se ťňŮŔ­.J)Ž.­rĽíšň…‘rÄ€•ř[QéË#\eÎ UݦłŚ^·‹Îr¤ô{=´5¦×ëF!Ňł~ÖVWŃľ’(M )ť.ąÁS ßëŤ:„"G°®w<…tdN[PşĘ2·"I¨e¤Í)<«I8jXáü‚3Ćń·SđŐ4ŢúgÇz˝.é`™zśÓ×ҵg©Äúwöß B±řE”°éGyďkIÓ!ËÇŽ±}÷ ÓssDAÄôÜB ŇaʑÇ8¶¸‚©ŮYâ$¦Ţ¨†n7JĄÂĐť~ëFőFłdőâźHĺvŻđ_DThß¶¤K?@”ý ‹E•÷V±[^«8Ŕf!lL}JGJ,-$‰C¤’YÁ O§”’(%J3 ˲葼ýMˇŹyăRHč!ňLłxčé EcáŚÝgŃY[#ô5‹*ɆC¤”tűjőµ¤†pěŘQvźŮ&NšŤůęŞhd˙yŞ»ľ`ăZË2´›B×č‘'t’ťö•ăíeN‹l á·¬­Ąą*]) 59$˝ĽF`+E—rôŁ `+Äőô-N“gŇ`Ń:g×yç ‡ô:]¤ěfŤé)fćf‰ë ÍV›^݋цůíŰö´k ÓÓ3 i–rÎůçŃjMˇ…Óý®ë ŕw©řäĐhçW9˙”j\”€ĐX}¬CĄ‰ĹZ±%xö|Ąň§¤ ¤¤żÔ#T ˛–#â !AÉ”éPĐĎj¸Żű9QäBÁÁ`@Gc\ŔŞV ÚŘäŽĹ ťőu.~ůE9+Ç—éuűLÍLłtl‘ÜtžŃí 8ľ´Dwbq]I§§78Ľx(N‚€8IFöWźĄ“›*~śz-ú*Ę]Ť´cź•[fOŽzJö ¬^˛,C A$T¦‰F&"´´CX^Đ®×iµš#Ő(Y–Ńéll 7űEk6ËŃĂ‹ÄIŇ‹>xl0d~Ű6ŇaJžşRpk-ÝÎÖhŇńWíý#&’AŐcĘ-I#¶jNžŚ ă@ßôHŽÝJ)1:' ]1¦ëôˇ”đ^˙¨¦~’]8OĆXęŻzgž!Ń(Â0"Ď5Q˛±Öanaž™…yň<' c––ŽÓlµŘ÷ě3ĽĚ›«Yžř*bă&F#ŚD(ŠAŠ<ľ§•icČŇ VŮ@bÔ:LŔěěRIŹ`Ś!Ő9Š‘?c­!Žc„®Ýťď9¨NŔ8esUďUŠQřT˘eĘŁhRB–vĚ‹Šä¦ŢAĎ×)´ŐjÓLj©6Ť+®`ľÓAĺž^. IDAT¦9Q-˘ß룂3vźI0ŕśóÎ#Ks’$A…!Ćâ8dŞÝćU×]ďŘB:ť fćç‰â ]Ç0Ą\.@´¦§™šť#©Ők5.»újćççyĹUŻ()^xź (éşćŻ!‰cÍý÷?ŔË/żb,˘‘"൯y5áĺĺă,<Ŕ¶ť;Y}îŮ-Së§)T)×IK–¨źGř|´0T>Ůă ×<Ď ”BŇĎŐIÇđ€IP¨ŰÝ Űë1¸ç>ôÚGňŚZ˝N­Ńp˝~j ĂaĘÔô4GŁTHwc Ł<Ď9żłÎާö’ĺ.C'•â\c9tđqŐjÓ J9? Ş×°B ‡<üĐĂ´§fxř‘GPA0†Xk9çěsX__ç±ĹĂlß¶ť™™YfçfąăÎ=„Ë0ZcxĹ•W˛ĽâňźţĚ-Ě·Ű,íÚŤ4ăžţiZkQDçŁ8_)9řÔjuúý>ŤF€0p¦!Ś\‰Ő±ĹĂ~(ŘćńŻ˘Â˘˛«+` ]vÚhâ$AIÉĆĆ Ť:ÓÓ34[-T0 x(ËR˘0`×®ÝĚ.̱ŃíHĹüöíĚ-Ěa¬ĄV«‘kí3– (Ĺôô´C Z—×n…pB -śyÖYÜyçťZ\$Ó9ßńmßÎË/ż‚Ź~üo‰d„0Ě ×]{-Y–sďý÷1L3„rцÝÂ8mśŔVłÉâ‘ešŤ:J!•€sÄ:ťIâbn)%Ţ€ĄcËÔ˘Z9­:kwä69|˝pĚ–ŽĄŃlppß~vl#ËrÖVVlôYYu»k}}ť¤^Ł==í0 «kk_^a¦n€C?eiéaFB‚0BŠ©Ů9TâÔ˙L‰Ž‡……×/„a}mŤCGQa nůěgřöwĽąŮy˝>¸ňĘ+i·§Xďt¸ëž{˝&)śĺęîßjÄí)ť “pĚ+<$ę+ęő:ĂÁăÇWX\<ĘĘę:q#9j4–2§…n¬­®!¤`ĺř*ťŐ5‡K–Ąt76X__g8HŮXŰpŤ|Ur§Óa0’ůBŽ\›r`c1' ěńPdę|('Łxľů„K‚=ôČ#n •ƺ݇ŹáŠË.G ¤)o|Ýh6›üýço%*ş•×-Ř?/¶EĚ?_` ő$&Ë4wřŠTŻÄ\tř°§—Z;ÖL®uYUýˇcËoˇŐn3·ŁA¸Ń.홦f¦ŃYN§ÓˇŃlÇ1gĄgÓínÔęe/ŔFłÉěömĽüŠ+18˘Ć ?`aažCkët{]m™ť™bye•ÎƆďRÉK”ź„§Žp[šG C/.ňŠ+Żäö;÷°sÇ.˝ô~äa~ě1dÁ–”±Ó& ¬~É8é†ÔTRY|á{2´o©®Ť©\}»Uižw¨łµĐôYëöÂÍóŰč÷8p`?FkýÁüÂŹ<ü0a„!TČ0 $W|SÄłĎíVŁ­][tÜ2v¬á“6n8CŃčqËl Ž=.K—$1X¨ŐjXk©7?>.Ś"Â0$PĘg¦¦¦˘€złEŁQÇéE!5d‰ëäięLŃ(©Č-Ô[-"†3ÎŘÁçźGł>ŠV×ÖX^YĺřĘ Ë++_]-'Ś"Ź=ů?űÓ?Áňíďx;źĽůf–WV| [ďÝČ ßŕyZĆ˙ł ŔM»•wľĂ °*{Ăű?đ‘·Oj¦â;Ö’Á ĄŮ¬WۢýîŻm.&{ja6I˙F%Fť˝ĽžR’z‚6†0t?»×íÓlµh¶šäYî'Ér°kíŞéSňnűŘcdçśĂ0Ž,#ëő‚8týťŹŞ€¬@©Ŕ “®¤–v«EŁŮb×ÎťŽé-+kk,-/sřČQ6z]ŽŻtř7?řC´šm>đgNE>Ť,<. ÇĆ/’řŹ&ţřçy×ŰżŮA˝Ö|÷_ßô™÷4›ő·ŐâV#k¶4 ÎvÖ×;4Ť±wˇ7 …ŕůk-.uLŕXFAĐhµĘ˛°ÎF—Ő7‹/Ď5az?@ÂUřz5­¤$Hj¨ĺf,őű$A€śš"đ=‚ĂĐ7ľ‚ÖÄ:çžű ®Ő9Ľ¸ČT»ĹT«ĺ4K9âiž‘ełS3nđŽěÜľöóĂ?đ~˙Ź˙Č!~VyzÁh(¶”3Ń(˛J ý'Ë~âS_ŕ[ßňZ«Kń†›>ţůoԓ••ăöą}O±ÖéC\ăúk.?!IÔ…} «ëë(©śĘÔľÇ_a÷+‚!‹~ű'¨ ÄZf¶íp€Ošb±AH­Ů˘×룆óŰw2=?~U±ű•”4› ’zŤ©ą9?ZÖăAHBeńC]ëë&S`¬!J’8FĂZgŤN·ËţC‡ÉŤ&Š"'ŤSí6­V“ş©3L3â$ćđâ"íV›#‹ąńµŻqÚai‰cË+>…-Ćz"xČ?))ôcźĽ•wĽőutyň‰Ońç¤?Ýn7ÚËËÇě#=Ć‘ĄeęÓł˘63ĎăÇđ…Ű˙źxĎwzϤŤ*ľp«Ů@kM·×'KsGĆ g ´Eç†Á`ŕmâfRhA‘4ÖMúă©ŮY×|Áh˘8F[ŘŐl ¤ VoD1a¨\gbcÝHV/zŰQś¸6łqL»Ýd¶?ôđŻ+¤t\=$IĂÍPR’řä“«t PäÇÁ¬­­łşÚÁ8€¶†vŁIł^§Ńh 8xV˝IžkÚí&íf“‹Ď=‡ŁKËŠ~„[$‹ţ± bÇ +·ę3·ýJď©%1O<ń¸˝ĺ3ad ćvźĹÁ~ĘýwßĚŁÝGÇlô‡¨0@Ľ\YŘň©vËU÷hMŻ?ŔU2‚őyęő_úňmťPý…sŮ&”sěËrÓÓäYĆľh´Ű8°ßuŻŽËb¬g ‚LçĽíMoâń'÷˘óśű}¤QŻŃjÔ©' y®‘Ć+ĺ§—Yđń0đëüíÇ?Ď ×_Íg?×/I)ţsłQăľ{ďâćĎ}žöÂNĚôמzňqZ­ő¤ GµĘWđśřKU3}'Ű; đ&?WśÚ0 ÝôO©X[]eĐĆ!ý^„dnűvŻ‚0DŞ€¤–x3˘µńećŁa<ÓĐ p”4cm™–žhý|°( ‚Đ Š/ q ŽźPT÷z)ĐZsΙgó…Űoăś3Ď& Ýgµµ,Żo°´şF=©1ŐjUF`˘Q–µ†^w=űłżü$?đ˝oýęŕ®{÷ňŤW]@\Ż_~ëďů\GŰÖ׏ókż÷;¤2 XŘÁ­_ŢĂÁűh5[.Żí‡);ŞsÁ’„2DçfKňĹt ©†],“ Ůܷذ·iľú•>TsĎɸ†öË…ŢÂV•ßÁX‹JĚpčź÷m>DE®­-Ă‚HĚpŕĚI…4ęN‰DXŘč÷řÄ÷¸ţG[DGa°÷٧9óŚłůő_űţĎźú9,\˙éĎěů_oţ–ëľëy5Ŕmw>ňťI-úA¬ĺËwíá}ą˙ŃÜŁŘ«łbˇ [ĎháKUëÚŁU2Jş iža´- ş{D…/Ţ»·bÄ’Ö˘„D±‚Čnî“[¬ßL«M»Ů`u˝ăHŚ;\Ĺţ“QB6č— W´}ÁZ҆ ß]ńM™ÝóA2 ë÷ÜDGmť+Ć,VX«“özŁŢż›¸q~î@Tk#-ĄŞ,=SHÜüĂssě?~t“˙T ÇĘóŚ{áąçsűm·ň ßpq˝ëSźŮóŢ·|Ëu˛InşéÓĽóťo&©Eűřó˙ Ź>ó4ÖZ˘0Sź˛ĘăC•…UZłô•˛EĄkžçôzŚQŁF%T#Ť *-PDE”Ĺ€ŠČ‡acDQ ’BgÜvŰí4›Ť2ÓV8SUaJ‘űŮCcÓľ±Ř¨l”s~ î_–eţ±wřŚĹ–Đt!`.TQN+üĹ Ęš(\Śrä9R*‚‚&WŇĺÜůDÂFo@6”çpĽËAŃ<}p?ń‘ŹpýuŻef6ŽÂřÓ›oąÝŢxă #xç;ßĚ_~ôß…Ak­ącĎí\]ĄŰíPKdŃiŰg˘F&@ů2&Y.âäś‚ăžç†ţ`č![1jÄx'-Y!P”…•‚J9”‘1ĺŃŕIä›n¸žkŻż–µőÎDßľÍÎ$Ő"ËRĽ&üÎjÎbŚ×ż•şEź1hüă÷&ĆŢL¬çQPObăI±ŃouťËŚÖtÖVYnOńĹ;ľŔ«ľń:!„źţÜť?să®ýŐM& ®%ď5ĆŘ(ŠÄĂO?ĂÓO=A«Ő®,îČ‹'wHo áľĆŁRČh!Ó9˝ÁĐwş*żř¬¨­ ơ¬+ŘPn"…j­ąř⋨Ő룞ż/âbľ&žś=‰ANâ«ziRž -vď˝÷ŽÇúpQ€ďN űž}šGźy–×|Ók †6 Ă÷› ę‹% Cîyŕ^Gz,8űĄO"FE™rˇ*bTćěs× ňĚĐďśr#a)«h}x'J‚gŃu«ę#¸żcĐv$Ź*)´Ńl2ĺŰĽ _üRŞŻŤďtŇ‹ř5ţ•2޶°Ŕ&˛Öµ”ŇM6U÷=ü`±‘…\¶•¨¤’>Ő*Y]]!PŞ@-KOÔz7˝ÚﮪĆĘçlĹk÷ÝĽÔ”Ý.ĄŻ†•ĹŽ—˘lŞ,·(±.Ţç`đxT÷Lâeŵ“Śâ*<=™dŮę}/ÔžmŚ·Xik3 mőľ1|c Üôô4‹‹‹Ž ­ÓJ”¬®Ż—]Č‚ bjjvjmmy-¨USç©ui玝<ôŘcäQŽR.9â Ňpd­B~2’”N8¤r…!Rˇ|?U&’F9U<ö;×Řą)¸)Ě›h@=Ů ňDź9Ńó'ű™­¨Ú˙T@ű^AZTňú^Mš¦„QÄŁŹ>R€Ş @|Ç{ř®w˝ËŐď÷{üÎ˙ř ~ř˙x˘ÝöĐĄ Bµ,CŘJ„ŕŘľšŢ`ŕÔ<)ł˛–Ţuât±°ë%+­âÄX{8)Ă4ĺŘĘLµęĎ;3oňµ*lüőřĚ ďű»M>/„ 7°těAśöűüĚŹ˙Ýnyž|đ€¨ÔYCŽ5|âď>Ĺ;Ţţ6˛,㛿éŐ|Ď÷ż—żúđ_!Ł뱯jź^Çp’~Ě{q¬O|Ś#Í2rm*ÉŁĘ.Ł>Z|µ©=\aŇaź~řďřη~3gîŢ9Óľe$V}~Â.›J:®’^3“Ô屣Ů˝´é;”ˇĹMĹëëcPĹ'OřŮ­ĂÁ* vřČ1~÷Oţ d逮»ž«Żx9Yę8÷Ţ{O!w[€6˘F|ŕž{ďŰő˛—]*Î;÷l†é_ý…÷qčđ!ľxű ˘…Ŕ 3Ö©Ű Á(¤´~®ťsLŚu›¬-ž—B(|Y–Ó(Ąś)Ň‹YyĽ‘g+娼JĘCŔÍ·ŢÁ¶ůY—n."ř ¸#Kŕw”‡ő泣ď’Jx;‰‰ÍŔŹďC%«ŘĎŘŤ”vŘ Ă>Áă_3nΰ±Ĺ”S[ľ^Ě!2VŹicü\băKŇŚ-'—[ăFX¶Ú-®¬rŃ…ń#ßűnz˝J)ÖÖ×xꩽčú č ‚¬iťţCśÄďľé#ç˝?đ}ĚĎĎŃíőřŕű˙źü˙ýčß@˝Q‰‹$X)JbŠ”Â‡“Ö1‹!äČ!“Žg¬›¶áĐÁŃB Âb­öʵXTrÁ…páŮŰÇýŞruVćôI9„yRÍV„Gôč÷ý%pÜ!9ă:lřÄĂĘCwÝŤqŁdXNÜV…Çz ężJ1 €÷Ú­d÷ÎyjqT2yĄÔj5úşJž•žŁ{ąÂ×u«O[˲aqŇĘĽC…ç0¦„˝%NFä”"Ói=QÄ’ëÜÇ÷ÎŃ ,-v6ݶ^H…6šÁpč´6e¶.Ó9tHż×ăÜłÎćš«Żć5×\KElt7ȵć˛óÎańŕ!ľôĄ»Ů·o?I9‡TX‚$ba÷şçî_żő“źř°ĎÇýö«ˇ $Ŕ6ŕĘ˙ů˙üóóó;Żvz¶×E˝V'Šb¤’ÄaÄî3wrĆÎ$I ­s_ű_ŁŰÝŕă·|š›?˙9ľđ_­ j _5ŚŁ€ŐşáóTĚi€ťół$Q4*B‚8ŠfN#aÄúp€@úq2˘¤ńŃ“7KłŇ“˙˝Šć“EjşÚëĐVΠKż»×Ř"Nw;|ei©ÜÝĹé¦Cçŕĺ9˝~€+.˝”—_v9×\yI­F–§„2$Śň4eńčĂŹŇíöĘ&ÚP±˛ógěĂ´Ďźýöoľ/ĎŇ{E`đ5rPP@ Řő˛WĽň o˙žw˙T=iť›÷¶žÔE­V'ŽW%´ŰM¶-Ě3;;C„®Č×ë'Š"îąďn˝ă‹Üńĺ/qĎ=_q=ýkuWźç“C#A¨:‘…Ůp^ű¶™i˘(Ę6sÓ…IDAT#ź¸N ąăă…Ý4ő,eU:iŐÔrü¸X;/µCQěá:‘UgţQ™äaÇÁakGŞÜ3i:dmeŐw6ń;ÝdkčöşäYÎUW\Á•/{—_zgťq4Eç9V@- Ö˛÷‰˝<ůŘăě{vqś <ůV*KGvnÇvÄÁţ¸ĺSżńđWîľ8¬39\đ«€â˝ˇ÷ v]űÚ׿ĺ›ßú­?ÜnĎ\oôIâőZ$Nº‰FŁĆĚô­V“8ŽČr§ Ą„0t­Y~ěQîľďîyđ~|řaöí}ҵ‘Ťbâř˙oďę~ă:ŞřoćÎťűĺÝ{˝ÎúsÓ$nšH%n¨(") UQ%ú‚„ĂŤ!,ś9·ňęß˙áĺĘń“ݦ˝ TůžO|×7éŁ>VŤ ̦(x® ۶a1Š4ŃA1Ť śsÜş{«7oâÖÝ۸ł~w×ďacc€s¦©\î4oťÖýŇ Gµš5_CĎ#ŠöľOÁľ9űČuşî!ó8$‡tĺ›ĎµL¤z)±ćfŽanvóĺY”§Ë8ľt•Ąă „"¸Í”gBTKhµŰX[[ÇŤO×đŃGWQŻ=„&8±F<ŠŚÂqą*L‡¤Ľ´€vłqĺ/xç7Ż_ű3€m“ŢĹ˙ŽâÇŽB`b„ĺË?ţÉ÷Ξ[ůN––ŇŢÜbcĆŕ€Ź‘1廾—[¶#…Dś¤ĂÍ#Ôpę1¦ź«Ô±±ů›ŰŰŘŢÝÁ^­†˝ýjő:ę 4[M4›qŘ Ă›ň^2Ö‰Lq¤©M ńů·—"Ó˘ śc*B±0…bP@†ÂÓá4f¦gP*Í \*Ł8iĐĆäú"ÍjÁ÷\ĚĎ•0č÷Q­nbgk ۵66ëp?Ŕ ß ÓB·Ű€‰>šÎuT1*’Ůʵ]ݸ˙ÎŰ?˙é/ܰ  c€őź(ńIô(Z&XŚ”ç–*+ß˝üŁ7–Ożđí(*-dýŚXĘw=â{><×…ăxŕ†W'7f6RÚ64‰”ٰ`’Ą’4ˇŚD ŁjQCžI ±DŠf«…NŻ‹^ŻŹn݇8Ť' Ň$qJiÖvťÓ3‹Q 6çp8‡Ë¸®‡Ŕó €†gsŘ65§ «X–…¨XŔÔ”‡~ż‹fŁ…Ćök5lmmáĆęM4[mPBŔŰ„b4B1łzť’¤ %2»´(ą[ŰÝ~˙OżűíoŞî_°gÜ|߬ńęq”÷$…š8!7†RP(žůÁ›o˝~ňô™ ‹‹•s*“p,[ůž6ßőŕpÜáŕ¶.Čd™0é‘@–é+ĄĐHź¨9Ú4ĂĂ«·yg™†Nsw­dSËĂĺUŃ+ˇ]Ľ€$ŇÜo€!ÎŕŘęŐŃ{‚xŁ7čŁß ×ëˇÓí˘Ůh`ŁşŤęÖCłŮĐşł eŠ9”Y(†ÓŁ…(Rţ”OÜ€Ăő8šµŐÝťę•wőöďűűk»oĄ§źilxF ŕ¨10žÁBÇ.^zý•Żó[ߨś8y~vvţÎ8UB€[T9¶G|ĎĂ9,ĘF®Zéŕ,ç‡HEf@“,C&4µ+PFŔLÚHĆ{ö‰qńRBč |Ău\J‘ ¤2ŐE$C’$ččtşh¶:čôúH:w?Ľ'ßĎ ¸1ŠŔŚÂŇs'–/ĽvélĺÔ©çŹÍÎť ĂhaŞÎ~ŕfY ayRRB ©”R¦Ä 5Ö„a%EŢ|‘C±†1Lť¶ĺEib)˛ˇ˛ĄČô)bb ŞUcÝDŠZaśĂq8×ó$Iz»ý~żÚnÜßŰ©ŢýôĂżŻUďŻ˙Ó r=ăŇc™YĎĺÓTÄ—eŹz:¶lئiŃ5WßIxveĺř™ŻĽT™«TÂ0*…BŮóiĆXH()PjM1f3}Č„€Ę2Łh­t%¤6‘Łuy Ú‘üŢ€D–NC Ő«D–eB Ń‘B¶3‘4ýř`ĐíÔ:ťöŢţĂíę˝[·¶nrăYŻsĚŤ+ĎĆf·ú˛żřgYčqXc#÷öŘŕG®AqzşX*ĎŃL)(CźŮÜćçś;\B©Ů'ejő RĘ4MÓ8$i’$ťV«×Ş×{őZ­Ű¬ď·L#ebFjFbšŚýśŻ×bLÉňYü‚źuř˘wÔ G< yÄ•<â˙WcWuDqęČŚ•?žôđČ˙€áüżNЉLd"™ČD&2‘‰Lä‹ĺ_ôĂLzuÖ*IEND®B`‚gammaray-2.3.0/resources/GammaRay-16x16.png000066400000000000000000000016221255003167400203170ustar00rootroot00000000000000‰PNG  IHDRó˙asRGB®ÎébKGD˙˙˙ ˝§“ pHYs × ×B(›xtIMEŰ $3a†/IDAT8Ë]“_huÇ?ż˝»Ý»Ű˝ IĽ\s¦MJŢŞ5‚M°QZjE¬$|0V¨o ˘}«Ąµ †…*Ň@ű"ŠĐ¦ńˇôAŠmúG­pG·Iš?·ŮÝßîíř6)™Ď|™aŘôôôEǶwÜË#­ÉćeÔ=ďĎáááÇéččHm@;ź9wN€@^“{ńý>{ţĽŐjµŐuÝ˙D¤*"ŢĽëĘS##©‰ZĚ'ż\`áć5Ž\śăč•…őŃN€FŁ@0JĄ’ ` u Ş5®_řSߥű•śţq’îŢťë€F €Ö e÷»źA•vb›&/˝Ć‰ń7I›(÷ď"W*sěŤýŚOśä…wާ{pˇż¶ˇ€¬e’ďí&NLO}Ë[_|Í—ڱĺéj3g˙éWŹîCŮEDkcŁ•-rź}sâ+éŘ-ÇŻŻČÁź«Ň%źť˝$'« ˝ýž¤şz¤tLNť># ˘("P)B’onáĐ‹,V«|:ůßţKłłěŮ˙2NK+}»úYľUŰÜA*ĄpoŻ’µ˛č@cZ9ZĘí´níaÁu)>T&×ÖÎ_ss9vś‰©©»×Ľ«Ŕ÷|l3ÄH„Z“ÉYd#‡ŕůŮĽŤ‘ÉP˝=Ďĺą«,Ő=˘(ޤM‹BsD˘+›GĹ T:CX¶Ť2Rôő=ÁÜŤŽC¤ŁM€eeH’KwVĂL.G’40M?ŽČäóâ…ˇH*Ĺ•ż˙!…ÖÚX\ľł@Fär…bűŠ J5 ń*d µwôU•$  őčv.˙{S@=§}>)żÍĚŠ»´˘Ö‚€şďSŻ{$~‚5Hb°H (ˇ`ĄinrŘŃ»M†ž}FĄ{nĄso?ÍM6=[+lë®ĐÚ^Ú|;·VăŕGR©tQy¤“ÎÎNÚĘíŘŽC:Id(N’çm_őý¶Ĺĺz[ľPp Ă0CZZGÜš_ 㽆uĎ\ĎÜPëky‘3˙e·iŕpn%IEND®B`‚gammaray-2.3.0/resources/GammaRay-256x256.png000066400000000000000000001517241255003167400205040ustar00rootroot00000000000000‰PNG  IHDR\r¨fsRGB®ÎébKGD˙˙˙ ˝§“ pHYsÝuÝu¬‡ĂtIMEŰ $°ČYy IDATxÚě˝i”e×uöísÎŢTUÝŤĆČ&AŠ (€’5XRLQd$ĹKfŮTh;±­Č’–dŻ,ËËV"KÉŠł<$–ŮVěÉ43‰©e&b$Gq¨1–čh$)"pD= çŢx‡sÎÎŹsî˝çľ÷ŞęUŁ4€{° ŐUuß}Ă˝{ź˝żýíoÝęV·şŐ­nu«[ÝęV·şŐ­nu«[ÝęV·şŐ­nu«[ÝęV·şŐ­nu«[ÝęV·şŐ­nu«[ÝęV·şŐ­nu«[ÝęV·şŐ­nu«[Ýz×­[·şˇ»N·˝Twi^žëúőë¸÷Ţ{!„xăîîî÷ !Ţ ŕÍ’îÓąk–đIk퇉čý>Y]·»eQwŤ^^ëęŐ«¸˙ţűqăĆŤŻđłľž™»ć._D_đźž={ö÷ŞëŘ9€nmĽ._ľŚ‡z×®]űçĚü—™ÉßYÝşűWu˝čý÷ÝwßwW׳sÝ:v]Ľxý~ź˛,{Šívý—w4ŔĚO¦iú–ů|ÎçÎťë@·_Ď<ó ~řa\Ľxń AôeĆd6CžçĐĆŔ®ut›WśîĐłţ@±ö°ćX»î˝zaî~”ĐĆžtßR Ť" Ň‘RŐ5{ňÜąsŹW×·sÝ:t]ştéçž»ví»„B`0 M()!„8ţ‚n)Ô‡đá¬;„ŽzbnĺŔŕc=ö5¬śšŹ=–ŹÉ7;ő4Ěîőą˙y®Ü™u‡jc‘—%ćY†\km0ěĄŘ Ţ˙šsçľ»‹şučzň©§~`<ť˝ç{ĎÂ.üŮc˘YQ`2Á}§N}˙ĂŻý˙Ü9€nµÖ'?ůIlmm}í­˝ýŹťŢŢbËÜ]ŻW#PRňŤ =tćÔ[fYöÄŁŹ>Ú9€nO>ů$Nďěěśżxńć=§O cĚŃ=ťřĆëÖÝł„<žĎółŰۧf‹EöŘcŹ˝xĎÝ}üw§ń?öŘc¸ą»ű©SŰۢ,Kbf„_Ë}’Ż»aç;Éë¸ďůvż6uś·ă„«/­5 â8™-yě±ÇđéOş‹^íë‰'žř%"ú"Âň×q7 «6»´ľ$…;I'¨żcÎ[=÷ťp(węÜËŻą:ʵ¶ţwşVϱü¸Mž{ŮŮXkŕ?ţřă­sŻâőÔSOýýA)%Şg¸ë~®nĆĺ;řˇu#g´Däp˙üëŚć¸rÝńĽć|ˇ!-˙ű0#oç~±ň·uŽ5t°$(|żÇoeŔŐ×ňďCG±|Žđqä}çăŹ?ţ+ťx®/|á ogćK)YJIÇí*›Ű‘ĆĚß׸b­±nj蛼†ăÂďuć•’aüŐż…k y§»üÚŽ2ţĘŕ×ýĽ.Ҩ;3ĂĂĆĘóü¬âć[Ţň–ÎĽÖůóçAD÷cn!hůFĐş‰N’Xkkľť0˙¨đ˙¸Tă$©ÇaQÁIBîe>îąC'q” ˙ľ©ă MáůçdcĚ…7˝éMâźŔWőWwŕ•Ľ.\¸€×ľöµxúé§źać× *¬ľî&oÓ<ünyĚm?vMD± ţ˛©3[vJ)HOěRJÁZűOy䑿ŇEŻŽŕ笵ßeڵeY˘úwhř‡…Ţ/ŁżťÝú¤€Ţí<¦őÚ`çs”×®A& äŮł ŐtΗ¸ąo‘ŕľS„^Ô<—µŔîÔâ`ÜwJ`+udŔj™”7n :}âÔ©µN Š˘úßĆoyÝë^÷›˝^ŻsŻ`ă˙Nkí/h­Q}…Ć'vżçu“,…Ţ›ľŽŁBă»á1‡˝'R ă|oü©źÂg¤Äöűއř op† Ćg/üĐŢŹÉsSüç_u€wc„ŞE`o üŔ/Źp%Źń¤ĎáoýÇ) íźĂ?üĂxčcç}ľç=-Ç"„¨wbeYţµ_űµwüÚv<€—p=ůä“8ţ|ż(Š_(˒˲DQµXůŹB®_Żj…ÄaŻc\«węľK8î1ëPůMźgÓ÷!0˙íßF’¦8ÇŚůg>ă˘kÁ`|â‹%´Š1|Ó˝řčÓB4ç~öšĆŐąÄčáSřťg” ®ˇ1(>ö1Śz= >÷9pQ´Ţ‡1ZkäyŽ,˰X,(Ë29›Í~ó…0ţÎĽÄë±ÇĂd2ůĹ<Ďą( ZűŹŰ^¨~]éę(ţA¸{fTë"đ1ëśÜaŹY~mÇ˝ľM_[ë1Ć`đm߆ʖ%ľ4ađ5_S—<Á„oxć¸çąÝ×¶.ďßô=­{?6ĎÁă1 %Äö6HĘf§¶ŔÁ‚ˇ °ÝbŐô8Z LrFV¶RF/v4"ŕév2 ‡îkłĎŤ‰’$‰Ł(*ďdU s/áúčG?úľîĹĽ/ĄQ˝ŻívśË±ďÇő÷l¦ş}98lÍ)ÖĽ6˙ǰ5ú°÷ţNJůßö¶·ýpĽü Rʇ­µç7­* jEţlKgřý€hßX!ů ťČQś‘¸mňö‘zl¤ľw€V mň,B:Ásˇ­PĄhx @k˝Rá9Ćń™·żýíŞsŻ€ő‡ř‡ÇZű_oz|–çřôSOá§ßűł8÷eoDŻ?€ ęÔn=Ő ĎKó;ŔÁýéś‚­ćĆpe8«[[•·>đđqĺ™/8'Ŕ•ŕÇňŁ`Űü¶ziÍ˙ÚŻGÚqµ_{u\›ýGB¬!H1Ř‹qđ’h k Ú/áj lMř!·˛lđRIŇÔL'c°µ°ZăµçÎPĚgx÷źů3xÓ—˝Iź$m{'3˙Ę;ŢńŽ;rv˛ŕ/Ń"˘?ąé±ăÉO}ţ‹xúŮgđ™OýĐb{ç 3PőT!ĺRĺŔúßµp†ĐW°‘„eë6UËŢhÚ–Zž‹"śÁ­ť}Ď]ż )ĄËqٶ#e¸ČĹ„?Ř}«ŤÎýU‚5ÖýÝ{"6a ă_ł?ż„1uĹť«Wę?Ź%CW*B©‹ŕ3?/n9>ßł­5Ş°Ł–eŕćsqí˘8A‘ĺ‚p°·‡l1sŻĂXDQ&`ďú \¸t q¤đđąsH’äČŞú'}Ç;ŢńŽ;Ö'Đ9€—h1óŰÄëk­1™N‘Ä Qä.WÚK1‘e H©üÎĐÄÄl}3óRTP˙ą×čúć:‚ŕ¶Ay &"¶`$‘BOJ@Jš — XÔ†*¤€© מ‰Ăú}°·J’ĐljÇÇ1–Ó*ŔRBD0an}6Ö2˘8‚Ě)¸q6lÁ-ßg!TUçâh39tŽîš%QčŮbŽl2öy?k& ,[ÄQ %””Č‹Q­`kJĄDDo˝“÷á«ÎŚÇă˙¨×ë}ŕĄ| B 8.J@–eD$ ýŤE "%ńďţĄďy$ŞÂ–Ş›ž‰ýöo[»śłĂ r‚|UD!|OŐ_«ň™;zú^dďř&_ € ÔÖ…p;5 ˙ZÉĄ Hô? ßń4çÄIŚ˙ű=˙Ď=}đŃEeř•±KA”T;…¶Ó ß»{ßQ­­#„ÖÎď#¶pź! (%QZŮJUlĺ Á°ŕ&Ň`F¤"d–qëÚUďX0#V \ó˙+çmŚň¤ Ăş=€ůćÎÜĆúÝßý]Üşuë”Öú‹Ĺ‚_Jüă°ć›u(µµÖ;@řťDI4Mńô~ RF‘߰<6¸®sPřß:‡QÝ|BJç*ÁKQý]¸ďpĆI ©üka)ĆěĆ5TţqŢxEcčRÉşFŐ1Â9†ę’îwBIg\B ßôťďĆ˙ţQśÔ){ăg ¨H‚¬l"n˘•j‡Ż€CË‘TĐTÖŽ`*h¨©đ€ÖG6•‘ ˙8w#5Ń#VW.< :ÁńžRƲ»fţ÷Â9‚Ö=ą®*ŕ·ŇÎÜĆzë[ߊ/|á ż: _bm˝ĘÓv‘«]ŔZëD”ŞwNHGŤŁůt 9P˙ťŻżTíĐě°n‹gkÜß„7PS±u!1¨r, őQ9§P…Ű’T¤@$ ¤€e@çdTA—ÚŽG oÁËv>h ¨?sßýxÓW} .é‹­Ô¤r° ™&áW†Zç:u Ă–÷ŇäĄ'L—\aŮ"IbŘ6xŇ<6Ŕ]ŔŢÍ›Ň9ľ¬4Ö"IËPqäŞ˙ŞNŔđ\á˝P}żÓüWŤřЇ>ôçx௫”]^Ę2ŮÖ]ä#Ë5uďYcƸ0Vgź>dŻÄ,đĆϰUříóÜęć“J9`2¨oHXČ6;·őŽAV6`ÁlauYíB€a`Ťłf ‚Šc˘€5®ŕ"vçdY nWµ‚!©r4č÷đŘŰކ§?ó)HµKgp!}‘çAzT9–ş(™˛Đeŕ%íż×ŽŤ‚ož­4" ĂÇěîb±ŁĚ˛Ur€1°FĂv gpm—•‡Ž)vŕ¤ëÜąsďSJ˝¤ˇ˙ayţ%źµ® ĘĹ{ĂT¤üî!šÚ`+P +7bU·Ż˘ˇd}㵂(ˇŠ\¸®üNI !Ąš^JXk®ŕŤĂX÷ş„l"‘:üžłâ°őŽçŢĂ™‡Âëżâ+ńĚ“OÔX»d|=±gą<ş®Äw— üőŠşĐ!Źcf”yŽ—/aëĚ™&´iđÁçxbĐxőőw`łőÁ~đGyä‘ţÝĐB»é…^滯ܤĚHşu”`A¨2Ik¬Żď/×ĺi…˝V9€VęŕŔŠŔIJ9R² ĺ…Š "WIR"Žc0ˇ.ÍąŕDÔ†ăţí•vY—ř°¶TFía Ѧú/˙}­tWřójoB…7\xć< e…śęŔŹŹr¸Ńż÷î«Â|ĺW~ĺß}±BŞŰ5řĺ ˝V…&ŘÚŘ2z[#(© ”k#m¶üę椦 ŕ!'Q—°|ĐN )Ľ &ľ“ňz'vÁ*¤w#JbDIRzIšLPĚŞA»meÔD0ÖBT` Ź„pŁ·„¬$Ç„w®ö˙đăŹăM_÷őxę÷×9_j×ţ—?[˙RtWţŢ2Ľć+4ţ–ń.>{ľa]n2]ŤŽN7I ;°ÁúťßůťżţđëۑŇzˇ ˙¨ ˝V˙/ĽIŘ  ENE¦Ć‚]‹Ć_›>ËM$ŕSkMó3‚1^$š‡Ő!ş¨đp¨$AŇë„‹k•Š âŢ2|«¬häǤtgצ‹áAL®D1<©¨rBşďĂťÓř†˙ŰńĄO}ÂĺŘˆ[ĺüK»ç2¸·®ĂŮaţŤ3q´)+úŇ*/i0ăÖÍXĚfÇőŚÍ¤ČŽŰ0:°Ázä‘Gţžµö®Ëý×]荛f|mą7BIĄTm,ĚŚ3gĎ€0ž­—¦)˛ůě]DŇs?·F3®]˝kL+De˘ş*Č~ç§ ŚŻR€8IÁľĎ$H%Eqí4DPö«vL)¤o{®xđą?Ľpś"÷X%}DîyÍ9|ă»ŢŤßř˙‹«Ž„Ŕ<ÖíâmF`ý—˙ľbüa¸ßFüCÇ‘/¸uíZĂȬ?©ő·\ŤÜFO†oęŔ¦ÜĄK—ţěöövßÔ7÷f^öĹ ű×ĺţGż>s1GPĘIG !ëÖ´E®!Á‡öĎłTßÜv‘‰0™ÎÁĚč ‡°l[}/äDaĘňQš€†Łš3 ¤l0 oMj"""nx5÷ Âdťî)QU3áľýŰńńßřUě]żŢ0ńÖ¤R5íŮWMęŢű *Záxăg#ŠCÎm-.>{ľeüÍFĎűŢ8‚Ř9€MvW­őß1ƬČkŻs› Ü8©9.”[ň{‘©J,F;;.dŽ˘Dk¸űU­Úď5lÁ!)¶U`ß ŕŚ\·/-}s;q] ʇ€¤†/ŕÉKÄž XE7DD-×/9Řp[_°P¤˛>qŻí;˙łÂ?ű±˙RĹÇ~®8¤d×JôŃţńpžó@xć™óë;éđŘm^ÔMęťL§Ó/_·űŻ3Ć3"¨h Ç]čŁó=Âţµ«üîO˘1¬ŃÖQar0Fš&ĐÖ˘,JXc|=;쎫Zm+”np€ŕXßđ"…ň)EzĎkÝĽT#ß‚ ‰0ŕ‚`­nu.ŇRG˘ëŻwîIJŁMm„÷˝îáşéG( áużE^ §â€óżÔKŹvSOhŐßŰeăçUž€7ÝkWŻ _Wë_z—k¬DĽq€°Lë0€F›ö‹ť•űoTúń%<)%z˝ň˘D© çěň<Ç|±[‹ŮlĂŽ0d(uáňë,Ł =¶¶Ç஥ÓlBhXë4 Ą1gąç¸N»80¦ŇĘ ¤$ĘĽDY–hqö+ă‰:JÁh]IV:I é‰Dşrě­îĆĄrc¸k‘„ZQCë­¨!4mbĆl:ĹţÍ›«ˇ˙»;Őß7“ß,-ěŔË«Xw‘Ź–µv»Wžç°ĆBHŐ4ʲĹd2Ĺp0@:Ö`oyQA®lĘ,‘mwŃ–ڤęîóĆB„¬KouP.Âpe:ßčăr‚ - ± Ş+ kĹKę×EŽńXńűŃ®Ď/ŽáűY™äăÁB»˛űsë±ë* Ú<÷ě3hyÄeçlíŠĆ€˙Đ[®€I _ŚÜżswáEű\O^ Ŕ8†ŰeÉx|LÔ7-1-2,拺ÎG ,‹čŞ Ä˘ŃđYAč Đjwu=˙îFµá„­Ć.G¶lˇç%’^ "‚Š$T¤jc˘Ę‘ă5äYÖ",ŐtĺŠĘT—üË’^F›HzÔŤZB)mjŻeF¬b^Y©yi÷oš IŘu3ž˙ŇŃŽp´ZÂű‹ÁÖŠ˘đŐŹćýXkĐë\oAÚ;4čƀݒµ‰®Ţá˝~· î{Mp!@E ˝^*’ĎćőÍ<źĎ€%­†Xm ˇĆ´4Ćo˝ŘŁj§câf¸†1Hz©Ű9ý룀ČÄäô-¤“$„Łkv˝AŚ{Ś G{ÖĆɧ SÂ8M»ô«AçAďZiŻ#űX‹"ĎqĺŇ%LÇÇyvÄIŠůdĽŠhŤĹb­yľ88LżPŃ9€Wr*p¬—Ż´%x™ÄRÝÉĚΨŠ2D‚,Ď‘&qÓ…ćfg °°uLˇ#ŻHŤąR»ĺ¶ŐőZˇi‚ş,Q–Úc ôOu h}öQTŞŮĹĂżP’‹±¤ ĆköÍvζdČúĆűűě‘÷7ďť•¦eP€ďé&@× ř 6ňđ"ř5łą—q»đÔSfĄtŕ›6Ć H‰"ˡ|/żŐÁŔ“xÜ Šl±h´ü<é§AĐëÔŢďÔěů ‚°µ:X´Ő†Ś1u—›R€t˝ţ^ďĎZ× çbuČ&ÚŠą­Ľś×äĚÓqĄäÇőźBú./éů1Öďţ`†.5®]ľtĽńc˝Ýo ®óB†˙ťx‘ ?9îB›ĐE I˘Ţq\> Xc UŠ´— ČKÄ©+• ! âÂÚţîúľ×-ŘO 6ÚŔú0Zřp;‰e‰ÉtŠRJŘH€KrmÉl]ýßÇ!ěŠŔ8 ckCx®€R®™)Ëó¦,¶ň†Q‚e@¶ Dđ2¶j‚V0”u Aˇ·Yˇ¸xáé“·ďářÄ<ˇłs/żÓĽŁ ÍŽu%±«É!RĘßôŔî­]ŚĆĐeérçe}@ߨy,ËŇ‘|ÎÖza—sXí'Y NS8t‰"I …€ňú`‚µźŮ ąÔě…«“”`c |c‘¬r˙F{Ě?µëň6ŔĎ—Lą­gŘJ`‚T†(¨24*@ˇ/`ĎN"A¸tţiW-hÍ XJ5Vş{ŽwŢÇ9€ŁšÄ:đ25ţM.ôńe@·#]–(˛ĽVýaăÂs’RyŢĘźC•€ÁąAY” áŇ&ż^–ęŞRÂF`-¬ĐJŔz‡ľSá;ţH¸& c´+Sz2‘- ďtB»¤v«oU`®ŐŽ)Čő «eŦtŘ…€ÜÔ„6¦Ú¤MCěŢĽĹtŠd8&xV3VĘ}tdŘ_ĄSÄë1‡® ř ÷;î¶Ű>©)‘E‘ré@©…zľĽFS«Że´Â†d#Ž]9¬Čs×ço,Ś1U·Sp|}Má‡d2J—Ě®G‹l˘ŠĐc •ÓhˇŰ@=$`Ťvڄ̨z·¸"/·äĂ; ňűVîß–ô¨żŐy>µę¨d˝C‹Ěó 7Ż]¤t<\rýż`?§Ŕř‰ëÎČőWi8!ĹüůŚ<ďŔKdř'íŘöIT«ăŚ6ľÖď¦1fłYzWč»:iüýęŚY)'ŕQ úPQk Š˘đÎ)ęËpä±L§·ď‡0 •R°P y–Č1ř¤TΡT†A5@—şIč=:.UT7UeF˘ĘFý®ßꨫ§,Í<¨ňűř#ZZ¡đÎńŇłĎ"ŞÍÎަńRŕ x Ź#˙CťÖŃőŠő÷B•veŔ»8Ô?éN~ś(čq‰dY ¶npe•·R 6ýѧNť‚. LĆSڶ9E)§ź×ëĄ8Ř?Ŕřཾ qŤö˘ťDH=yÇýÎíÖĆż6Áš&’•Äp´­µ›S€’l-¤RX,ćČó˘Ń…FÄ´Ç4Î^ä˛2·&ü,ü*Ť×vMßqP¶¬*AŕŐ‹.ś?ďÎ!ÇÔôFÓr6ěěŢ1UňçÁŔŚ  j9~˘ńr„Řa/Ă<˙¨uŇ4 ÖĄ70Ůw0CÂxwł‰W¦%ěîÖ»˘ŕćúőÝ|?ŻÚc ޶śŞĽX.ĘĄ†bGÔŕň{` H NčRCHŔ±˙ň\¶jőäâ‹%ń4Ľý`€¦ű ŕJŤË€¸‰¦‰›­ź¨5 „ŰĐ!…Ú(\ż¦›×Ż#Ë•¬Ş˙›ôQŇŇ5 jňŔ+˛Z@P«2QE UFEG´ Uę0€—Yžż řw;ąŽn­ŰĄÜąBö›¬ĂĹ(ŠPVŠĽ>—vStüTĄÜÜ)j]@!e#Ö €!ęĐł,K¨8‚‚€ –ÉÁŘçř„Ĺ|Ž(ގ˘¨v,QĂŤ$Ža¬u˘DŽúŰDHÁĐ’Úc[G8ËBU/A«»UE-ě ˘=·†ŐÇóvo\wB§Őós`çk˙čĐĘ@“PŔ4r‘ÂI%:QĐ—iž»Žá°%Ąpm±$}§˛_ßgDUK>ŐN`!„o¦áÖÎ$}N&¨á[÷ݵńú÷©¨ž¦ăäČ-ŘşA2RőMîD„ÉGά5BA*7cʤp˛blˇµiRż« !ü¬Q;¨Jš\TS…@HŇâ4łEŇë€'‘oĺ\ }X¤ý˛|ŃꇰĆŕą‹0m­ŤŇza{f˘]2x?Ś… Ł×ë#í÷ë1i•ᛸDś¦0ĆB©čÄFßuľÄëvňü“ü&Ú kµVJ‰8ŤÝďaµďę“®ÓŤËóŮĚh޸Ś.[]pd3˘,­źâ#a}Ó ˘ÚhXí„;…”•ňéHĐNL˘.Vň^ŮbŃ8NŻäT}yŽš÷-¤@©µ%'mć¤Ŕ ŚÖmăY¶I8M‘ÍvÁ:­˙ć÷Y¶Ŕb±¨›‘€gżôEE±‚Îła †CĚfÓf$Úaa™błEŽl±¨ĺ×k·ˇ Ę"‡¶ě‡Ť®Ţ ]đçvŢŰ+şŘ’©×ň3©üŤc-X’$Ćö™Óőî9źÍ1đěÓçŰŇWÖŔ”¦ŞĂłßÝ«Ş–W6äĆ[[ka¬…b‰¬Čd9Ę,wU€fz‰{Ćxe¦ÂÝđUx€´©ç Xj€9rśŠ3ŔÖ4\n•Ôš.jÍ °ŕcyWEpźU߉pýęsŽA+˝—ŇźO÷/!2AĂ^¶ĚiVÇ ź x,Ĺ7QÝŽ U—ĽŚňüŁśÉ:şďşŞŔa(`úK!ŔB@—ES"óÝkÓ1’4Eže(‹y–ąŮő™uÍ ř™‚Ö4¤f†ń%C©$¬´ÖA0 µ{¶nĘŤ %Ž~µ“—eŤ?T9>‘w`ěFkREéˇzř·wfÍ®HÜ Š7đÖHs őĄ­šťN&8ŘŰsR䵩˘¦2{eăÚŘEp&Âď‚,×Ňgíç$´®Ţ”ŔNôy¬­~ZsÚ7ÁŐ[żˇĂşµhőamÜęCňŘŇϡ;5mµ.‘çÂËm;”ŢSKŽEqěŤÉÂX ÁNrŰJQ‡Q9ĆşŃpß‹ IDAT® ¬N¸Rnşń˘8FQŕšÄnF®ç8ćźŃZ›ş’PÍä€_±óÜnŮFÍ9C6CNă {šŃáXÓźŰ@Ť1¸zů’ŻV´z‰j# R€ú;gA-đŻ‘T÷ ĆęKç%ÁÁÇĄÚN' zçÖýďüQG~ńĚ5° Âߊkźm»óĚÚö1¶şťl0’ʶž»:néąÍt†OţëźÁx¶XąĐÇEUľ /P' ČOĄ%_ú"82Îh{ ‚ÝO‘/ lźÚÁĄ P%Pę†>c]ž_ÝĚ6¤ÎÖ7wcśÖZG;¶Ö—Ç|w_‹©ĆuTáĘ”NŚĂúü˝ďĺôżkzs¨ŢŰҦtÔĎ@ĐGÁtd ŕ,%éős.={äÁÔUgÎí‡µŚ•—ČÄŤz2“­+(Íţ_…^†©u®Ł0§® ř<ÖÎ0uRe„°Ťs.7şďK?‡Ćţěg-óá—~¶ ⥟Á{`ě° }\7 ·]˘đ”U«mµŠ|ŽkYîŚĎçöyžA‰ţ`Pcq’¸ťşŃBĐŞEĽ±Aµ«#©_o%±ĺ»Á®ÉH* ©”s:Öř‚GŇ©éÄ©Ř}e—*a/Âěšäş’Xíx˝Şo!pőŇ%hm7ŢjVÄŠÁ·F/An@Őq–ę@ĐĄA8¶Ë°}á Ë©Ŕa´Ďę>ł–a ě:A„(Špúěi„˛,Ý„Ű,GO&ă‰+éYgáqű~Ő€“A pd3ĐZ®»äöČuH_…çŇçĚÚhXc|iŃ–`Ee?Ő¤"Z*}‘+çWŞG­ ŐĂŰŠŞ0 7jaw“ýĚ&ăş?a˝‹Ąš}ŘÚę-hď⻯pUĐĐOjn§›Gç˙ť(č]a¤@¤D]kÖĄEˇ5bIĎ«Wü¶/˛ŕtĺ@Q—śJJR"'Râú•«¸÷ű0={VźÄh{eYÖýR*(e[FQŤóŕFpóy#ꍴ*I‚ýü?jF^[Ë€qJ”Jy–ů¨Č«öÂO6fßěëÇ‚U:~‚Ů2ZVꥥRZ•:řľ‰ E†ýý=@Č#>¸őŤÉ(puľ_é<,FŞ˘˛«QDW|?€íażţŢ˙ęiAHăyQâ‡ţŰ÷`2_ŕvř|'źßÜ8U7 ¨„1á¦í†˘Z—€.G łÉÄ#ó Ć,s(˙ďŮt†8Ťťk—“W:«ş˝« pŁ P‹fx˝ë:ę*ŁĐĆ@B‚É€Ř .-ň*Š` Ęuď_Hä©¶Z×!*ú´6Öĺţ€V¨îĐŚ‹.ŕžłg=]÷pŰo·ˇa=†˝ýä!鯂…wl\ˇ€6~řÖß•ďF'@Ŕgźľ„ďú‘„$r$–w}Ë7ŕo~˙źĂŹţŁ÷Ax°¸´l‘—%`R Čôň%5đ‰´ÖT!V˘4€ó]%’8A¶ă`oŻyÝk‘ö{`K"‰§?˙yXcëÝÔú®A]VަôY6U7Đ“Pj ¶ŽĹf´f†”äŘzJÖF"„tśc|UÂëü rX@P…:¨á…F ś–1–śŔŠíV­Ňu4ŕ«pBŕŇ…gŰéÖş™a1°Ń%¨ľV®É*W#üshŹX?ĽĘ„őŐt˘ /ůB ‰"$±Ź=ńEüĹďxŇHá/|ű;đŕ˝§1™eř‡ďű?ńî?ůVĽëß{+ŕŁô9üôĎý"GĺýÉű+/ňCŤý(F ř“.KDJˇČËĄŁűÜ”Ż_ąęÁ6 î%T„h#›/`-#"@DŇ4iBW/Ń]%ŇAŻÖčőz˘QˇŻ(‹IaűÔ¤—٦Z«ŔuNśŠ®ÔĘą °»čź›ú{Ą4 Ż$ä…N—Y}U˙?ۦc+#żvoŢÄb>GÓL ¦őąŢ’Ö/UV„ŕ:Y XßůK„%‡đÉÓ®đ%^Ö2J­ť §’řžw}+~çăO!IbüÍď˙sřľ˙ę§đűźü,ľőOü1|Ű7ýq|ďů µĆ_ýîwᇾçĎâżďżÄ{ţîă_ţŇoŕíoy=¦‹l­Á*üÄ™ †5Ťv]ĹŹŻ€Ş :}ď˝(˛¬µH’Äéę`´Á=Ü]”ŽřŁ ćł™-rçěú @–ePQ䎚zŇŻ± B–e¬ëBR!í÷`Ť…ę%ăe©ˇ"…R—Ś'°^ÀÛ:Ř9š±;źt?ű±ä®Úáâę^݇^Żç5ö×§wEîHP[[;`Xڶ·ŤŘó1Ú6EA*ă~îúHŇtĄô·vh3NťąE^ř©ÇÍe3Ú`´˝c-öö×fť(č] |ĹŁŻĂ/ţ“…$m4>üŃĎŕ˝˙Ç/c8čá©§/ŕß~ôÓ Ař‹ú[đ·˙ńż¨uúţ§źűżđˇ÷ţwř©÷ý<^˙šűń˙üćďâo˙ĺw[\[¤FŻWzéŻjĘŹPäşQ…”Có‹l^|†CĚĆS'Č'˘”ŞŚĘH"Šč˛Č‘†HH–RÔŹľ†oچ” ŘZč˘DÇ0Úń„O‰ŠĽ€QŽ4źÍę1ŕMx hc\Ď‚Úý۵1­a”łĹ|±pjB ?đ¤-ôY©?óĹ/ÚiżŹÉd˛Ů(vfEůlĎkďXŤEŇKqëć ×Đ„†+dŚĆd<†6ÖĎjŔ Ç„w˘ /Ő"ŕÓź{ďúk?$’`¶P~7"¦sż3ZlúŘÝźÔh¸ö‚šŰŁ!Ć“5Ůüę…^5~ZIWŤ.Q.÷¶D 펑JůÁ.wŽâş„€Ö%¤Tΰáđ׿ďDA˘8‚ÖfľŔd&N{HÓÄ ř¸Žü$ 7=¸š\ÜĐĺ8`÷QMLb7ľ4aް–ŽV°âj <÷ĚE´ű$$‚$G€ŐÇ.\'"­c†ż`WXpKS™iŞî~LyüNô.Ä"]9ćÖţ÷Ţł W® Ä‘‚»ă ÎśÚn]řĂDA7©é.źR®÷>NbXËŢŔ5Š"ÇÖŽ ‘mĎÔ ’1‹ů=ßB+„„Š!Ta|0Ƶ˗=çŞ ÄA~îŘ‚jrŤe «ťôXY–u‘[E 2RRÖKUÉł,Č»Z$­ŔZUŤ—gěÚ˛îsĽyýŠ"oazd]•hŤŇŻXŹţÖu}jš‰°ô Úµţ Ź' ´$Ň•ďö`‰ż˝ä|®¤Ŕ?˙…_Ĺßűëßü[˙#ŠĽÄŹţŕ_ŔĎ˙ňoÁX?úě—đ˝ţŰťöţítR#.atéŔ5áÂńl‘9`/Ž`­A’$¸uý†äüîn­ÖR)Ě'SäEbB:č#Žbßć« •űŇĄFÇžŻďv°tĐGľČ Ëý~ڤ×C4BQMĆŽzí%ÂĄ`ϰ~Xęň%AEnbQ–-Vzů«k-d8‰(śGčÍżeüLĎçŘżµ[óü{ć…‡X­°€ĐtŠ5;6ŁR ®Z*€Ŕ m¶޸ ؉‚ľÄ+/4~é·> ą¦~śú°ű› ÂÇ>óyüĚĎýküřßř^!đo~˙řŕ/iăÇ~ň˝řÁďzňRoÔ Ř„ŢĽÄlŻvn7ô“Ş’^äč·FK FCäEŽ(Šę{Í ­](-˝â­e‹"Ë]îĎe´öĺ?v*?I «umŔeQşDărř˛(ëaś$J!Ď]_ü`8„’2Pćq˛YÖşnC)ýô`ľ˙É÷¬Ăޱ©™cX ms¬5¸zé"„«ô\KŤ¶ßĆÔ‹Ŕp—Ë~}*J¤ĄšmP 6›‚DŚă$:QĐ»l÷ĎóřĐoCI‰e1Ȭ(ńóżúŰžEÇRŕ÷?őţíÇ? řˇRH7ŘŔŹżçýx×Ű~“Ů⢠í†H`1źˇô}2űn˝,Ăä`ĚŚ…7&Ě`ćł)ŔžO$«<ŢçĽI’ÂhŤéd )$Ŕ.rP*öáżÓěőűNÜ·ýĆiĹĐÚˇ˙Rş @Ý©čUŤŘÓ–‹˘@G(ň"`V%A7eX˛mOýáPáŹC'\şxŃ1ýŞ-yÝÇH‡„ü+ĄÂ*sO¬G‰«'M @^ ĂNšńaeWĽK˝€ Â: Š#Ď4ňYŽ.+ŐjŞîQ)d}CÝöl4…"šžă/•QٱoŤű BäS§le A„ iEČŢJ¨Ń)‡Î“(]:.5„Ź. Żř§=Äm$˝(é{źíßtˇĽ€a”eŽĽ(|ýľÉł+A“p›zĚPüW‘‹®]˝‚˛’ZýűŤý{ć$oŕ*1@˘ ç?¸!úTRarE >Ć÷ §/nVě0€WRUń6uŢ*‹cńY_ęľĎľĘŤG[#ÜűŔ(‹ăýŚv¶°ĎŃ  µ†.JDq€qëÚuäeŽ8Šýü‹Ţöi<üŤ*ÇÜëüěŻ}lK_*Śđ™ßřEHŐí·"Šń†·ż3Čéúą˙÷_!źŽ›Ţ‚'Ĺ^5¨„RQíąLűŹ›Ńß~L*B“É“ń¸3u›u›‘o9`≍|,H¶ŮŔë+•ÂPCnô¨Ý•DGĎ8®:Ô9€ ×ţ4󭩇é´ű˙ágŢ7­ÂĽF h >N ÎWmŔOgé·3Ć+”Q‡ĘUË‹eÇŐżuăööŃë÷a´Át2{7oa>›;aŁ,\§`ÚK!#.J öú€kźý˛=Ła´F™Í‘&1H¸ťŚd„ĹbŽ,Ëat ˇ"|ü_˝$$„ŢÖŢüö?…ů<Çě`Ü­ř09Ďó†ť' €Ţ`ŕ ‚TG9ĚÜôú{Ĺ_w gXÚh\żzĹĄCLkJ{ŐNÎ')ż/ĺ ŔrÝ‘ÂHˇ˛sŃ4rx˛G·˙cô]7ŕ ×Ő_ů‰`ĽjŠc`ßc –á˙M´\3ŔŻýúŻ#RęĢ ”Ľ”r3úŘ—ÔŘmquŻ?Áĺ÷äkűy–aűĚi̦3§0wä`îwţ(Žó9ŔŚÉÍë]żctývb%Q9*5 kÜó«(†ĹÔÓŮőI#cĽ.·uá0Sl*>µS®lŁc#{Ôýň…‹žP„FĹgÝu0UhN¨C>& şG‚†€ŹęQ¤ [±«CDëÉ»2ŕ^“yćd¨ŹĐá»Ýđýů2J©şłîdş­/Ĺl¤˝Ú€Ś1DHű}¨ČM$@‘Şőä®]ş‚Áh~żŞr‹°ě*÷ÜwD€Q Ü÷ŕČLQBĹ ł1J]B*Wn¬:űŇ~iÚĂ`8Dž- ­E)ŔÎéÓ@ľŔîî-Ç퇬gäµóŢe_4Ý‚őw[É»€áę•ç ­i~|DLżmŃQ×:|qŢfępuđóťĚ¸@9[`L„x¬ŕlí¸I»×Żc1›:• ¨: 8z2I¶RĘŃ’…€RĘU ¤# é**`Đë;îÁl†áh´ĆWCuk-Ă!ŁáĆ%5k-FŐů—] ·-ÜZFżďĎOÔ:VkŤ¸—Bh G+ŤGÇĽµÖmť8ąńßé˙…rś0µ\z~Ľ/×Uĺ5k­ăß§*Rč űŘÚŢI…éÁT!Ič˛@¶Č ”‚ aĎ]şŚÉŢ~­ě3>8ŔîűŮl]éĺ+âÜŘąˇ‘‘€Ř§SĐpžŽ]";{ĂĎ}‰R(2ׄó‘ţŻXŚŔl|ě{ĺEŘOőČ,íEG% GIÖ$%„’e© Ř2öö÷pëć- ··0Ű”Űďy óů|ă^€áh„iëü|h”aŤE¶c>ťŐ$¤*&0Ú ČshmýPÔŐZäQ)áťćtU€!Ü?)ČłůóHäóŚ—ű’J˘ČK°u gQ–PYŽĹl vQÂxěR"?¤˛MÓ˝^ÓńlK0E‘;mˇI usŮ^őŕŻy ěç?ńĺ_űôÓX\»uĺ DC* ˇÝä $ŤgUŮ’`‰!Ú¨xş×ťÁAně ˙Yy]żd0¨§­źą×Ű*sŁţ|âÍ„wŞéÇR¸/O“®žÍz"IŃŕQ|ôsľĐ«s/B¸żÎ™×öą–öH¸šĆCnשPnfF^ČfsDI‚­SŰč%)tY@EŽđc­…Ö%t©Ń°sć4Ćűâ*RŽ3ĐčzěŚ=ôd–CÜ?ä#Ź€H@~ů›$…üň7C•%ěsĎańŔýHŻßp‚¤RÂh<ËëŮᮬG bQŁ J~­~h÷ä—eŮ4ÝW†żěEBܤú] Ů…zRŃQ–Ř´*Wj?‡Šy´ČI˧¤š«@áxsÚěži9ÂÎĽ¸†˙Bcëhźë/ö2ČeÁÜhîWYĄ^'‰ŁĺJ…´×Cľ#ISěŢĽ‰´×Gś8ęp’$xŕ5áô=g µA)ěďîaűÔ®]ą ¶ŚńlŠr2…}ă—A<đ€{%ŕÉÔë=ňŕé… ~–Áj$N8’U˙˝px…’Í ‹ §!IŻ3¨'qÍ'¨Be‘·Űb—d»¸=$Ŕ㦕j{”» 5jżK)5݇czDľČB:‚ é‡7ś Ú‰‚ľDˇţť ŹÂNz‘«wŔÔŁ·\w[ ťe¦,1źŚQć ”ĄF’&Čć HéFxÝş~iŻf‹ý[{ b$iĎ)ůúÚţ|:u~Ćbö`çsŕňs˙Î7Ŕz…ˇdMČQI őĄ§ˇĘ¤”#( ×+ŕ3ó˛đt,„Q0ţýĘ([ W2,ňBh$ýŠ<Šc°‰ K?fŚ-P(‹Âý.Ď›ťYk÷h¬a† ĹşŠţŠe[Ł›2hĐLkňЇÁƬ¨UĽ2Ľ¶˘Đ•_Ayţqçd>ą(([‹×Ľůqś{ü«°µs {ď…T±ŰI…tä"ÄI­5Ň~ĂíďşÓĄ†Ś#!±/Ĺ ,3’4…R„Ś<ý– ă7>ńo`,0ťL¦)hwč÷0/5(Šk€4§ Äyä9Š,LS×Ç/¬)ńUßńÝ(‹,¨é{ٍ#oL–ˇ”t‚¦”ЎMé0á€N©Ě` ß˙ޡ"§‚\ä®´ĘÍĐëĄŇ+z4[ת<Ť0Ţß –|ŹuÓŽ] bęăŤe$±Âb‘9˛—qç…—`g˰l|Ă’«¤ś˝÷^śyřÍĚÚů+]âĚß S2Ć…ń‘ŰÉr˙.x™äů›śó¤GKź}ž=…S;§0:8çÇgŁfˇ±5Hű̦(aggĆ3çˇŘ2˛Ě †DľY'JڶFHz}ŚÇűH“E©a­ë:ĚóŁŃ¶ßGtíνĆŐ˙‡CČEćňéóĎŔ (JŘ8†Š˘Úů|ä?ëž“`'+şś¦é@<·#·¶0›:“SgĎ`6ťa0 4ŚŢ Źt0ÄÎßźý?1a8Úr(˝X!čŻĆk^űZ\şpJ /?.H¶†#ڧS´‹„u˘µŻ{Ăđěů§ëéĆŐŃF[|ĹŮS(­ĆřĘ%Đ[iIś‡u˘ /ŕîüBäů'9çF pµpňő`ňŠ5`7sŽIúN= )’A![, T„˘Ě% ¶ű}YîDbG(JKŚfŇ × ĎsWşZĚ‘öű(çsÜšŽ‘>ý4ŠGY GO<‰2GěµţKßčc¬ŐĄ±Qä›~<ć»ÉçÍ•4PĘ} nÂP–•qä4 ¤tq~€¸?@Üë!®µЦWSŹ(*ęőőz^ĺç¸ëČ8ö= G•ÝóăZ˘•ŠťvaX5$RÂxV‹Ëu˙ĺT ëĽëN~Ď;8Śë}$ŕ;ÎQ#Š#ŔÖÉzYëzhĽ6Ŕ™{ď3ăňłĎâµ_özÜş~*ŠśÂ ‘Rˇ?ˇ×w AŁímLö÷±{ó&ŚÖŘ»ą‹ůbîZl{)ÔŮ{°¸|ńAÄLQ ĽxeÎsS-&ôd {}”N=ú墨q’ JR¤ý!t‘Ŕ0ƢĐeUwÁ 7 šëWK~{*ířŕŁS;MCU%*˘˙!U߇čĽ\®ľ]·îׯž÷xź-´ťrőŹ•áa`Ź ˛iE s/“<˙vĂúó¶ůă–“ÉA0¤łŃĚ«đc ’$Ĺö©SNÇ(˛[;;0~roőw©$’4EÇČł Cxó·ţi|á·>„ńîu¨8†ÖŮbóÜ%ěś˝7ëĂ(ŤAążh ˛¦nÓ%0HHÄ˝>ŢúîďĆG~éŹ÷ťŞ ßŕ& ď2j'` Ŕd2®µ—gńŐĘ&L9ŹW«ĄÁŘ [7Kqk0éŃ1@KŃ˙°řż6P¶ŢPE[<¦’3©ĺĚŽ t˘ w0ÜżÓyţť>籹˙ĘűˇZßϵŊšŐgMÓ˝¦”B’$¸vé2®\şT;†k—źkę #JS$IŚţpčźC n \|ööŻ=çBajŤ¶¶pţę“ ĺu«ťVŇď°nbPÚŔ2 âQ#Ë3 G#Eî%ĘÉçúTŹíîĄ=€ŮlŠ~/AŻ×Gę9 qůŠ…ÄÖ=÷8^˙p(‰ĽĐG!|U"4lpęĚ, /‰†•.Ď ĂÖb8a0 ăa×Ţ]“łÜ‹Ľt“ĂÓ­qęĚ=ĐÚŕŕćŢZăďĘ€wi®gÎAn«°A¦ü`_ô$ýظŇŐřŕĆX­k‘(ŤţŰěb¶aÖ8ž˝Ź`ÚhÄaY–(ĘÂEĐžĹW9˛<•˘ľń… zLyE„IÓŇĎŠ<Çb1›¨=çfJĄ`ť†¨“Y@Qd®@Hd‹dCFŠ(‚ŚcXc0ľu EY˘ÔşáęS».¶ÜŚĂ~›7n@I±bŔë$?‹¦ÓÉ1a»˙\ŤA/íáąË—’“˙¨µ1ŘßÝEˇ &“%Gutu¨}Yc^ďžÝŽ˘aŽĚý—w‚ĂÎiµŁô–Esl-FÂ0Ćřy~„4m« ŤëZ9#›ÍaŮb2ž@‹Č9ťSîąŕ˛ŔlĽßxžF+ĐŚĐJa0܆Śôô·Oůz;c>›Ő;>{UEQş"Ţq’¸úÜa>_ÔéVĺ`j«‘A qąß;‚FyŰ·$áŞHYG4«ů|•ů …'[ľg(¤Tľ Čőźmű˝ŕp, }`ÍJÔR[ĆX@›}‚“2 NQ·%–˘Űl“|z˝çÚ[Żoä_‡Ś  ’4A9đ¶˙đ?ižSúéź„`ß+`ŽŔT!Iúř¶ď˙«`Óř#ç!,†[[ȲĚÓ“ť(¨Ś"ßƬę†Ëqω”ú}”Ł!úýľS-JIo BGŐ¨.OdŞÁ˝ ŞŹĐᢠőĽńP˙ŹŽVń ťĆ˛ččRĄ‚Ęó¦€_W|‰wüçň[ڵNNKm[wŢIÓ€Zů‡ óéy–A§Ś3ÇĚő»HҲEîʂĮćĄÍ*aM®@7?ö«?B—%„#‰ŹüÂ˙ąľ|°ŁĐ*I –`0LQâŰţňŹŕ×ţŮ˙€(I=ÁhŠýě?AĹ AGR Čܰ$I`٢,4â4e93ďďa´µŤ˛(Q–ÓůÓń¤f9’P®EŘGů­młiްdä6šŃÁíC–F Ő_LGE˙Č'…šcáě¦z]% ¤żP¨ťxQpFBk˛Ô(µ†Ń®<&ĺm6÷+7}–ꡎŔH"…Gżâq”Zc˛»‡Áhč¦ z`˛Ĺ‡ď„Éřű7w‘e ôz}yîXgjęť…EYĎ0Ö`k4ŞËŤşČ›qÝĚĐE‰Ůţ-/ôčůÔíüó””~:¤3­µ+ű=Y8M‘ôűč[ †D‡Tş2ŕ‹ĽăßÉ™™`¬A–kd oüpŚ=˘¦Ýĺě·W Źč ŘÚŮÂtźcűĚýAýáŔ…ře­íÄIě†wzÝh{˝~ăý}GĺeÖ<śt93&Ó vNď€ŕxH¤/cYk!¤Ŕl6Ŕ^?ŹPąM­AY”h¦ě5ź0€§0ڧ€Ż¨ Â±Ţ U—˝łŞíĽ^Ą·ĺ6–FK×ɬ0şÍYx3M•QŚťxIĂ}ßpă/ČŢÁ¦3'ľáBqwŁi¨t7R~RŇFĄźVż@°]°74c\PŇKŔDČóÂKÝtiś?E§°–Q–ŢđćGť$ďňé ‡ç.]Âs.ąá§RÔ­ą®Ć.k ĎjÓ÷śÁdt©aŮ@)Ë@Ĺľ^n‘ĺ%dPZC[u®ß?Ë2§ÖËÍ$¤ŞÜčƤ+貨;ôܨ?®=™5{{{ŢČ+f‚¨‘wŰšÁôŢ×;?‚QhĽ’w·wçĂ"+^Ű @íżW¸ËÚkłĹůY`p0{¤.ĽüXj•…_ŚÜ˙UăîTžĎĚPJáÖîö÷g ŘŤÄ\{{ ě,Öş”B`{k qăSÖÖáÜQ©Ŕň®#Ą„R±›Ň›$®NďI0 7$M¤qŠŃÎ6zíë`Ř ŽbdYV+ŐšRŁ, FCDqSxęÓO€˛Ě§,¨w_ůťËÝĐI#Žc°$OůM!ă‚q¬Ľ¦_âĎIűžÇŢŰßÝCÚKÝä !jj0ˇ—¦ČóRJ¤IŚ˘—Ô‡U;9s!1ÚŢÂ`8‚µ[[[-C:¬Ňb¬Ĺp0Ähkk)śćC+:Ö2¶¶¶ÖólűYfôű= ‡[Ť€_Zk¤i #5â8ި؉‚Ţ!ăľ;ţÁx‚k×w1č 1=!Çúü´ÂĐŢ0«ß5Ŕ#›űŻ˝Đä \k§‹—* Ą"$=×,ĄD¶ČĐŤ°Xd.ÄŢßĂ|6őé‚Ů|^ç±Qăô™ÓČrç †Ű[°Öb1źc¸˝…›×olŔ°l`­E‘ČóĆ”0Fc±#˛Ť4wYĘzš2!íĄČ˛ÜEBR`2™˘Čs'nRľ~Ś!/Čň JJäe˘(ˇ"÷e´†ÖĆLĆoś“#ç49»µÓů“Éd‰VKk˙Él±µµŤÉř›Lek°Č2ĚfŽĽÔrĄFžç(KŤ˘,7R^N »ŕĹM @|ńKĎ"ŠRlʶ<©6ęeÇZŁi !ÚĽńEzÎ+¨«, DQ„ůtVwÓY¶Čć č˛DoĐ3'1¤^ @czpŕĆwűŽÁíS§°ĹŚRkXk‘ö{8ŘŰG’ö ¤rť…q„|‘ar0öy3Ó©…˛÷ú)ú˛,Š”k3.K0ă ‹„ž§ż$·á{čE ŕVQš´ÜEBş˛%ł]ż&n©ąô¬â!¦(YcKęż$ýńr#¬µ˙©ÁQŞĘ*O´$)şĽĂ‡›Â ™ ÎČ_ÓŮź˙âEŚŰHĽđĆ:šđú]žęň]n8¤ x˘ü?¨*Y?“ž ¤€RQ­ÖŰë÷‘öz޶ĐŃë "…‡yeYâÔ™30ĆáeY"íĄýÄŕ­ím$˝÷Ü’4Áý<]jDq„Ţ Ź^o€áÖŇXbgç”oŇqŻ,ËȲ̥+Q„Čż¶Ůt†˝˝Ý–SlĂě«Đ81śˇ-!ývéذ,†čűXX öIÄ vUg¬Ž˝đkAőŽz‰d$Ŕ˛rTGťö(1Ů.xAC)nÜÜĂţA†ŃpŰÁRk =4řđ˘Q77»¦×ÜΠR˘†D D‘rús’GJ”Eé qŚÉÁ¦ÔĎgčőű(ň2Špőňç±Ď198@EXLg荆8sď=čőú¸yíŇ^ĚÖµîBŕĘĺçö{“môűCv|±R8uć xoR ̧®\HDnܸo€bf…NÂĆbµĽŃhä r  ôĄ:€=%㦀ČMQ•Ů*ŕQřčĢMNu¸â/4‘B[4h :î’Š@˙?{o$Ůuťwţî˝oË—k-]˝a'A¸H¤ж%R¤h‰˘Ą‘ŢĆvŘŇ_Łń¶gB‡=#[˛=aŽw;&4#É1rhdË\!pn2ER @‚Xč˝»ş«*×·Ţ;Üű–̪@Ů’;#€®®ŞÎŞĚ÷Îąç|ç;ßW/‰GjŢÂőžđZmá­mŔďđC)É™óۤ‹’NQMÝĺuËüŐ“˙R^źQz0ČAŮľŤOçy. ňő—“¸©yďŞámőe߬aF4Ęö«ťN—R—Dťt±@yŠËçĎsäřq’Ĺ‚l7c6™P9™˙˘nL'î„`8őěł,ć ®no[??Ńś‚G¶¶¸˛}­ ¶î{€gź~†NÜeçĘUʢDHaíĹßó™Î¦ÎčCÇ1A0O „ş]oŻÍV+ÇruŤwU°•XĎ^´O÷ö~n»Ŕ˛8+ Cĺ`nWy‡é*µa)—G·şl*#ö_ŕyEÜý~嬻ł»ÇÎxAv(Ś@jşÔÖú»(­oĚ<űôÓĽć»^ËmwÜÁΕ«xľG·ŰC+Ć‘&sÖŹ%/ ÷zdi†çyŕőßóÝŚ'S>yž“,Â0ŕä]·sú…đ”čČóÜ-xoËomŘ›ě"Ą"[Ř­Ŕ˛tă>%[ÉQ¬xy,÷ÜâoZ´ęeZn+čÚS aężŰ n(ŘUŇ®?o&ˇű˝&ą¬ü¬}l[±UŞÔIéđeü-QĐďŕcőŤ”ŇăŮçźbĐďÉń”!/™Z KAč9˛ŤcůIŮ.ýŮ·\d+‚kă×ëýoP`.1É<ßG)ĺÎëJôĂŃ«ŰW¸ry)%ÉbÁŮě4A`E@§“ /ž:M·ŰĄÓŤ ü±N@/ž:ĹxwŹţpH‘e¨ŔgmmŤo?ő-·j\÷űř~HYća"•âĚ‹/R–e­1ĐVA‹[ť†RěďŤEÚÉŐŇX¬Ľ/Ué_­ľ*Çk†Ł©®ÝŞpH{mplą^:(?;°V®>E[Á®ąâ}kđ;ę·.ťˇGv´$$J”H™Ł4dĄOaBC¤jÉą¨©ż«#Áëý˝ÝďţB·íníźE‘“g™N-Â]– Y’:×M<2ťŚ­…¸¶łţ,MHé‚(D AÜí¶Ög-56îĆö׉;řľĎpm c$E™áy>;;»Äq—WĽę^ł9EY!Ął3Ż-Ăť¸§UV(eU‚z˝>e^"”$îĆH)Ă?˛ŻË&%ŹăGŹÓéöěN@7v‡kë}“írŰ˝…Ú°µu”Ĺ"±?Ď,wűµúÝ^ŹŃhęži?/@´˛sYN?AševłŇ´żV˛uäYˇŮąxéš~$·Ć€ßˇ^˙×%éîU‚aŚP!T :QFOć( ™†Ľ”¤%t$µÂě2ŘgĹf Ň["p4 Ţű垯{…uÍ‹Üęő#(UŮTZ[ůŻ4%î÷ŘľxăN^­KçŠădÁĄlÍÔ-˙!Ę2ŠŇş I!)Šś,ˬ~Y‚°¶ÝA±··ë&)çĎžłĽwWŻ\e‘̉{=˘°CYyNQjÂŮ tij*Ż5<DĐétLÇHĄX$ ŇEbOy!J"”GY\¸t‘noĆ"Měî52B«Çj«ú2eIÜŤ9wö¬ÝD+íŐÁ8 ŹÇŤˇçuŘ@e©‰:!§NťŞµŞGQ–\ŢľBV”ěííîS^m om~‡[«—.1đÖ©żDř! +AăŘ#˘Úá–J§Yá‘’ČoÖD˲ŇţÓKł)ijű0 ń}żęň쮥Çu:ÄÝĆh‹„4Iš6Á±“'(‹‚d±@HA𦵻n‘YŤľ˘(¬5ň;2ݏ]ʢáĘćF[‘t‘ĐéƤYV‡‡ň}tQR”Vjl¸6"ŠcŽl_A)A/ěĆ Qm·ř„]ÚíDé0í•ڶ“ňŇh:Q„ďű„ačG‹ôű–u(„¤ÇľŹç{Ř%BŃ0÷Z´aŃË.~{q¨Ua!ě¶!UÉŢâČ-ŐŇ q€SY^l\ńŐ¦AJÍ~şááZÂ[Ű€/Ót ĎKü0pć-űçůÍlŃąrŤ, x%şČđ‚Ď‹ëű˘,5eYĐéDő…2Ʀ)JIŠ­'čĆ1O?őM‡ôW1`µ´q;4%ř‰ŰNrůň%ćł)lŢéÎ<ą$|ҶŘĘ2Ë4Z#Ą˛$˘˘°8€T,ś·ˇtRáťN‡ńîé)ćłeQŕ‡!a--˙¬*Ó>ĹeCĹ­k{QËőď˘jjHŔ,“*ް{M˘N$˘!ú¬Ü'҉ %[°Ş4(q 7l oŤ_ĆP–ƪ߲Â%_"ű/4ő.Ň Qř„ý5Gî°Hą”ߏŹ'E‰1%ş4=v”˘ČĐşŔó‘ű—& ÚôšR„§j5 S3ö?ĺyś¸ăvʢd˛7f´6 Cň4c6ť˛¶ąçyÄý·Ýu'W··‘ĘŞßEŽĘ ‡–Ö0 Ei÷ű“$ĺŇĄ‹äyąś0]K%Ą¤Ě J%‰ÂétJ·×łlĹ굺ť€vđW˝ąP.¦*¤_Č}tëý"".đÍrŕ )k]]G˝tßŰ*ĺ+-ŮnhU©=łL j·7:Ô…¬ď™Ş€[˘ P BYĸůöłűZ @Ő…/‹ᇨ0¦, *Ź»(Š™L&„aDÚçđ}Ĺąłç¸ýŽ“Ěç «Ř#8Ô6ŕţ6`…J JO!<&{î9¬_𦠠kG֙ާ”Žs÷bt©‘-łď˝ď5<őőŻS–ĎW$ ;2 }ź4/čö»mǝʓ\ą|ŮV9UUÖÜ-ÉëjáGIeÉCĆć9˝~Żi™śO˘̧ł–xF3 Ň-ŐŔ űŐZ§°sô«żş§w(äĘIŹt*Ä–(L%˛jOl–’i ’Čý/];)€Ú‡ĚM€Ő·DA_†GE¶ihĄ`”tí^uµÇ4Ë.˙ Fâ…!R€N5WJň<µ€ÍJ°Ö†Í­Möö&DQpŕ<”(č˛ôR ü^ŹÎ«_…És˛‹1ÉÂ.y’<ËŮ»şC§×cvé2RZµŢ˘(ěn0ť(´ť+ŰĚf3·§0¦$ C&{cŚ1Ś÷ö` žç;ď?EŰ9GČFBĽR2ŐLŢXóŹ0ŠjŠ®çökZă{q×ę¶­żIrą´´´ŁS­÷şŔWRZ%fc–W7ëy#fAµK=Ůôô¦í&$VD[‰ĄššjdŞśĚysĹL[ýđ&LAnŤ_†ŔWJí\t+=­·­+׸Đ)K!0J!<ŻMEiy“ßö],O)2,VÍÍ?ą  ¸?`pü8ńć&B)Š'Hžža2›ĎŘŘ<ÂńŰN"Ą$ět»vŻîŕ{YžFG8zň8ž˛ż_؉xáŮçYßŘŕô /0Ţłpd˘éxJż?pTQłâë*Ę˝í¸ýJ©ů·Ű‹Ň1}ćłEYXŔq‹›[Q‹“Ó’c« B+MŔÚČtuť…X}ÓęE.±m ŤXťí»Uq÷ˇn‡óAúŕőYá Yaö9˙‰•˝¤Ő }ţA‰‚ţ‘OmÔtő ­¤şšţ»Íđ5@´TŠ Ę«?o“  w'žRűűUĎS¶ĽöT}‘OűlVT•“÷=źĽ(ÉĆcTQPĚç”~@ŢŔxŹ,Iďě’§©5˙}ćł9~ЉcvŻl÷ű¤I†xv†„QČĺK—)˛ś ç/ŕA˛yôΞ'Ď ân—¸×]˘”G·ŰĹB„j¸ýÂŘE ÜĘóŇR•­’oň<ü ¨Y‚ŐÉFa'BIßÝ‘ŹçW˙yHĄ Gtş]Ś1ŚFŁ%NţŃémŻŰc4JÜâ;šŃ`äţj®}}ęçď2 ÜصY*Šś(ŠĘ»¦/ŔŤF·Z€›ěőŻGąĽÖęnŁđ#V~l™«”˘¬6ł*•ßÜĐďwąxáë›ő\^)I’,čőú$É)ýCϺغ,ípžc‚čé3č“îîŽ÷YI–ćx^JÜď˘(ĺ!=E„N!Hx>e™wc„”řľďĘXçűaDQŘ‘fFěŤ÷ČŇ”,MX,ć  Y‘łX$”ÚX@OZĐ/Ď ¤3évű, Kʞ¦öJĄ,ŔWíHKšĘY¨Üţ|*ĘpIéčŇG—%»{{äeÉp8dooýrce©™Ďçěíí5 Ç»Ş0¬ŐĎŤő˝Ö§ĘR3›/O&ű|üŠ"'Ií:užç×U†ą% ú~(OX¬đł¬őçyžS·Ń(%)…@)I–ĺŮ:•m«kG’nŻKYîâ™~×ÜýË夒ĂřĹSČ~źrwLş}™ţúzmÉF<Ď#Ë2Ú:ť^íő÷Ž … ;čÓíZĂ“"Ë/ö(´µó”ÇĹóçé ¤iҬW SŹÉjwa‡Ş^˝Z°Ş‘e[á·Â äŇBUÓ…µĽeµÁŘಠÖě˝ZµGÔ«ĆÂ8 G€0şéÄťżAŁ$–$¬G@…EČî¸LÉ^ćhf™lőű…¨÷ę98|ďk ř2=*SOŮš ·uűWĹ?WE?Ŕ§( ˛,ł3a >yž‘熭ŁvŚĄí •eĆÂ0<ëłÂ ]–élA‘&°HĐă1čĘ­Čç)ž§M§L&c†Ł5¦“1ŰeIŻßw˘źWčőzL§3K .4ač3™Ěčz”EÉłĎ|›˝ť=„Ö~Ľj‹ÜÎ{ Đą]S —·đ•Çż™É[łOŃBýkjO»úŞ•i …´wWÇiŇý^¦mú}µ,,Z%@Čęß§)`a%%ˇÖPk°¶l™\ęd ¬ĺɸ¶đç­1ŕw2-ŔńO IDATxŞ6łhtű+ÜŔ^®ý˛^ÍŠŻď{ENYúN›ĎŕűA˝ôÓH†Y/=éx÷ĆŕD5¸áđšżżűź.Kóąý1“IK0S8]—NÜŁŰďQ”%'ÉŢť¸ĂbžŇé&dYF…¬9‚řžíŻóŹYÖ\*đĄp˝‘şd0°ľ6˛6jIĘ|±¨CŐ8•!QŤŤ ÔăBCŕÄq!­ĆAĚ Šiá^ë Vq[ŔËôđ}ŹŢĚĘiß« ŔBâ¸Ăl6#MS»P$Ýę°Hé; P.ąěc(Ë’Ëç/_ÓĽňFşÝ†Ą¶ľzUżęxđ¶ü6Ě&Sžxě1ŽžĆ”5¸©KĂÎÎN}úK¨ H®č¶{}űš­4¸¬«€šÉUu_Ʀ›L*e";ď/tÁßđŽ;îF»6€Ł(äÁ‡r”犇Đ,U绤Ľĺ-ßËŃ­#hw˝‹_ţĘWZ„Ŕ2ŕŰßľŚŹŤőgÎ^b4˛ŞéżÜű·µü–'Ýn—ŮlĆl6µ§bk×ߎť¸K4‹ů‚+ŰWQ¨9˙7şĐbą°ĽzĄęýázŮ%n;ň,·I#KéG$‹…=Ĺ]-¬K]OµKmFwwv:étý‹`(Ë‚ńîG“”Ů|†NĄX©Zŕ3#;ő0‚4MH¬ţ„xľgűlI=ĐÚ´Öe[ëŘre˛˛¤'Xô«§ľëńÝßŰďŽsGô±˛bŻ|Ĺ+9~ü¤UZvŻEJE'Šy缝Ź}ňřľ_˙ŰĄĄ —Lî˝÷^¤°;Ň-:=ţőŻ#+ŕXHĺ€b-?vKôf‹1š÷MH‰ÝVÄC(űŢ,ć RI:ť4MÉ˝X ëÜ˙U‹¬ řKšm~NŤŚxę‹Ö"Žó0Žh$˘.K^ýŞWˇ<źN'$IR:Qĺ)‚Đç؉ăÜqűśżxÁŚök ”EÎëďżß.8!Ú”\¸p‘ťť«V ©ý»Ţäđ–(čËŚW÷ćbiˇcYÄł1ýXn ,oâ8&M’$Ą(VzËéđŮÝy1¶íđ=IEřzŁźE -eSXĹ%eQPş­=)¨rf“)Ő­n3áVŔ¬˝Ý]ň,#vUM5ŻĎ˛Ô*é’t‘°7Ţ# :¶şĐ9w —T^ët– ů®FżĹ}żˇY7ö•qgŰ@´˙}[Yą­ °ŞćÓ:őí5«í—ŚF«'Y[_ŁÓ‰™-ćüćźb‘$÷ßwďzç±X,xÓ›ßć>ň×>6äĆ÷ľň•–áűDˇťó˙îOŕŐăĆU:łą©1ŕ-QĐ—!đŰeä±­#ś>{őŃÚRp/|űÂQŹŻl©VQÍ-č{y‘‘çvőÖęď9ŕŞr.őu˝CŞ:HU ohđ¤@+1ť •Dy‡ŠĽ•×Ă’ÓQ† tcłŮ¬.ý=ĺQmĹBňÜą <éˇ)€­µĺáU(·®÷âšÓŰÉ‚Ik˙]“«ZÚ„68d3.lŠŘJ-*ťXR®éú¦*ŮMăř۸‡˘ C:q‡ß|řÓştŚNĂSßzšţ`Č[x€{GŻ$Žc˛,k”¤E÷ł,ă{ßô&|Ď'đěŠóWśĽ(ĽgźŹ€Ľîuk ř ţöç”s¶1F_Ç•– ÝŻéĄż ˇđ}G=v{öö4o}ŚŮřŢŔĄŁYŤčöúőĐÍCżßc00­ŮŇĽš…/«…4‡ đŠ2'büĐcsëÓÉ„(Šđ<Ď sfô{=Nž8É‘­-Žln …äĉ“ĽĺÍoAJ…Ć ŽVŻłÔ¶Šńź$Iв~vv( C© Ś6HiiÂą|»ßQV¦ndŘŢŕ]–íZ~źdËIyůÄn|ç~ޱU\’$ěîŤ |ż® „R|ăÉ'yýýŻ#Úxí}÷ńřOÔţŐ–áÖÖ·ßv;óĹ?(Ę’'ľń |§Ńö:4R\—éw=‹[ŔK ükůŰÚäâĄ+¬Ż­íłř^Îş­]wS‰zšş°ÚńŐźşÁ¨‚ßSKÂcôˇć˝n +_…¦¦éJyQ.ÂŽ? éwĄ®5÷Ť6µH=ÖÄŇî3L·/„‘U. ’$±‹?µ˘0KěµZfÜhJxM/Żř>ŇÂ(˘0VBlÜëŇ;~’, čć9^ž;…’Ľ,)ňśţ`@ž%vĘQ+±Ľ÷ďŞő°ŔeĄxD]ťWłü†ßoŚ®•’)]2đ /rúôKěB» ÁľgĘóyěk_ĺOýčŹňúűďç+Ź>jÁŔjôXĽí­ßçÜ•}˘(âáĎ~)es1)ťôXuě!¸ß9ę–(čď㱪×ĐוZőň»öT )ý[ľďĎ*ĐMëO÷şe} _Ž˙Ŕ˘QÜaľ˛-Fd$É‚Nܡ;čóĘű^C^ä\ąx‰î Ź’«ŰŰŚw÷@n+/Č‹ą=ˇł #ŔS>y–Ző^Dz“®|ORKi•B؉AYâ©©<§ ,žbŃëb˘Ůď“oĎĂOĘÝ=Ö¦3B2, ¸ęó ôű6×ÖRŇ]['ňĄ±›—•˛přĽţţ×1Y$ô{}:Ý_ův +šŐ_V€·ŇhNś¸ŤE’˘<µźŠSŤšGż×c>źłµu”#›Gxäsźł¤.wMŚ1üŕŰßn1 2'IR˘N‡{ď}ĺRűXGŹ%ËsvĎž9Xqč­Ŕ­pÁ7íčÖ&§Ďśăř±c­·ßí·|wí.Ru:ş“×č:đŰ ŁŮV»Öě˙šżłăÉ'N٧Íěď¦<7nÔ)IÓ‚«WÎqéÜy‚(B8;đJëOIʞ(ÂťNÄ™Óg¬É¨Ńt:ĽŔCjI–d„QčČN–ŰuBÄžd6ť˛pŔ ç–ř"-Â/:QqĤ۱ú FďĂÚé…‹“)Ęmj*G9VJ"=Ďm Tś św€ÂsB"Jţ‡żđPľÇt1çĹłgą´}•s—.rţŇeÎ^¸H’ĄxĘq2śe·Ö†^ÜĺÔ §PŇkćńrĺ4vIŔÍp0äŇĺËś;ŽcG¶ĐZóĚłĎÖ+Ć|ď[H’„4ËŔúřÇyţůS–8ŐzĘ<Ďąt˙kɲ”+»»‚Ŕ·Ć€˙eY˛µµÉŢŢŃh°l+Î,:M@ŰҲU ¸äPăíöŔM^š(¨¨Ńuß÷Éó‚|ľ@ ‰P–†0™ěMčtcŽß~LĆSşŁAŕSÓŮśx} Ś÷ö0şdog‚ň|?°ŠCü0¨ÝxŞUçn7& #ŇÄZ‹Ő:řRYĄTČ8&ŰÚD­o`<…ś/šľľňŔ|iŤ) ´.ˇ„iĘd6µ#¸¬Źďy($BZŔN9$?/r 4qsĎťwpĎťw˘ÜŽ€ň{“ ç.^âěĹKśľpłç/pţŇ% ăü¤D® µ˝»­¤¸}]aňěsĎqۉĽć5ŻáÜĹ I’ňC?ř<϶?źzřa;‰Q˛1©6Ą×(!ŐhäáĆ€‡Şo%ř…_xźţéwŢÔŘDŻž/IŇ”¸í[jNđÖÉ^;íT‰€&Đmpý7ő–]»lĽŃ…ľÖĹ®fŕZ|_ą>ŮV”J‚0Â<˘N‡éd†‚N·Ăb>g1é)”RdYĆ|6Ă·ÝuĎ>ý,eY ”DkC–¦HĎłŞCRÚ~Ů@šg,sR7Ďvł}…ň ˛Čm˛[! đ}{˛jŤôýšĹ(dµë/›Ŕt|s¨¸˙mĄ6¤YŠŇ¶ě/ kyf*âO‘xwžĽŤ»Nž¬5!ň˘ 0†Go;É™‹yţěY.]ݱ×_©ëńeŢČÓĎ<ĂżűÝÜ÷ŞWóé‡Á÷=îĽăîąën¦ł)łůśO~úÓ|Ď߸˛ ÔR¤ŕ|‘uőń­mŔ<~ú§ßÉ˙÷ţOýŔd2ýSJIŠ˘o¬®źÔšÄý^E^0eRď äeéäż•[Ďuě>Eš"Ś&H28š#‚ť¦”{{řŚpU….ŃFSK ˘);{{xĘĂďőđ=Ż˘9+Ë.@„nEŘÔôcUŠÂÔ˘-CY”öQş‘¬˛ ,muw׉ăÜyňďx«-ÝO_¸Äs§Oóě™Ó\Ů“çłŮUćó·źŕ ¸5ĽÎă?}čáďŇşü‹Ú?—Ů˝A܉ĚúÚ€^7b±H¬§ÝKŕl¬­±7žPę’¸Ói•ů«'ąYŰ˝ľŮ×P' }(QĐkWŽ$e-1®”B—šŚ ߎ֭­‘ĺ9eQâ>—.]Ş= .ťż@Y ¬N_ž[á ËţËAH”§Ą¶Tŕ,·ŠÁşÝ.Ę÷QR‡ţĎýZk§IčÁbH;|fŚPŠ|mD4™`z}Dâĺ%kśY:fĄRľ˛ţ}¸÷şĐS–”B%Â÷ůĹ÷“'Žqű±tŁ#›¬9łíěĐŤĂ |'áftă4I)µ%lEAˇKkŤ®KrS°9qd}Ťďűî7GĎť>Í“Ď<ËĹ‹9zě÷Ü}ĂŃNÔ! C~á—~‰(ŚĐ¦X“­vÚjEâ&Şř[˘ ­Çű?üđ}óSFëżRęü¨’A76ëëC_1™ŽĹ… çŘÝ›0™ÎyË›ďß§ÁwXŽŔpĐg‘$\Ľ|™Ł›Glů¸r’›6ĘżÔë·zţŞbŔ,}˙˛\ÝÁę/׾ŘöŞT‰Şsx„Jâ‡=9 ?R%{Ů˝Á)ěŘëě™ÓŚ6Ö1ĆP8UăµµÁb± Žc›X §zÝž ˘¸×%ÍRkú †CüŔŁ(ěw«{vÇc+t*`c4bk}cG68şąÎŃŤM‚  Ô%EY‚6 ľňÜkk”ľ(KK«ÖĄ5:Ńš$ËŘŤřţď}3ëÝçń§äG8züBŔźř$—/_&đ|´ËTă%ąđť #Ő˙˙77üŔG>Ăźůńw¸Ź>üŹĆź‚ň„@ŇíĹfcmRpőęUńͧžbÇÝĘ ž‡ńükŽXbZôćFaH†ś9ža@­y>+UASę_‹ WĆ<7şČ×Ý t0B˛Hđ<«M Ą"/ Ň$a{{›˝ťzý˝Á€Ý+WŮ˝şĂ"MČŇĚ"ÔĆ&%ł™Ó0Đ.™U?Ëajş,ŮťL)ËOzl_ľ‚”®źäę•+ÖÉőéódaY{QďD™5qŠ@s©j% »@$k1Qăv/Új?˛íÜşŞĘý[©ď#xó4ĺůó¶—ŻF^ĚńÍ-ŽŮŕ Ż}­Ă”ő.pe†Cz„4y^¸ijâÎîÎU‚ďşď5śĽó.ŠĽ@ÍĆü‰7}O>ű¶Ż´lĄš  Ć[‚ł«Lŕö˝ńß´(¨ 2ů?ü“BŠźF7a ł±>Ä÷W®l‹Ż=ţ5¶ŻîÖ¦Ň÷Q~ö´ňť ĚŤ˙zÓc ÇŹn1™NąĽ˝Gż7°f+l?ËLc6°Ęló^ŠĽ¨Gg%·żúŐÍ®ĽtvUĄˇ?"ŁŘ.; …ů ýżŰłâŐ2’´çűea5ę”’ÄÝ.A˘”¨“S© Ybµ˙†k#‚Á)Ł#›üDĄďW)+ęžjM!-Cß˝VŮ÷Ş1¦@Đôş1RH"g-.ŐŠçźPÂi0Čz7_´”öŢóž·đď~7~č3VJń÷¤o0ŘńÎĆúmrńüs§řÜ3Ď2OŇÇ}TÔA!˘ôGěNĆ|íË_äëŹ?Ć™OŃíő™Í× ü—RRY`É0č÷ äEÁΕ]2g{ÝéD„~ŕ¶DE˝oŹ1NĹŢP%ăÉ„8î8Íąë‹‚^ ¬pŚvˇí§´J'żťçŃW’˝Ý°CÜ‹ť¨©Ő&đ€4IIłÔ e;§/‹‚,Ë‘˛ ÔJ+;>,¬·ˇÉȲś$Mđ<ŰĺEÖÖ2\V´ô}çHdť†«WŞ…¦4V¬(DíIĄ}Ó8h]3ű-ƢMŤČ–¤xăKhšŕoY*KÓđ j?#ß·Z†Î\¸Ä çĎóČďä â.·ŰâŢ»îdk4´|Ň0ďŇíxć©o0 Éň܉Ą®ÉaišGě ŻăŢü=Ľpţ_}ň)ĘRcTÍM÷ţ$Ć€–‹ůŕG?ű·”’W ąnĐ& CÖFĆă~ű·˙3§^8MV”řa„xa„Śb˘áł,ĺ±ßůŹ?öe.]ĽHoĐĂó|Ö66‘R‘dĹľ7í÷űćµŇSŠ#[®‡…ÉtĆl6§(5Ú-·4ÉG |Źţ Ď+^q;aňÄď>ú’DA•®üŔŻ4nę˙¬*˝ Ąs+ň|k˘¤˘Ě,_I… ďyěîěŘž[Vě8{"űľ‡ň¬ÂOő)Ţ #ň¨Ŕí¤Ď”Őąw„Ş4Ë­7"i™É¬W cdCrK=%Úő÷v,¨Ý¶’rmMž$tú}ň$Aµ|ĂaÔ±[ţ~Í–Ď©ZžRw» ý}ﳨTz[nÁ—ÇÎ}őqt©ŮÚXçÄćŻĘs‚Ě-KyĘÎţµ1äyNřˇßpH€;OăžŰnăÂĺ‹D^äX•âşäŻ?’cŔŹ|ř‹ţÍÖ—ęďJ_Hcډ˘á 'Îť=ĂGľđ.\¸ Ľ(ÄŹ»xť°?@vbľöŘWřÚc_áěéStűC|ĎcmcŁö°ŻěżĽ xŮŢÄUöóVĺ}7ŽéĆńˇ~eY.±Ż5<čy´C©óÜiË#)[–gZkň,'Kxľ¤Ô9eQ°XĚY__Gy>i˛ ÓŤBR”AźK.Ö곲ămĄöÚ!X4¬M˝nĚt6ăÂĺË$YNd{g‡'žy–ăkl ¤EaqÝ(#•eaU\ŇŞCI—(V*Lqvđđŕ_âÇ~ě­|ěSźń´V?ç)ów¤ $hÓ‰Bz˝XĽpęűčopńň;Ž:řq‡ 7 ·ľÉ g^äŃĎ>“ż÷8ťNڬ­oşV¸PÔúňHË"{y*–›ŰÍ>L_˝ç»áP´onŃÂL=zÄť˘łÉ”ńîĄK ‹N‡˝ÝóŮW’8Ž)KŰFh­‘¦iˇ+AË"/¬yQÖľ‡¶ˇÝ*®Ö©,áEW›ŇjŞŠÂH‰.ËÚWÓIV>ąöü5ŽĽSťŢő{%I'˘^Ź|:µ•v Jş6 "­Ş·;ęý±Ú…^Mˇ×âZŐ˘"¶e(Ë‚wľăí,ćs<ßçĚö}ň):AČ='ŹsĎÉ“Śz=kz*Ň·{y‘“…»ö˛Ć¤¸¶<ŘzQЇz‚÷ľ÷őüŘŹ˝•ßřŘç˙†”ţ? |ácŚçů¬ŤzâÔ©çx˙żŔĄKŰÖî*Ž ş=˘Áp0૏ý_ůí_d6›w{ ‡k´’Ş™×NE†jĽ¤^–ŔżYĐđf˙Ą]h‡)»˛˝ŢWpSˇâYşŕŽ»ď—.\@÷ľúU,ć)žŻxţQ­ČnY@-]$̧łş*HÓ ! ~2Ý›Ze ^Ęb6EzľCôí5)eI‘[rŤćčŇő쥡,Šzü'ZĘ?QkëKÚŠ@†"Mń6ŹM§ ¤] rć+Ť¦ŕ*޶¬ű'x"Ý´BşQh;±gŢ$ăöëG8qě8łĹś ŁĂsç/đÔ /!ďřľĘŁ( ”§čxĘňŞÄvť{äý6ŕ?ú ďýŃ×ó˙ü{?řw~ ¶t©Ť°ą¶&.\8ËŻüűqúĚY„ň»]Ânźx}Rz|î·>Ă_ű‚¨CŕôűşĽovÇe#'%›€¨ţ.…|Ů˙ĺÂÚĎąę xÓ?ÇËť÷<<Ů,Íhcx˛4CHÉd2ĄĚ ˘NDž\ŮľB’¤OŻßăŢ×ÚQâé^¨“޵ókYŰy‰–A‡r6`Ż]A+hĄP-©/'Â)´Ň‰¸÷¤¶c«ö÷E;)4Ä™dĽGĐíR,Nj¬9ŞßwźIČjNĐÚŠÁ*ŮúyyK4ÚµćźMZŢôÝßM’$|óé§yĂë^_o§c…ą.yîâEľńäSßÜäŐ·źä¶­-ňĽpŻ˝˝pđAđ‡Vô‹_|ś·˝íŤH=Řüřo~ńע0x—Ác AOč"ĺÁ?ĚăO|mQŻGŘĐßÜb–e|ňSźŕ[ßú:Ýţ^č^4jłŐ‰QÍ{EC6‘ől›Ú"úĄ<^NаćíLş Ť~:ýŤ#®HĎ·«˛Ş 8íÄHĄ’řľ]啱"Ë3|„5şžgi×Ún¶íąÚ€ îOéŞ,O)»ţ*l«ĺ93ŃN˛J6ŘĐŤ HÍč«*JP®ř2¶Ô€…€l:%:q’b>G`}UKU)č•Ě>,@ÖăCąě-Xµq–BEN;A^äĽxö,÷˝ć>{_*Yĺ W9H”PÄťÉbÁ—žüâÉoqďm'yőť·Ă!™×­>ţř#_ćG~đ˙zŔ˙ýK˙‘·˝íŤ<ôń˙ü7Ł8ř—ž»é•”b4ěóčŁ_âSżů“ů‚¨Ó#č9JŞ5ýřopęą§éő‡ Gëő ŇFĘZłRď­“@u“ŇŘGW§ÂÍ‚&7ľ—VîŻ8ćĄk1W«˙ę+~hÝrUĄĆ‹ĺÔm˘˝^Lwń<…źxžŹňŁ5K…ťN¦–x3¦©[Í• —˝rúŶ TĺYg$KüQ(ßłm™l-µI• DËQąů^‡áÔNĚ´Ş˝JËßÔU@:ŁÜDBJÖ §‘ ?çĂ IDATŕÍj^=>˛făU2iŤ¦hµÄoJpםw$ /ś>MĹdifÁΚĹhß8š±Ä>żďŰđÜů |őŰĎňĂo~É"}IJ@•Ýăł?˙#?řŔĎ~÷[ŢĚ׾ňčŮđé/™w=đGŽÝřäĂ_úx§~ŻŃĆcDŻ“.¦üŇ/ý?|óŰĎâ!ńhŢćd'ćáG>Ĺ3ßţ&ýÁ€Áp­>í—_,ąöT7Mu!Mb¨ ˇ^Q­˛ćµÔWBő_ÖőއĂa«Ů:źů+˘Ž¬´Eăă(¤" Ökş>p- Ř”ÚŚFĂ˙í#űÜź›Íf?ôß˙Ů÷ś~čˇ/ňŢ÷ľí>|ö ŹóöŢČ˙­÷ö»ťßPžŞ$sÄÚÚß}üQŢ˙1]¤Ä!˝őMúGŹó;żóźyü±ŻĐëőŚFug3sŁ×–ĆQ–%IŮú\4´ËvŮ´ŔU&°ü‡M/uŢkę˙[ ´çŮ @*iÝ~ÂĐZ{GQĐŐk´“٢â*÷o-ݵ ,¶µě¨Jzç´Ł<ż¦¸zŇC;°žÄ8_şÄ¬<ĎŠ€Fî»Vú•młĐ– x5¨ĽřZŹ"IđŁĐ9$Sóö[}‹z¤·t˘ UŹ<÷‘,ĹňÇŐ”˘Ó±“«;;ĽáţűÉË’E’ԳƴÄ>ŞűQŞş]k$ĎĹr6żÁ=´JÓĆŚ!ŽăWů˙âúЧţę{ßű¶_ůĺ˙đy~ę/|˙\řŕG‹·˙‰7ň±ßüâ?ďuă˙Iá~WÁpĐáCüu>÷…/"ý€ţćÖo»“łÎńţ_ü·AČ`0¬™a•–\­_÷}ÍMRß-ŕOŃÜDP{Ç ąîUŕm5řzĂŻwQó˝7:őW}ăo4ţ9°0Ď đkNZ”Ő® Î^ߊ€fiZË·%˛kG^lIŻÜ&];÷»ůÚ˙<ßÇó¬ô¤]µ• !e;A '&ëż/™˛.e´ŚCÜumŁň•ÉHľÓë÷k˘+‘ÜV×M”pŰ…˛©,*ĘŽ©Źű±r`ŁçI’$áŹ=đV¤ě\ÝiîŻzĚhZ´ř˘¶O7íJu_«rřVŔ`,„Ż<3Ťţß<řđ;ţĚŹ}˙Oţű_ýeţĘ_ú©ď|řĺ_ůúG˙8ź|äË_čw»\Ű˝káy ßü›űŻůćÓĎĐ =N4ZçźxK—.DZUqq˝_ŤŕÚwł±ěFÔ(í’źĽ»¸’v™Ú®@kđ„ ˛^ŻÇ•ŹýPSÇT3ĆĐéő\˙ť9Bv1FÓëőń‚)!ËŁĄ[ÚÜöů”ň¬Ď`e×˝dŘŃFĺmYŢéuë$¦ş]Ś25‰§>ýë  «çW˘ĺ$űż–Żŕaݬjý›Öá)Ą˛HĽl±bĺÇ–×ęßh‡UIé ą?mănň$ăń0ěXŮđ˛äĹ3gťz%An˙…®LU'ÓŠ]XcU-îĂAĺ˙őĆ€J*t1Ă:äY.$0˙Ú‡?öŮ7ĎÉ›^˙ßź=ńąĎçŔOţőD$;źţ죏w»ń«ě¶ đ<˛tĘżřg˙†ł/Ńß8Âćwsaű"źyđýÄÝÝn×^´ęĐô„¦mýl¨{(V !—*•VÁę{4·?ĘŹ˙忆/ KsL­őŢ>ŃM«KűšmI˝u[߬í2séŔ1NË oősň¬ŕŻţů˙ÎîżßěĐ-yAŔá˙$:\Ůľl)˛BaĐÜóŠWňü©ç­%UőžQŇfs!čD1I–¸÷ŐYuÓ>­*KĂÝ÷ÜÍ©çO!Ü~ß8óÍ'¬ hu˛UşR"Ś!ęĆ$ »"\íČ ×NTî:Ő ©KÍÝwÝĹ /Ľ€T­5aăěŰ]´!˘Č]RgÚ2ßŘ·‚ĎňO4ÇvSú·\Ăę!€±Ó†'~ď÷¸ëλ|ŹńdĘ…KëőäšrlŞźbę„P=YUkč:÷›e‹řCâGQ'âgţöĎđó?÷óô‡$i†Đš^Ü˝_ uęo˙ő˙ĺuůsźżňIďűW˙÷ÜuoĽ>=w:[ŐŽ´Żi:ĺ}ďű?¸˛7axô›wÜÍ>˙g^r°„!(? ×ë3ô-eµ˝&®qęôŮ%“±\,®X†_od·\ĆôŠRŃaDA‚ÉdĚŢŐ«Ha8ż˝cŰ&§x[%€aoČΕËőlľMމ(őČÔ.÷$yVc(réëMŔJ·đ2ôŮ˝z! \?ÂîÎUk…VI–· Љµ‘B¬ĽŻM[€€Ň†ý>»»WQ-U`q`¶Áťu:$‹dEjK4§pë˝/Ťfذ·łŰ™¶ÚłÜkŮÍľ$˛b¨«\ŚvÎp˙¸Đšµá˝Ý]7™1cwIĘlĽÇ"IM§×ä\O+ŇhÍŃ»_ÉŢąÓüýź˙űüĂźűGD]«üd" ĂĂţ7ő×zĹ/˙›÷í=ü[_řý'€/=öo}Ó}|úsŹ=ÖďuďÔ­4 ď{ß?çňîŤŰîDuc>đ~…¸ŰĂ {sJŮôDíŇľ=»oŹôd ý_˛‹¦¦ýV­B%´Ř6‘Ä%AءŰí-ëh.…S릤±Ü=Wk*ű gâ€Ä±˙{L>«źăf¨źUPŤúCţŇŹ˙8ý~ß÷kŢ=ĆĐíőMç Ęl®9µÚ­Ň”KMs}‹·J媜íĆ]fł9Ă"Ňyë1«–jU‘+°&$­„WóUbâ^ŹŮôŤ×yV$»•ZN¨ĚţŰCż3ťÝߨ>Żh´-ý6ň~şýľu{UąßĚ|e»·4-HŞ @5lđćkm‡ŮşU0KÉA´ű[©\g Tyő‚µ–1ÄŇMÎriÚľô+Iˇm#.öőüâŔ–CÉ4Â&|;aż˙žŰNŇëv‰‚ žĂW>zďS„ţq°|ĆUA(¤DëĂ1' ŕ{ďY1Oe·űĚ5Ú cŔSŇJ‚_˘kV^»'%ž’+ď9đÄ4Ć:#—Fî#ÜŢ·<$–}VăÍőSľD+”•×ŃN{„ž_^U%ů'Žl˛;ß4ˇ¬úXIĹcŹ|’·ľë=}Ĺ+9˙ĚÓüÓúżó÷ţןg<ž!]“Çńí“Éď~ô'~řť?ú™Ď<Á;Ţńú—–^űÚă|ěSżý×FŁżfLµ3-|ŹĎ~ćÓ|í‰ßcíä¤>űń‡č‡Mđ«ĺŕ­9°]Źl“}šůiüŤŻh4ćjdÚ1Ű\Ó&J­­Ú+ËŕiźĐ5.Hě?Ĺ—<äÚh®Xľăěé&jŠ©hÁ•„–ŕ!®KűܧŘ:’:QȉcGY$ AQ–n/ßRI’¬ŢÖ‰n0ÍĺtĄż^šVTeµ”Ě †ÔřdîXł”VE˛S–Í‘*ĚňŽiQď':ťŐ@íľjm%%Iĺ9™sZ•ČÁµ—Ýd”L§łľ°ŚÓTrŢ8·b/UV±¸5RÜ7N­5Ë“X$i=î¤ezd4¤Ev˙×⊬މbľô[źá-ß÷ýlÝyßřćÓ<ôŕů“?ňă,‰ă;úýÁ{Ţ˙áßü[ďxÇë˙ĺKŞ>ýĺO˛{Ńď‡_u?[T¶ęłé.żú˙ÝÍ-LňŮOYŽ•X‰ĺäťČy¶;Š$Ú–%ŠiR’˘HAěűĚ`ö饪î˝ďŹ»Ô˝ŐÝ3Iq‘¦ÎiĚ §«şşş~żű[ľß÷}ţżţg0F}t }í+¨Öűµ:,µĂ; îĹňűľţĐ üĽž–áżÄSŽ–‰ c=” ”Čąbvuż\× rü’sřśîÄí ą?!®që÷w I®˝Ťq×2--ýsîŤ"ŁIŁŻ^ÇčČň˙ßţ+~÷˙ú}ĚÍĎ[:¤0d˝Zű‹ö©ŹŢ÷ŮĎ~źüä'/Í|ě#˙ďýĄm›ęőú¤‰ŤĄúgNťÄöwcüšëńŘŁˇR­̶č¨ď˝ ‚YÉíPJC>>*Ě…ŁĘ’ăP/â…á~”AŔ3e$†nÚ¶%ńj„˝6b9ýŕ„ź¦{eŁgő‡}˝ëd¤?ĘZúR%ŕŚ†^ŠJwľ–$8ę$yřa$qŚ(Žž˛Fá¦Î:J$Ŕťž´’®’Ĺ*/‹Ę¶íšZ•Ţ oŁ­űčźBÚßÓCô2Rŕ2ś¨C ă¤Ox˛$$şw}ŕRňj?«sđ&(-B¸ÉI µÄf_µ†Ń"’(Ő]¤Ř»gŢő÷ëˇ*˛lî礪#Ă9 B<ő˝Çđ¶{ďÇý/áŕÁ}X˝v˝VŁ$!$I*ďřŇWşç—ß˙łO_rđů?˙§řđÇ_řtvĹ ˘ŹţÝŁ¨ŤŚb˙=Č2Ž$‰5I,äÓ®zn»Çól¤ä źĎ;­Ďřá¦%° Š/LBµdň,wZޤ lwçÍąs,Y„đćspÇąĐΠŐĚE\Ă'ľ® Á-ŔÁŤÓ"$\ŠÔ¤,Š/q˙á3©©i´Ó¶"Ä21r×n'éýj‚eŚi©ăb© Ý˙YĆĺ]˛=›vužţ¨¬Ž6®ÓXć:x+ör׋ř•NJ â0Ä/ýŇ2†8líˤ…ćŢÎŇ T»`Jx.°˙ŕ>\±z-ľőČĂřÍßřGŞmiéŮ©¬ŐúţŔO\˛řO˙ď٤’<`b)“Ga˙őÜó‡phßK¨őhäX)¬·Á0q8ŃüUťřÍ5§čçrO®›8ző/Âzc\ą…ç^ÔáWř‹˘[ –„ř©ń‹€DŽŐť8Ż“ĺ§=( $—L J)E@¶mąA •¶é¦U™íluywčĄ őŘhç-ż´ÁĘĄ;—fŘ—üRt1Xy™ďqçti¬×îęa4@h·Z8uü¸­\:)¨Šě¤+%8}âÖ­˝Űwż%˘î|5R’( ď˙Ó/|uôüÚű'.ÉlXżńjRŃŻbTňĐ‘Ăë}xá… ®Öś)0řśó~–x먲;ΡXELÓPzS€&€,Ú„đ"Ëćś+ĘnŐ…ŕE6F uŠ’˛$<ÝW!~A‡8hA DŠÖš©8űQâ„Ŕ˛[TÔ;DíëďÇę±1¤YŠš¨yˇőeŘóë°‘×űĄ—â>^»«aF« A80€‰sç:@aË‚la\ť‡0Âî—v`Ë [°˙Ŕ>\uĺ&Ű}P\ýýđ‡—äúűú~Ä 5ˇáŃ'ĐĚ2Ě^śD­ (t”™t<¨'é’s‘"Öśîfˇ1Î@ĺ;Äy^Ž'U %¸”D3Ď*Ť·"X¤En W¤ě´ôń„Đç§Ň75 nŘIĘm*g”ąč&A€XxiŻKßmrQJ‰ 6BJ‰0beűQؤظa#Ž=˛dKĐŠIż=îÔ| ‹h´[8rü8®ąz“ęŘ.™Äń{/Ůat·µ'Ý›ĄŚ`rz'ŽAT©9ą ł1v$%$ĄžRlăm•ݢÍ&uAĹ­řá›uŽ(Ł <ňŚ#ÍrťľG$Üşľ#áLаߩIČň ‰~ /ŤÔĘr*়T@H`«Ţč4[R©`hhpIˇÓ•íÍąŤŚ ăÔéSjZRoËĄ„¦c&ĄÓ!“,pęôI\śťU\….ŢBJ»íRjĆ6zÔ(DZŐ–łgN Ríóň^c¨~ĄÄYţʱ›Sm'ZD‘tÔ¤š[Účîžn/ UP«ß'*‘.k¬Ź!p{‚v·áF @©điX]Ě'!Ĺąr#&–‡K)1>6¶bü?˘[žçX·v-Nť:Ő3ýóź÷‹ĺ¶MŞÓĎ©É h´ÚVłŇSŇë­wW·o¦i˛źn€ bŞůÄ!I pµĺşť$!ťâTë•G*ś1#“şN`ÚGVîÉ-ÄI˙ESŽúUa@Őň\QT‘˘-*ab[ů§¤PTlQjÁýŚÄŐˇÓ0Ćč‰ô‹nAŃď/…”RŠ(Š8¦&(łj. J:šÂń‚řČ:mu i&,i¤„4!»&¦0]—ü‘sn‘€\Ź 4ç»0ÖŘ…vJ·â Ă„’,§+@%đ†ŚrĹ]ćĆź››Ăââ˘GlzYUćKا|CľšÇîµßĺĽgyµ7‘ĂĄ¦D—ú>ŻäóĽě.@Ź(a)RĐ^ďg±—iŠ-7lF.rP©ř7”ăi6Řżo¨mĽ]vÄqőÓ§Î`ÝşőĹl‡®ľň* ®]‡ŮŮŮÂčtÎKĄ3Â)auçá>Ô×Yą)UB ”1í4h1S0Ë DˇŇBqŤS2W ˛ę!í‘ó,ÓtŃ*p„Ć[Q°YP@ŠY +.‰ő®Ü ąě;ćóq°dI/¸t(Ćzßśóe‹ÝV”Ë1úËe;ľśý^éąő —_­s{->ĎËąŢÝr˙ĺ˘'ĂwČ*ĽeÓµh6›LÚ‘{J).\€Ľ¦mś ˝"€úţńÖ{ߊ<6Ď•Xl4đÁ_|źűÓ˙Rđ§ĘB”ĹŽ t« ”ŠÄ‘ł9@EN(€Üćţ^!ÍDF8‚ڰ†tÄ> ŐjCjE3¬AŃyeäÂYąiA5f Z¬ćî¬pş.x‰Č‚[.őVQ„ĚK«×R 0Ë­ž—*/VŢgąÎĂr7áĄ0/uź—óy^«s»ś}^îőľ¬ĎăĂđŢźĎsHŞŁr=€Ç„ŔáC@)­r!–Ś•Ĺ…ěŰ»7Üđťgž8Šńëý üŮ_ţwPMÝ)«ŐMçÎgŮ18f"ËTHţ‡-şE±8Ş e'c|dÎąEí*} jÂ5ź |6"=ÍK3j]®ň/eTćáîs9a°[=/ď×Í0şťŰRű\Îçąśs{­>Ď+˝Ţ?ĚĎGţΓ(ŐĐa ,kăôcŠ'çR@ .8 $¦¦¦pâřqĄYš!g%ăÔ¬şzÓŤż’$ Î_ÄťwŢî´aŠW_ą~Ň/ěÜî ™HRŻř0…Ń–ÇXI™ź­T,ě5îŮ›.Âu·UVBpuŕć9}ŃŐď°Żńţ.ťcŘă\HUŔ”Îë$ÔľRÚ˙K®<ĎĐNŰ8sć,¤Čqĺúuŕś÷D®-µş˝śŐwą}ş‰¦^Ęą]îűt Ń_ŹĎóJŻ÷űó9Ž"|ű;Oŕ»Ď>gS¤f˝zŰwă}ď~·ęý»ç%ßţô3Oaqa9Ďqp˙ŢżpŔ€¬ś Č$‘AÉČÔô4ž|ň)Ü˙ŰŔą°a˝”@šgřżç˙Ŕö];°óĄ7Ľ,Z\˛#-0+¶É×Ýp_:*°®‡îŢ3·…¤×—HtőµÔyĐ)„Ň NšQ óM}B( éě«Bzˇ÷Q )J q wÎCO%X¤ŁqĘ{?úřS8xđ0îŰ]X·vµfוNşsÉe‡çO^Î.¸śŘ"`“—sfĄó»ô˝^É>—Ĺ'Ňĺ#‘Ţߨ¬JěąĚ{ř‰0Đj·qâäI|óďÇž‡&H) $ű;v IDATkĆĆđüÚ-%ĽBµ\`Ŕ±cG15uQK˝Ó–î˙ç¦x”ŢSȤ 8„Á0e”<óěs¸ňŞ XĹzküć4šM|ůó_Ä»xŽť<ˇ ‹$ĺN}@Ęn—ÁÉËOi:#jzĎMHGP E»ľ®*Z™ÄaÎŐÎŞÄNä~Ń>µĽ;"T°Ů˙Q ĆB$ŐNź»Ż~í[¨U+⬡¶˙RwŽŠÔ»ç d!^MĹfdöő´ëťNş%‘®…YÓóőKzĐń[FÖNńŢKt:¤ äĄü ‘€0´ŻÂu<ŇŞ÷}…Š)ȇpôD5z uKq&…]ŕT.-ǡtśťt÷şX'‹cs”BÉüÍň#ŞP>ă9fçç' 8˘O‰ţţüŢ'˙©b€¦ śp{Ż7[MěŮ»”2Q(IĆNh˘ë4šŤů+ëŻÜ&sµ˘íoż‰_˙ȇPŻŐ´ŃŢ.Ë3|ă/Ä»é}8yć´Ž$ző¶ÔP8áÜ:ľ‚<ŁvŤŘEE©„AěyőRýőťI9*!ď#…AúďK© wGpY‘é,„L*Ł«G±zlIúÓ®#Ň:’Í.IÁe_#IŮv;ĚܡI,-lÄűî\ż'K¶î+íú5θ7ă/év˛ÇZŚ˛ÖžŹ^dĐËO¤â#tˇÂĆpÝ•5ÇdśĐ‹„pëZîűJ˙R:ŻužKÂ*ŤŠ”@ŁŐÄáă'qđŘq4ł őZż÷Űźç\Iî E\Ę%Ą;^xÁŢĂq\#'öh:Ý"€ŔÂsO=ńä­÷Ľý×¦ć Ąb×}đÁżÁŻüňűE‘Ń=úŕ7đţŹ~»÷ě u©ŮË"®g6×?;Pr˘“áÖF ÝŔr 4–!•N4Đ}RŠZzGĹ8fáŠ(Ŕ¬P ,Ŕ‚*VŹôcířUGîETé/őÎJÝĺ˙Äá.(H—cşÖ[îÂřR\>Ű.ńuIA;ZvÄ? / pâBŹ˘{ ě°Iv°;†n Ë5H§6ŕą·Â;«°»şwÁţ›×Rí ¨”šđT; "A¤Ô"ł˛€ě:oŇqM˛°˙ÂA‚JĄŠë®ą™š]Ŕď|â·Ŕ´M#í.©-c»víFłŮ˛şĂxčŻđ$€ymă˘[ u 0ź¶Z§›‹ ű(ĽŽ§śÁ17?ŹŻ<ř5<𿇠:Ŕ=yÎń7ţ%|ň˙ü|ă_«$ŞÎč9á‘€tĘÝś@7Ł–Şž@ŕżU”Éę¤ĺüě Kí˘»3!žc(cfvRŞ%Ó 8I«újAPÔ‚š¨ćŔ7úŽÔAPęçIń“xKça^C‹ýaöµŞŃ´•±…ÚTpîúMĚŚ=?â±Ěµ˘Ä'šqt* »¤«3)˝Xt¨FűŹ"Â0Ń‚Íç»8Őzu¦K%Ý®Qé!¸Čň֬Í›6!×5RröŚ8tč ¦¦¦ŐyH0Šţˇ!ňžůÂÉŁG¶8`Q»:“˛ó§O5nąűŢ·RBxž«‰bF‘¶3:t×\}˘(vZ{ęD˛,Ç–Í7ágŢó^<ôČĂh¶š…‘{ a7Ł+ý˝G•Ő ·ý×’%śL—çI „eťN§řüR«f÷ńÝţZőj짬ŇKi aR’BÉV:«¨Ç9`d4-Đąç#=±4ęs"Ú×—¤ŻĘ˘§¤T‘DOi»j…S#®Ô8Ő´®žh )ÄaKú¤Żßi Ón­ä/ęEF\O-^H'µĐ†W6Ţ"-¶8WDę˙ĘĄoÜnKXăÖ°…–Š÷~ʢUÍ…*ęm˝a3Ɔ‡•ńë¦M$ ŔĚĚŚFrĹâť$2ăÉŻţůű#'Lé€/ĺĚťť=u|â¶·˝ăťiłe‡Ąŕ\âŔÁC_…ţ>…F"nH-180ßüőŹáÄ©“Ř»k„ú‹”ˬԮ†•kđčaŘđť@OQ ˙y[¨[¶O´„Ă"ťy«”¤ç{#č«%¨UŁÂ'b‰ź–sč›Uy­®ňĂeRâĽ.ź—I3\SDEáĽ=łŠ>ĺôÂŃŚ$ş˘h”m$"I„[’B ŢŁKŁÔŠOŞKËp9d,EČj{Őwévá „cČĄßT!PčN€Đ•{ĂÂŁŚÖÁČCÂyÉř;°$ÜÁ›çťżs®WFŻŤ?ÍRŚ ăέŰGˇ˝î SR¬aČđŇKű°¸¸ýţ`aÁ±Qň­żţĘ^Ľpa·^ýtš/—rÖĘćgg˛µëŻż6Ó8d˘ŐUĄ:‚0`Xłf\Źţú€Î%~ćťďÄŰď}}â1,6-a‡o4˝zŇn˝ ßu^•źxĂŢĄň˛c*§ĺv_éز ‡&]R’âŘőJŚj{Ue¸ˇ¤ôCLčÔ¬ŕE¤@tŠ”ś‡S°’đ ÂiMKYś»Ą,w.…V*ÔétRFöLúŃ‘˘J…¬V<¶ ç˝Lm¨ó»1„.αŤ« ߥ3$x+¸ »UŽ_¬đÖh…TĐZő'ś×éUް,Čôsś{ŽA=”Q ^¬řĆČ ‡Ŕ}Ç eÔn»y ®Ů¸Ń‘i+îj.´BŘ˝{Ż‚ŕR@ Âj¸8qţÉď<üĐ˙pŞĽú/Ř»yĎÎçŹßţ¶űď BÖźgąfŃ*ň°3gÎcâÂ$ÖŻ_ ĆÂ’Ę®Ď9ĆGÇđż˙Źç9ľ˙ý§F‹ĺCöZa Ľż·˛Č‚GpYDZúţزY*¬đ•tÓ–ĺj¤¬"Š^rÖ„HÔŞ *Iä©­Kt¬ěć( Úm-Π0LRú›sLs<é¶©Ą}+k§ŕ;Ç‘.î•t†ÚXĄł@Hâ2%›:ŠNKڤ|dťW±/…íB÷öM,:^'ě /uÎĄ†+c”îJÍ…Ź*u˙¦Ťź— ź ç9nCzî„÷Ü>/ŔsŽVÚĆ57â­·Ýj’8řWŰ‘ RI09y‡±WĤ`I­&Łj2ůů˙đ‡żŕ8€ hYL°ŔŤ˙üÓźůă…™ą·3Âh(ŚFS"‡QáŢ{ďÄĆ ë-¦YJtČ\-6řÝ?ř—řć׿Z««‚“§HşüŢĺ9řPa3Ňk ]žX –8NŻçP¨»…N;¬Ç)(-Á–Q>&:Ž?ľŞŁĂý%Š2_—NaXÁźGü<ߌ&w>ď´á©ëâyYđ#Z ‘+dž’Ä™+ ‰RN^:/‡Ý+R‘ň1Ęű•őÔŞ Î=i_iÚczeWŻ:?BńXX<Ľ4-Ś^Ő‘R@UÚ…Iôs¦Âé`"¸ŃčşźÜjšsTçĄ äęŽcí´ŤŐcc¸ý¦­Ł =pë¦ë@vż´ŤĹFÁ©!„fţ˘ZUŤŤŠ?ů×˙ę“ÍFc§vÓZîę)€p~ň#ű÷¸ëţźú©‹¶z˙JRÁąóŘąó%ŹIE<ŠÚ.ŞTäđř8ů«/ţŮżś8wn»ýŤń‹ĺJÜ˝Z‚U«l\ő¦»?ü[źúôüÔ´ĚŰ9a4@FÂH“mš[¶Ý„ëŻŰ)©…Y–óţ$ޱ÷Ŕ~üţgţ žýŢwÁęuKŔA@ťÖ,µjS‡·Ź.˝Ę›j3ŠÖĽ t—j4h‡@©żÂ—÷őĄŇH)RęĂŞáľŇ±ŻoŔ(ER©(ůnΑf)( P‰€R´ŇŤ,GB ĺµ9Ęš‹¶6“E]Ű“ÎŘ4±´čŠť˝¨ŕ‡a¨ČMsnĂtBüİ'Qű™yw‡E‰‚0VÂŤ$€© ç1;5í¸|áL~ĘŇ„©ĐTŘjĄN/Ý[mĄD†B Őnë(Aء2¦búO8˝x.yq,.üČAż—aTżJÔq†űű0Ôׇ[‰CÄqčĺ§îŤ¤~/ęYžŁťf `âh¦ZYqSŞTU‚P!¤"DNqĚEq–ą!-hÖĚC89¨ű;eęý•‘ť×Ő홝zSH3żë—”2€¨ ¶ś«‚\žç™ş…ą9p.u•]€ Y´ĘteRjČÜVÔmő]pµ¶ÇÎXΚ­fQ€ăş g^§f– Ĺë ÜÂç^żŢ´ű(Ąŕ&@*= ! ŠąÎ:°Ő˙<ËQ«×qÇÖmŘrĂ _5†vÚÖ)ĹŘđ ƆA AŁŃD–¶Ń_«ApŽ<˙^Ü˝Wëg” ćf¶€a€¸Z‘ĂăcdâÜ™§żđą˙řYŤň;«{ýŤĺVţ—ëÜÂ` Ŕ€uwĽíľűßűŔ»9ßŇf !ÓŐß Ô2WJ=2Şąö$úűű°iÓ•X˝zµę]KQŚ_zS[je«$1˙Ţ“řĘßţľůío¨Đ\˛č× Đ~Ú}?“ű÷vn]µ˙řĂýu ÔJNĂĐ(ىŁ„ä9G«ť‚1†¤RĄ‹iŠĹvę @d@–u*rt;ÇGň,ܛݠeř­v&Q‚4MŞô.ĘČúúR¦f t?ň “Ä›05Îâüé3ľ8éĄkiĎMî’ëTů ă(„‡ŃB Z©@H‰…ĹۢóR1YĄĘ ‰,ĎUşˇ‰ř„ŠŽg¸ů†Í¸ó–[q÷­·#Ë2Ě/Ě{ĹGB€ŃAŚ ö€" &ÎO`űö8pŕ‚ +M Ş’QŁ:0 F†ä÷ľýđyúńż{Ŕ(–źY=îË{ĺü݆0űś@Ŕ0€µ6~ň÷ţŐ§VŤŤo™źž‘<ă„"4f ˇV T5“RŰ Ř°~ ®X˘ Ň”äĐG ˛ "€1‚o>ö(ţö[á‘Ç D±ĆŹ/oÔ6Mé ş9’.]ř˘-á´QXˇěŻcPtöňM> CPB‘svš‚2†$‰A C#MŃL3'PďFˇšÎĚrGżXiiXŠÍűQÉ%˛,µ‡q[·”8=~BÇ1€4Ë<ĘönآŰpĹt:äáĂ(BEžC’B`âüYĚNMuÔll_Ý™áR‚óĽ€öęľyGŠ"’JB4‹N˝ĹďŮ §Çoä·sÎ!¤ ýł,G.2ÜtýŤ¸mË6Üşe«Ň}Ő¤h¶šÚB‚±á!¬Áţ}ńä“OăÂÄ$ ÔÝIꌫ¦*JE…Hj946FÍĆÁĎ˙»ý™,ĎŽhăźt¦ü8.Héĺ:ł/u::X}ĎOľó'Ţó‹|ą^iÎŃÎňŽQŘ@wK8çpˇEŇĺ ôruZpIí<†!ź”$C9Ď˝ť-Dăô€Cú"­ţ»Í‹PaG Ú1)9f§¦±0?§ Sí¤pŇ•`đśCÍ•ťóQBHˇşćď\ ÍS¤­VŤ¬Â­[·â¦ëoÄ ×^ŹJRQ’Űz4·ř aőZCýU=r ;·ďŔţGč”×ĂX”¦Ż‰N‡ŐŠŁZŻÉá±127;łď«ö§:qöĚ^˝â_trýôrCţ–(G€šv«Ś]·ůć­ď˙űűČŕđč5 ÓÓRd9!Rµ´Â T][#PŐ `9§ŞÓ×WĂŞ‘a ô! #•› Ý‘÷¸ßüJ ’$ÁÔÔžzîY|˙ągńôöçpâŔ~ ŽÁ˘LĹ^zĹöSJ]G +Ü^A±0ŕBŰ:sE÷ˇ^­ ^­„Ʊ”°ţŤ…Črea‚ Hőä¬rŔX Ć_ąĐń˛Ć)©¨Âžg6­3Î^ZCÂP‹żć%RQéD#Ň2)›UÎtüˇMŐV4€íu ąŮY,Îϵ5ᣍ¶hirĽ °G8¤›Ş„ ’KĚ-Ě·Űذqî¸en»y+¶lŢŚÁAĚ/, ŐLŃÎ3ä·FonLõűj¨DŽ>ŠwîĆž}”ó™‡<-DiśTJÁA†* *őš]EÚiűÔc_űë/ěŢţÜłş§?é„űłď+]ą_íÍ­ G0¨ÁČć[nżő}ü𯎌ŽmZ™•<Í @@•#˘˘k`˘ę ©ŐďŁjŐCč¨#‰dśá±Ă•rG+ N)˘(BłÝĆó;_Ŕö];°}×N<żk'˛…y T8vŞ‘ĺß’+KÖ­&€Ž‚!A­ZA­’ SÁ'á`Ö(µcUóÁX€”sä1Ş™B ,F墛3,dňp+[ć„´f˛¬Ăy `L«soN˘¬Ë#`"9áꔀ걄żš.Ě͡Ů\ô¦ţ|b·>ŐĎ/!ő¤ŐĺyŽvÚFEŘşy ¶Ţx#nľńFÜ}ű-Bžgh¶S´Ó Y–!M•LšfČsŽv–ˇÝÎŔ…DDÚ\ġ‡°kÇn8tŚ2!!Ě:VÓ µ‚ł´@Y˛€"Ś#ÄI‚j_]Ť®"­VóäßüĆ˙Řůý§źÖaţ„^ńĂçŻÔđ [ZkG0 Áđ[¶nŰúóżüÁ÷ŻYżńćĆÜňvp FBŞô@G,TŃQíŃŃ^ý @ }}UT+iÎí PF乣µćŢŤ´:yć4víŮŤ÷îÁî˝{°kĎKhÍÎaFj¨F / K®řQ@ˇ4¬ľüJś R‰K)-MÉQ‹ť(0 UÔČąr €2Şx4üÔX"qKLÎ*‰ËÉěĘ-ůĽtî*Ďhŕ9OşÍ•.'˘sÝ Çž«”ž©G§ „@cqíFŇkĺą5€˘]\ŚÚć÷ěłzxǬř‹NžźżZ†˙Z87- ]Á0€áÁˇá«>ôű®˝á¦űÚÍ&˛fK .šN‹rŞ^ kŚyG®ü7%†/¨VbÔëUT’a*D]Ę-6ÜŢ.ĂJBĄP…¸819}{îÇľ±ďĐ8tŹZ- A#娹lˇ‡úŐtBÄ1’8.E.Ǜި™ Uáś+(0S< k’RPĘl/Ľ¬ äN'vĐ}ąy»ćBŕB¸ y…Ň,Âţ‘Iňéţ<ŇN‡QÄN-:©›­FívÓaĺ5y˝†îćň<eÖŽŻÁÚŐëpĹšőXżn=Ö­]Ź‘d"×ĹcĹ,‡ęő ’8D0$IJ˘R‰ÇęwĺŚT$qâä98x ;wîÁŢýµ["łš”t®đEdH¬scA€0Rů}ĄZ“}C¤p§O{ćë_úËżš8sú€^ńMŽż¨WüěrúúoDĐËTôiDá0€Ń>ö‰wÝrç=ď¬ÖëŁÍąÉóś 0–ІĘŽ€1fŁëm™ßú«$ęŐDŤ¤ęKn§ąZEKôŇŞ°č¤žęŁ ß .NâŕŃ#8|ô(Ž?†c'Źăř©S8wć´šgg®m$‰cDa¤xŚ)ńĐy.Ň"<7,P¶Sbfá‰oÔf8I aŃŚţ—N:H”'Ţá’č*şłĘ+¨±™O‡—‡[ÚmâTýťńnŰÎóRś(˘€%·ZM´[-pÍv322ŠŃáUÇę±5X3ľkĆ×bŐĐĹç›ĐßЇu¤_„ ŠÔŞIbh Ž±Ń~„”áÔŮ 8rě >ý‡Ź˘Ől"ČR¤yŠEŇóN(Ô?´EÍ€PÜRJ¬CâBŚ — G‹YV’#CĂÁČđ0FGĐ_ďÇđŔĆVŤ+LW !Í•€×rE MéN?>Äj5Ćš±ŚŽôٱ8‡Ó§ĎâđŃŘŕÎOΩ|ĽZCEČłyÚFš5ÁÓ6Ň,EŢn!ÍŚ@qé•>*č%âJ‚J­*űI˝żçĎś~áŮ'dÇ÷źţ6ö)'żo–r|ńZăëáĘŽ€iG`Ň>Ç ľďW?|ßí÷ľýţń5ë6µ‹ČZm ! …ĘŹm˝ ˝4!`ĚćĘŚ20f(̨ ­=:iÚĆQ8ꢔR;…LCA;…'Ęj.>˝Ya)'37 e „ ÍRL\Ľ‰‹ş‰‰ILÍÎ`zfÓłÓť›ĂÔě fgg1ż°€ĽŮ(+JÉÚÁ1Bíďĺ˘\±“ßžťĂE™,ެ’#=Vá ˙pS‰SáqˇV«˘ŻÚ‡ţľ>ôŐëčëG_­Žľľ> b¨FÇyŽ\OJ3ÝÇĽKě¸iő" uť‡‡°f|ý},,ĚăÜŮÓ8|řvî| »÷@˝Ż•J IĄŠ8® J*ă,‘g-diŠ,m!K[Čł6˛¬…˘H-ŇŽF‘LjR©Ö‘T4¦ç¦§Ž]8{öđţĎďÝłcű~ÇŔ]co:­ş¬Đq ^ľ™ŤçGi#K¤ nĘ`˘÷‘¨ßußý×n»ăîk×]ąqăřšµ†FV­ˇ”"OSäíB¨ŁĆĹXH­Ő "TŘ8|v _GĐ!…[a—ά«Sç®Ę^‘«`Ů…C0 -H)Tt€"ÝT{:*ĐI¸)ἷ×Ň鸎€k`7/R)˛q/ vJéĂ‹Q۲eŞÚOY€ dZ $Dś¨ö^\­"` ósf§¦NNž?wěČŢ—íxć©ýş%×Ňwe7«{Ż^Ľ™ ţÇÁ,U;(wL”:NÁu öą«®˝nĂmo˝÷ꍛ®]?¶fÍC#ŁkG)ˇČŇ6xĆ‘óL‚ bŰ`RZŚ qďdÜܾ1˙'¸yCné‘cN !Ć”˘#˝đşš§´ę˛zŁp ^ôá¬ě˝ŢÓ Ő…Óí(ÚŁÄń¦Ôbéˇç=L­Ă(a(Ł8"Q#ŞTŔĹâÂüÔüěěŮŮɉÓçNź:±wç GN9|Ü)̵ťB]ËYŮ]cĎ»»čńM­8€ÁÔşE a)b0©„­5¬ąbýš[îşgĂú«Ż^;:ľzőĐččřŔŕŕhßŕŕ˘ŮĘłpČ…ÜMNâŃ‚AŹY۶˘ť­P⛌Q+4*T‹0ϲ¬•gůBš¶›i»5Ój6ć› ŤůĹůŮéŮ©éů gNOÝżorfzjRŻ»:#O»üž—|‰Ýůʵ±Ż8€W×).7ťp˛.΢\‡`ĄÄmoşÇKú‡†W­Ş ŹŽÖ“j5ŞÖę•Z˝^ “8¬VkŐ #e”Aa0ěӛŐ"—RJ­0$Ą®:J)%Ďó,Ëó6ĎłŚç\đ<ĎóÂC „D±Ä¨ÓÚ*m.m©”ŇǾߏ»÷î=÷žÇĚřÇe ¤ š'9çŹÉ™™Ď|żż9óűÁ˙¸‰O0&4éŹ9®ś&˙ŕě† ~<>>®}ß?ă§\.ëńü¸Ţ¸qăO€Ě'R ‘HŘMMM7lÝşő·AhĄ”˘:…aď~«µF)…ašeźŠť&–JçÄúM›nÚ·oßcAħđ<ŹJĄŇÔzj÷»víz2“ÉLŻřľĐ(Đ)c”RhĄQ2Ć´llĎCk…ĆŔę§Ď›‰Ň‚ąń.&SĂW¬[÷)ŕ€őA•J%·wďŢÇV­ZuŃ{űŰŰŰůËÖç)Ďk!ŞřŘŽ‡a[Ř®K®ń\ňŚ đü›‰Â(а,›B!ĎńÇůŮÝwé«×­; 8k Ŕ8ŤâóÚÚÚ.*‹˛P(ČBˇ Ëĺ˛ ‚ͬ†jk§“I:X2FNHg§1tô‹[WŹŤ—JÄ~‰´çrâਔqL ĄÔű”?€+Ą$Žc3–ŇŚăŘ”RšRJ@ŕOećůź!ČŐR #z_ŮŽR0\‰ąńw[(ŚŹKÉ@_ş\~'â2Žß·uş ł,‹iŮÔ; Ř®KI ‡ö0•HžßJHBXaL}ň÷46/ T©P,ä™˝h1Z),ŰBVřh€é—ÝJ)?BĂŚqŕÓŐÓÉÁ?>HF䇇(ŤŤRTż¦ݲÓ/{ćŃŁtuźä­#o2tôłÎ[ĚŔ±cŕX¨XNYđŃ0>QÄ15ą,2Š@h2 ÍÔ/_˱íĎá «ŽĘ-Ć1ěě ,×ÁrLlŰ"Š%ŽăP·đ<Ň}=¤˛9 ×%•ˢ•˘iţ|f̚ɴéu¬ľä2/Yʲ+ض};­mmŘŽ{J |¨Žk“L'ÍřŘhE†”ú¨„Ží088HE¨(db˘@F ±o˙k|ăJivďÝËńŽ“¨8F*ůŃ ¬_SZăy6 ‰‚ şv–ëVSśJ™t&K2™ š5úúzęr9.˝řbZÎkˇˇľžŽÎlĎ%B€Äń<żmW^ľ†ýűŹÜ±{˙k÷<±ĺ9!´m[Bi…a¤ÝRILÓbŮę5䇆Ie2Ř®C*ťˇVJ.¸Ă4)‡!n*Í‚… ĺׯ'–1´Ś0p”‹U€_>H*™žőĚł;ôµŰľ[×ŃÓM+:;;EľXp\”¦Rń±RRµŠšÚiDQ„éyŐ]Ćb­ŃÂ`(ź§x„ˇˇaŢî8‰é8´Ěź‹¶lýťÜąűëëo¸rŃął_»÷ž¸üÚk2™\V$“iLËć®ooÄ ĂÂ0Ŕ4ś¨Čp>O__?¦)0—8Bc: âĐLŇ55Č(D+…ťH âĄ4™T’ĆÚi\÷Í[ő?˙…wNsłő÷Ż®yé•=Y-4ž›Äµ]LˡŁo)–ea™gç—^x!sćĚÁf5ż„!ĐşšNĺ†Z)4­ˇp7´íŠgţĽEßwÇ]Ä—\ýŮ_=ôëż._Ń‚7«T"…ë&XĽp!–e㸎ĺ L‹«VÍÇ0 âXVs>Ą«“+PZVŐE«ËŁuŐľ©—iVA7Ý~7ß»ĺťM$6‹lm]ýŹîýe_Só\ýĹ뮉t†T2CÂKă8.ž›Ŕsâ˝×Î9á˝ďP]ŮëĽ÷GŻçľĎÝź»žű.ĄôZkÖ­[wŮŘŘŘŁ­V+~­`ůÎť;,ĄpΉě§l“J©cóH)ŹŰĽsďýŃŤ« @Ť±1qÓNčŔKç*«V®ĽŘŃ‘Löük ´~ýú[JĄŇ…ÖZˇĄDá;ŕńÎâ­%M„sŘ4Á¦ iš`“ěÚŮ—Zśł4GöĂćźr÷áaĆg°^4,ČŻ[·ná=÷Üó 5Ý“Řh_ww÷Ňrą|čŃŃŃâ’%K.÷Ţű˝ĺV±eä6µŘ4EII;j“FĂg®eßÖÍaŽVłsĄ ą|žFŁŽwçÖZňaŽfó_đÎŇźŕ37\ĎŐÖş… ^ tł' sŐUW]qÇw|í•îoŢĽ)%FI˙ÎËŢ#¤„$s8 R)ćťľ†ćÔĺJe”1äËÝ<ţ­˙˘21AłŢŔ9Gj-i“˨×꼴wąˇAĘĹ"Ţ{gŚ €üqÁă7ÇqßM7Ýô…4MqÎťŽ$IĽRJ$q"V]|ą Ä:ŹR‚4IA€*őÓ7ŻDćA‚Ršuźřn˙üßP«ÖOš¦$q‚őž}»w2sh’0źÇu|äX?Y*)Ą–W«Őô¸ í=ZkĽ÷Ú{Ź‚#Ć0ĆEmđž¨álÂĽç2µç—äŠ%â("MÎąřÍäK%fg*x¶ă­zť™‰ 5,ˇxďEx'@!BčĄ ĄÄ9‡s!$©MqiŠs<¸Ô’J+ć3gu6 ŹFăR‹M,ÖZĽĎÖH’„Éń1Ľľ^OE()Ź“|˛&˝÷(%q©Í´"Ŕ:Ţ!˘„ś0$BH„ň‘I7ßU¤ÜŰ‹ŕťçĹ=;éD!Ţ{ra€ SÖ€ż÷±­Ř$Á;‹óďŢ[â8áő«†pÎâ˝§ÝhŕŚĆ¦)Q«I«ÝB 1aµŮY¬M‰“Ű-ęő:GŽA ÁŘQfŹL3˙4ÁôÔA!—æé©kŕK_˙µÚ,iŃS4”ň†»÷Ňš­ňł»żLś:„”$I”™P±ęťfjßnFźyŠ­ßýO„V śqĹţ<˙Č=¤Ö‚ łŐ:µZ iŚ AŮ „ŕť×ý5oşęZŇ8&n7‰M”R™:LŇjâ\J×Ŕi8ď§ŕÄTkÍŽ#ÍU•ţh"‹“m 3/ě¤vd ĽÇ†Ŕ´Ú-äţýĄđ#űiŚŹÓŞ×xúţŻłôŚ5ÜöwËÄčÂď, -ćŕřR*Š…<|ň“xżř÷uR¤#+o_®4Ą”H)łčŕÂ8˛X>sř /x3chţüçřţů´¶m§]ębůŢJ»Ý"Jb ĺ2awůîňĺ2a©LľX",v‹ů"Ré_F_k’[šÍ6Ţ;¬Ë2q%ť—Yú-ăŚ3ß@ý[™ľĺVZ;v°rů9ô/^Áôô^H*A–pšŤ&iŃ=oŤf!iÓŽŰ䢥5BI‚ Äy¸â}W’Ëç™™™á‘ Pưbőj.ľčbzčA¤–żVż±(ĄhŐęäiPîŞâ„€ÉhˇCpÖ†\±pÔůĽ÷¤iĚ‘#¤QHĄR˘B±ČöíŰąóÎ;Y˝ú ĽDqĚ;Ţń.ö˝4B§źv§ ă)Rô‘‹r®†6B¨c"„€®.¬÷ů]ĺRk0[© ”BJťtH´ŃÄI‹##„ů<Ďí|žµçžÇâ%KYąj%›žŘ„T2Śs§–‰…ŚÎj“0DKŹ÷)_&ćJIŠ]e ĆC®P`hx!ăcc%¦·§‡bąŚ BJĺ2C +vˇŤ¦Ţhň®K/ep` Ź>ĘŠ«(v3'Ćźš€ 0™ôŚ‘(%I’ä¨ 9çpÖÓśś$MRęZŃ L:D­Q§Ől2[™Ą»·N3jň$Ţ3~p‚‰Ă‡1¦Z­óń?ţ8ą|Žď˙ŕ!ŠĹ.JŤ.ŇÔvĚ0}ŐZÖZňů$Éę})!ގVídh—Eň®®.‚\Â0Ge¶Ęâ%}”K]śsÉ%”/ąÜ–­ôwwsćš5ôÍëcş2K«ăüÇWżJ±«„2m Brraô;ëćCď_Çý?řÉé=]á§ŚŤTR˘TĆuŰí„8N±Öw™ËÔ,žL#•Ę Î;˘(˘Q«1ł?ć™íÔ¦§s9ĽŁ5  sîÚµ()¤\*Ń×ŰÇTĄ‚ő>ë(u´üż¸ďǸňŠ·24<ôŢ˙~ŕá/LNŚ^x×ć§ybËf®|Ď[:XE1qśŇnEXçp.{‰@°ęĽó1& Š"ňą8I ó!˝‹–łp°LWObŐjt`ĐF“/iFSłł ť¶€j˝Ć˛ĺË9}éR¤LĎTZăť—'öż€1ąŹnüŮ~tò6>ę÷ŤîGKE­ˇ´ÁyŚ1c(• AŔO8ĽsX›Ňj4¨'›äi5[„ąđą›o˝?˙Ě'^°é©mWV+3ë?ÓWüó/ěĹH%J….”1Xš8k; °YÁďŹékúNópţâ%YNđPȰΡµ"ěîR@ˇŘ…¤8!0ůśđŕSSH))K4˘´­G¨,Aj©Ř˛ý—7>ůÓg_Ń›Î~űWn˝ }÷}3ŻoŢąQëoüŇ?ű—FGD©ÜM`ÂŚÚiĂ`/Ţt3­v!%R(„ĚH˝‚óN¦EXC‡Çéëé!ŃVbă"OjTĺ¦Y$ŤZ@Ö#˝áĘ÷fĎĚUµ€)°í(+Ű•äńÇ7áťCkÍÍßü§ťvÚŰ}|Ë7Ţö– ŻŰž?đÄť÷|ű˘›n»YôöÎÇtx©Ńm”R|öÚ«‰’ôh -¤DIRaZ•¬ű68@u¶–©˘Ă_çď:¬ĘĎÝĎś^3 @ „§÷ł÷„R0}h’@)>ö—7288ŔMO=5 łBM]ôĚsŰD„Y1%$Z)¤Ň(ĄĐR3zp’Ô:¤’(©P2ăŞBJv Ň4eů’ĄH©:škˇ ć"ŢýôYz͢–8ľK}ôZ’$eúđ!śwH0ą„$jÓß×}¶Ů?Âeďx}ď~’î”Ŕ40: ň vď}1k—kQ­5Ji„P,:sg7nü•xý+:ć·ďźX<žŘ—ęé.ă˝cŐYçĐl5ą÷ţőó5Ŕ÷zhöźţáď{îýţýlÜ´ ĄĘ(Ŕ:‹´)I,Řłď%”4FÉ€@k”1HőĂ#¬\¶Łďěx´8nVäɨ AéĚÄ ŕśóx^f_s]kď=Ź=ů>‰ů«O]ÇO7?MµVm*€e«×,Ů?qá—˙ń‹Ô ~ňÄc ;Ý7!­vL;Љ˘„¨ť' í(!ŠSV-[ŠEaťŔˇđh/5BH˘L=w†y‚°@+t˛v©ĽTX‰8u´â„Z«MµŃdŞ2KOOxĎQ«Őüîö4×ßyÇu `Ç/·<˛âěµyvű®ľŹ~đCÜpÝ übŰVöě؆SúĺAŽĎ¤ă…Çwx sŽy˝%ŇÔ!T@ě% ťÓI, ' T€Ěĺa•Ë!§*Ő*ŤvL=Š™m4™m49R­1S«±˙Đ!rAŔągžĹš•«Ř»çE?69!öěyîň/˝¸çX-—ţôłź»wpţđşĄĂ‹ü…ĽN9Íż}ő6îşď;TMSčî%_č"09!g._ŚÖ† ĚŃpžÄÍ™Ś$MŚŃ„ů!  JI¤T$iD’&ěŰ˝‹8IńÂ3[­Pk6iGmÎ?ű,.8˙|ŢwŃĹ<öŘFżk÷^QčîŞíÜńĚĺ›üř¦Wś‘˝űůđŮk_÷ĄyCKzćůĄË–% ‡™84É˙ŤO=ÉŽÝ»ź@Kä§/^L„hi°Já˝Ä ĐJá:EžŃŹEH‰'łďvܢÝjr`tˇ$«N_Î/<ŹłÎXCď|öěÜĹ ;÷ř‘Łb`xĐĄi|ëwľvŰç€ú˙9ä{ë»/űë˙đ’—,^¶®§ÔÍüî^ć÷÷Ń]*“Ë…4u¶n†]űöqdzš‰©CL>Ěl˝N'Dí(‰H­#4†0 1ĆhCOOózűčéokVŻĆ;886†uŽă‡ýÖÍOŠÁ…ýŁ^J]rË}wÜ~ë±?™)eńęĎüŮĺ§/[ůţááEoZ8ŘWî& „Ď"•MӬǏÇ[‹đŕ:ýţ4Młic;˘ŃlRŻ7¨7ZĚTf82=MµZő»vď20t÷•N‚śÚܨMß˙ýoßµľYťÝűZNęĐó‘O}úŤK—-cW±´şP(®  /0ą%AŞÔZ˘v›fŁIÔŠhGí¬bőŹ M-ív“v»5™$É”Măý^Š˝Q»ţłżőͧ[ÍÖK@ň»ř«î ŕ4Đ˝fíy˝ †KA.TS‡&š{ž}¶RŻVŹqgLťX˙ţř˙xü¸čń1DnXIEND®B`‚gammaray-2.3.0/resources/GammaRay-512x512.png000066400000000000000000005017751255003167400204770ustar00rootroot00000000000000‰PNG  IHDRôxÔúsRGB®ÎébKGD˙˙˙ ˝§“ pHYsÝuÝu¬‡ĂtIMEŰ 6Äé4ţ IDATxÚě˝i°e×uö­µĎą÷Ť=ˇŃH AgŃ$Ĺ€˘HF–D3ĺJ”¨\‘mYV&U%'•RŞâ˛ý#N%%‘Ęq1®$’\*E%•¨Hˇ,Ĺ–#II!! $čFŁÝhôÜo¸÷žł÷ĘŹ=ś˝Ď=çľű^ż÷şűőţ Ť~ýîpćý­ń[@FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF†Ĺ•+WňIŘ!(ź‚ŚŚŰ‡K—.ářń〵µµ'EäGĽŔSîĎR>KSXđš1ćk"ň§Ěü•C‡}˝ýLed #ăŽĂ›oľ‰űďż7nÜxÔóÓ~ÂłlŚÉ''#c~bf0łđ›Ěü3‡úZ>5ŮČȸŁpńâEś8qW®\ůüĎ>šI?#c—¬QJ3żBD˙Í‘#Gţ7˙Ěed #ă¶ŕÂ… xđÁqĺʕǵÖ˙;€ď7ĆH~32öĆ`fđšRꇎ;öţĚČ@FĆľáüůóx衇péŇĄ˙ŢóźeâĎČŘ_C€™˙ÇăÇŹ˙˙,fd #c_pńâĹGD䏼5‡ű32öĚ WDäqc̵‡~8źE>{Jţď«ëú›""ůlddÜ8Ăű(€‹J©÷x1ź•ČČŘKň˙p]×_Ë!˙ŚŚ;ÂĚTĹGNś8ń\6222v§OźĆp8|Ęó}äďB’ÍCHůQ<ܲËKŞĐSA{°!ń˙Ůß3ëěůş€§Çăń‹Ź=öX6222nŻľú*”RGŤ1—EDDĚ E„őŃ7×Ö°ľą‰ÍÍMTµF­5´60FĎńDŇ->áĽó%b'5Tß7nń`ć:-ż(-RÝéąŮ.±ńv®"ÝŠ}g,çÁáĺe\__ í®Q#}[J1ŠĂA‰…á+ X^\@ˇŚÜ3 cڏgóÖúúŁŹ>š €ŚŚŚťăÔ©SxűŰߎ3gÎĽ""Ź]xă".\ş„Zk:´Šc‡Ź`yyK K( …B)03č*čz…zŢß·ěvľ]zľ§w_dkňťcŁ´Ýĺ¨ő=´Í÷ßĘâ¸m›Q"[Ľ>ß×ËŢľżëĄ˙˝şŞˇĘrľ3%»s>€ŃăŞĆ¤®°ľą‰›ë븾ľÍŃ 8zÇŹńç@čäŰŢö¶wůg7;ĆkŻ˝ö«ůk/ľô26G#<ö¶·áˇű­,iU×ĐZCk<‘Ś]ô#ă6J) ĽôękMĆxć±GAĚ˙ÁŰŢö¶’ €ŚŚŚmáë_˙:Ž;ö‘7/_ţęćh$ď|ě1ZßŘČ'&#ăĆ`0€řĆwNĘÓŹ=BeQĽ2™|ëÉ'źĚ@FFĆÖřîwż‹˘(ŽÝ¸yóÍőńŢúŔ4™Lň‰ÉȸK°Ľ´„oľô˛<öŔý“ápáh]W›ďz×»˛‘‘ŃŹď|ç;xňÉ'ńâwľsöµóç~â±GióĚ3ß—#÷0Îť;‡·Ľĺ-řö·żýecĚÇ™ą“čýĎĚÜ»ÍZPű˘]‹_W—Aü}nKö«Ź\ç!śy Yďí#śy"#]źmoßÇV˛ťBL ×r+‚Ţjg}ÇV¤:ŻÁ˛㪏繆}É,¶Ďl“đVű<çfž{łMúí{0ó?xę©§ţa622îíŔĎc~:&{˙ÇO÷k}oŮďtáßę=;őv™91 ¶ăEĎs|ó1[‘PźŃÔ÷ó¬ôĚĽçl^4ň$#b–Óç­ne¶Ť˝Y¤ÚGâł"Wł®eź‘;‹t»HxRŽŤĽř»ĽÚć¬íw]?c’m´ÖSJýO?ýt622î5śkžÚ‹.#go·Ď hVW¨~ę{üůiť§y ŹäőŽĎ·ŻE†^Büţžh‘~[}–:Ţ7k˙ü ź6·ÉŘz›ěŤ;¨°»ŢßioŻĎp‹1FŹFŁĂJ©Ť|ŕŮČȸđüóĎăČ‘#ŹŹÇă“Däçw˙ÜÝś…€Ű1úČ3,Ús|v'ŰëJô}n«ďź7tß]7ę°ŐwĎJßôńO}A——1&"ňí§ź~ú=_˙ú×ńÁ~0/żü2~řáÁ™3g.Ń!f¦Řëߊú ść!µííN Ś­¶ÝGŚ]ąäíF>ć OĎsĽmď^ňď‹něćhÝyZĎnĺµ>Ca«ÔGű:xCŔ˙Ý&÷­ŇŰąV}ž—Đ&÷­ Y©Ź>#±+ZäŽ#P×ő?~úé§˙ăČČ8Ŕ8{ö,ŢúÖ·âäÉ“""ŠCţńBŇ—GěZ”şBĚńâ»Őbµ2źŐ8OáÖvşć-ëË{oµ@ĎCČۉ tť§>ë ÝoçzlĺŃĎŠlU<8Źa×Ě*Ş›×řęJCőíÜü,o|V=Ŕ<Y÷s×~vE7úŚžřy®ŞęłO?ýô?Ë@FĆĆ©S§~ÎóźxϨ«€Č/p±ç˙Ľ•׿«ó!čy=ăy ˛ŻíoÖ"żRß*z2‹ř¶ÚĆn´vóĽQŤy=˙힇í*;ýžYâVó묢Îí\ëy÷ŁËHéúăS|]‘±_L7nÜ8Ş”şöţ÷ż?0đŮÉdň…>oWk|­uB]aÎYžńvŤÝXÜ÷}ˇŮA·#$óďNI{–ˇv;ĎÓN®ńV5·zÍf#[ö,o|ľ´Ť`ľŇ‡ů5 Ú^\Ű˙ď›R*Ô<ńÄw˝:P622"ś>}ĂáđÁŃhtŢ Ôă|dślő-Ŕóô%ď¶8ÍÝb$t…Ë÷ű±ťýĽűzŢŚişüźą>‹¦8Qb€@Sďzvüg €ćyf|§EłIPG O\á ĄÔT§A)ĄŞŞúŻŢő®wýýlddx±źS§N˝jŚyDD(öD=á·Z„fVÇžGo[Ű=Śý$­ýŚśěővöóx’m©*Čdh !h8ŠbF¤¨Ť`R Ş”BHżÖ‚JU h ˇT@ˇ¶ żŻumĄh0•%¨Uđ§â(@ź1PFŁŃEäď~÷»ł‘q·ăĚ™3ż¤µţń8ÄďĂüł<˙®łëç{ťě÷;}qĽü;ἙÍMk× /]B}éÔâ"Ô€Ź:v¬W{Ŕp}]pm¸xÍ`ŁŽŻî[Ž-Ă’z ęƸ±)¸tÝŕʰ˛H8qpd8˛Lč;+RU0ׯC_ą‚úŤ7­Q<đřŘ1¨ŁG˛ś2TşjĽîŹ0óÚO÷9Ü÷ŇK¸ŕęCááźú),|ä# ˘čěŚčR4Ćřü\$H"˛úťď|ç O>ůäżv7>źś—ýŚ{§OźĆoĽqd4ý_ZkńĽ'ýş®ˇµNŚ€¶!˙Üö$ÚĹF÷áÇÝ»}ě]}ŕńůß«íůČOűúî–§Ýu/íć˝Ó·­ŘXťą-fK—0ţÜçđŢńď]YÁ÷,._ý*®ţöo‡@÷őţď/ŻăkKoĹĘGÇáO<Žę±‡đóż=ÂŤQżQČ Ľ|^đ ßZ}ŕ8úŻ<ŽĺŹ˝ż˙đĹoL ¸˙Xd4Â…_üEĽďĚĽoeZZÂý/âÂç>lnN§7öýľű5Ŕ˙©ëUU%ŹÇcŚÇăĎ~űŰßţ›ŮČȸ ńŘcŹammí÷«Ş‚1†Ú~;ôßĺÝß+ßG&mŢMŹu+’Üíó; ‹˝ş—vk[Ł—_ŤFĐ&"`Ç‹ßü&¨(f\ŕů“%2™@Ć5Šă+¨Cś}Łî­!$ľůň ©5d\†Ćó/U`ôš4ŁzńETD¨DpĽ(€óça67§ }!`;˝çÉß˙˙ŃZc2™Čććć?}á…N<˙üówŐsśS÷<^yĺ•o2™|¨]Đ×ö÷‹Ä˝Dúť!ÖháÝMÂď#®ÝŢÖwĽ0/ FmPĹŚc J†ąľŽúĚ%đ‘e1Ä””¸»ÂŞ(p¶®Q2Ă8‰äy˛Ú×Hk=%—ěÎ-c¤®ë?účG?úÎČȸ đâ‹/âµ×^[ŮŘŘř'UUI]×!ěçîĘůďŐ˘}§{űűĺ©¶S»µ­[os;}‘„˝ŚŽômk·¶7xűۡď»ç'ś×gŞ ë«ß÷}Şę˙ >őÁ!&g®˘zőML^ąńéË8˘&xř„˛-~×GďyW‰…Ń&&g.Ł:săWŢ@uî>ń!´™±łĂ!>úQĽQU¸ 5^«*\LP>ó °´4×˝ĐunăH@´VP]׏?÷Üs÷nz¶s@Ć=Ťo~ó›żoŚů4YĚ@˛;ęqwáďĄÁÓU8ą—ĆŐ~îÇyŰŻcJ®sů2Ć/Ľ€‹żř‹ĐŻľ ,-áđ_ţË8ô™Ď`đÔS€éfdm€SoüŢsüŢźŚ±1=Fř[źYÂ_z‡ÂňB÷=@Î]|ëUŤ_ţ6pţphüŐgđýď-đΦ§„ŔlnÂś:…‹żú«}ő«€ň™gpâoü O=^Zšű™îš6هĹĹĹ·h­_˙ČG>’ €ŚŚ;Ď=÷>VUŐő…˙Ú‹ěA#˙H\űiÄě×±ÜIFŚŤ`nŢÖÖ kk¶đďĐ!đĘ ÔáĂýÖ77F‚›# 2Ŕr ¬.‡ …ęľ6Ć‚µ±ŕć&aŁ 8´¬ ŐĹă‡ëfm ró&äĆ kś¬¬€:*Š[:O=çK”RöěłĎŢÁŮȸgńüóĎźÔZż:VžŘłżß$|ĐĽď.Ăbݶq§FGÄ ®!u q9q*  (: µ9@+T+ë«(”%ž±MmF[ŁA€É Š xĆ˝ ŃR×vźElë_Yîüg­ í:‹ápřo]»ví7~đ0wš÷_–ĺ÷ŐuýĄY˝Éëż„ż×ç0‡ő÷9:"!ůB:÷7"™9'€`5ý)yë¬MK¬ r˙Ž˝đŮ÷Bř·Ýďë6Î뮏(Ą.=űěł'r #ăÄźţéź~Ůó¬]ö^—ż˝üýĚăď;GG¶ýĺS$Úî’é­Îď˙Šąß+FĚvÉ'çŤ0 ~h<˙óO|âŮČȸĽ˙GµÖ§Ť1Âłż' ĐX˙n6b˛‘9ßW1ó?ţńŹ:G22î <˙üó˙µÖúżŘó‡«+ܸ‹µs/í_Ëöźüť-ľ[˝ÇŽw m‡îÝZ ŘI’^Ë€wżűÚ÷ľDfËNďq÷˝ţ;·{/P÷Ö Ó:_{qîeY.}ď÷~ďćťşf! Ś{˙î^zxĘ 9wáţĺ|c°°¸„ĺŐŐ°(ąUJn–d1m‹ŞČ‰‹˙„ôsíÔ*)Ó+¨Z“٦¶0m@Hß÷JĎnř…Ýŕбn\|Ăęľö-¦Ň·Ű’Ś@zŹQfěb:2¶oA7"3ż7ţŽ@(]vu‘­¨«µ‘ą.­ß˙X¬§}=©÷ŇIĺi62}ABí¬{®űˇéż¦Ń?™9Uá _-еF5‡›XČ~ď}n@‘%u , '|ďG>ŚÇŹ[ů_clĂ.ŠKEbb?ŕ粑qŕßřĆ#Zëű÷ęűŤĽřŇwńŤţ—Ż]Ĺ/ýü˙ľďîŕN<řÄ„ZSXTĄŕ¤ÓŁ’ů­ŽĎ‰Ěä˙tß‚D; µçbb‚DĘ-ÚÔxô)Ű-őę_|¬Šäc’Z8č0EbÄ bt·áŃwÜ"[ś×ÜĂ÷cË÷¦§ľË’ű…!2í™nőýÝçcúWJ)h?714g{ű|QŹEŠa´ž6D¤{?ămŃ Ö˙Ş( TU5µß"Ŕő+—šŤůżŤÁăď|' ¶Ë€ÁESß~ó'~÷=Šgž|Ź<üV(ŢŮ Ş-2…ţz622î<÷Üs0Ć|jŻr˙7×ÖđĘéWqăćM †Ă!@ …R”,,.€‰A¬P AZn…Ĺ’Ú^ľ÷nĄĎ›•ŢEŞkU•dkŢĂ5Ó„ŰZé)YĚ[ § !t9ÎĂŤ ĹtŤá `aa ¬T§ *Ř‚ěŚ÷ şÓĂ•†ň¦Ś"JČXbfŚ˝]0+Łű.t±ˇŤëŘŠő©ŁôĹŻ+VĐZ»ďl_|I" Ô>‘đµ¦Ç+Šu+Ę"îCÔa°D1ްŰńµµŰj>¨ˇYĄ÷‰Č¬[#l?˝Ń¨ó:—e~?-W._r)¤ö}Ç€qm†Ä(Ęe9Ŕ DY¸vý`^Ă>…áp[FŔ2ŐdŚůĐťĽ&f ăžÁ‡?üa<˙üóźÂŽ˛ŕł±¶¶†K—/Ł, 0+¨Đç°3ČĎŻ `nqMłŻç-‘–‘bLp »‡5»ĂqÚu› !Vi{„2eśt»ć2Óë#¤†fFY– ø7[:­ŹÔč==żÜł‚ Łśgyűl挓Pe o÷ď˛47'ÔÔběwŘ6ąÔi.ˇeÜĆP°ÇbgÍrG(ixŤ>~rľ JŰäü iĄ*cÂýfÜN’LÝZÓQŠ.ĂN=J©Đn×€­3w¸U[ÇBÜJ„ĹŽAˇt¦'ÂÍk×PO&Ń÷şë"€A©„ě5!b(V`vŃŘ. ¬­ŻmÎ~KÂo{ţ3uDđÇüÇźüŘÇ>öĹlddÜf0óű´Ö»Fţ"‚ş®±¶ľp&YŔ9&ŠeY€YA¸Đ °-d¸őü)aív¸SBČ´ý»ÔŃě űwxŔđO”‚$óܧ·Ůź ÚF‡ű~¶C\<ńéşĆ`P‚@ 6ĐŃh燓„DdT0t­#éŘsiÎŹtxŞč4`\ΨkŞ$¦ŠČTcšu¸ůá» L ĎŮŞP‘‚ÄË—v”AfD‚Zo,n`9ňUŽB$ç.ć~Ab’/ŕŚÎQQ*›Šˇé{Žť! Q©}ťiŮúHZÍNëxs7o¸TZ|m ĽM¦T!ă"„˘PŽüŁQËîçÉdâžaÚ˛ËaŢz7—ác˛‘q»aŚyt7żŹ°îĽűovŢY©3çń±bei#EńÍ1”bëő¦rQ\hŐAJ-Ě1ůRü[Gynźş3&’đ>źăn 4E,=Iu3˝â*Ű›?i hcż˝ŇÖi‰Śé ‹.ňw4$e2Ć“« '˘ Ťçßěks¤•/•F­+'dÓ`$@ą¸`#:Nőn*0ĆÍ”żâ‘7¬¸)Ƕ>š˙č[ŘE±‹»öSäď«őý{IP(†D)qűB÷†5Hmˇ¦Űhj\şJTѨŔł ®4© tLLmĐ®ČRú^ aůß3^~ă‚}ÎtËŘ "AAdŹ™ †"gtŰKeźW4BFu]c0ěćôIđîśȸm¸víÚ_‡żŚŘꍪ^‰hKŃŽ"ÂsĎ=·«-RUUˇv…U{NmÁë°żS(TUĐu…˙żű0Źí"äđŕ§j@8°DLHŘ®iB˝"M8ňüíßµBőq^Úy{¦ 颙 i㑤Akä¨ Ř 4Ęĺ# “őĎÚ"AH´;{ .>'n~¶LľŁX6q*fk  …x˝oŮtáčłá}“Aó{V~űç˙'ś{é%¨9Ţ‚—@Ţi[`ęq«˘°ç? ńKOÂć"}E‡ţwěÂębl^+îŽzH;ňŕĎ‘jŽ%2L‰^+0[Ăß'i\t#HśźŠď"jö+DĂ‚%beIśgÎśqď‰p‰¬8ű·*ŘžgWŔJŮ‚@ÄmşiäÁŹúŢ­eŔ{˛±ďřÖ·ľ…ńx|żüňd2?ń®Ď¸Â˙ĐZŁ(ný¶÷‹gUU!wîë@~qq„dÄĄ”R(Ë_ü•_¶äQvArŢ#7¬Őň\Ť[3i:´L)GlÔ¦Yţ˘čóVŢ•TSĺNŃ~ř…Ű_Řf´6Žś};;ýŻŔ¤RR€`ĺřĂ Ö.]°ďe„‚.‡sއÁĆm[ĘĺrYE‡Dţ@ÝűÄzčî{¬Ń@bŁ0D±`ݎą.͵·íćýj0Ŕ§˙ÚżŤ_řĂĄĹ`8ůOiŘ?őTÍëTA0FEů“ćó!Ş’xÖ)ź&žżő™#„ Šą1ôť¬oř˘–9g%{› ąZ{/c*OPŠa4ą{GB˝Cóőöwś´r’fiîOŘH 5ĆGQ0 ĄpńÂyşę÷·#W‘‚a ;fv×W%ä/‘sä‡úĐŶ„<ś €Ś}ÇűŢ÷>ś:uę«ZkŃZSéďĹL÷;Ęĺw‹ü@ű(QÁź÷d!Ú¤Ő †Rn1}{µPË»ŠÖt4Bí¶5ČXŤs8O‡âĽ.Ytżs«€Śü÷nŹ˘q˝UdĹăZ)éłö¦ µR쌻sL[ᣖ ŁďOűúł 9OPüń†}6Qq–X’Ąŕ‘ú( ýĹKˇ Î”‘;ˇDUŕ7q `éĐ!<óŃďĹ+ö-Gp–Ř„ě1×ŃOĽx±ÎŞkAc˛Ţ­?®%HÚĚÜç"Ϛ⌥mĄ±·ŻHŮ}güxŁ„bšw›{ߊ+v´q—Čx —H’ 'űĹ-ů^ŔńQ'f é&‰ŢkšX“¸Kˇpóú5¬_˝šjFÄ)łŐŤ-´µ÷bcÄŮú€´ť“ÓBD´ÝQÁńÚĐJ!Î@Ćľăë_˙úąşşúö.˙^#˙ťD9¶’!őąRŞS64¬EĆU3YˇšŚíż Ű0mTC€h“YçÓťNńFŠÜË›Ł$J=#Ÿ˝Ű¦†t%žÜâ4(1 éőM‚#b|ä‡?“ú'ŕÁ 2ElLM\ ĺx‹ç§ĐĐu˙ůHFđĚ%- D.ŤÁFű’ĎźSş_É˝üÄF˘+䋼řŽń™Iź0ť>˘vĘI"Ł#IMIt9$슮'öâfç IDAT¸ôú9 iE»íqĺ€5ršűČŤ‹pĄ,! "afš§%pŽV@d cßđ•Ż|EQĽ}eeĺď„đŰä/[…ţç°ä“×}®Đ/ě÷ß…v=ů+(fE3©Ĺ ­`ťGĆę(DŽ@žÁ»N[ďŹŇŘÎłumf~á‹I%ň_ ď…4F ęFúwŰČ“ôá<ůĐyd€Ů"ůŘű´u’>ŇěŞMŮR’·Źóń!dQP¬,Q7YŠhűÔ+„(ŚO!ě§âď÷%"E;(Ř …!řÔ§ńÝçžKĹ#T#"ôűĎJŮ6:ŻMľEžľužb˛Lż?y[g\…€ očÚ€ĐuV*DŚAQ (ʦĎm“ĂhiRěR*®Ć‚ˇM0qˇ¦€¸9?±AěZËH"Č{‘â‹5%u¬ŤÝßĹ%ĽóC ţ•/Űz8VĆ‹a(^đŁćrk¶%_‚ŮäĽJK®>Ba´† cµÖŁş űş©u¨—HBŃÎŽă¶ş&<-iHşi—ßá÷/îů[\]E=™ŕýźţź…`wÝ˝1ĹQ´ťá—ĽÎÍëÔőzóůřŹKŔOo‹ŁBFĹiGCňzł-io+iqĄ¤Ř3ľbˇźÚ:…ŃŠsmى…Č—/]Âh}­IůLýˇž?pŔÄ|7ŔvÖ‡öšy ˘˘™.~çw~‹‹‹…Öúç|đA1ĆP›üďeŇŹC÷űiɇęűhˇ+Ę”˛-dŞĚ›śĽĎ·r PW}mĐJ4aż8Ű’7ß—.ČŚŹ8Úäú)Tą7…tMˇ EFz÷-a-C ˛$Ľ&Úő©Ż€PM&Đ“Ęőp7Źj2i˘ čş ‘¨u í}l")ĆٲD ‚Blâ HäR#äµ Z“|ĽŽ+…#Çď‡Á·˙říľS‡—NHm;˝ř¦2˝é"h kŠ{ýÝąI†ĺ´'F|q¤@â×ZĂl’}Ą×¨kżĄ)5‘ę`ڝГ4o€ńhŚKç_Ź Ţ[x ŁÚέmvÚµő&ű‚Ď~öłř­ßú­˙ő=ďyÄŞ•ô¶úÝËFŔí8öĆ;˛ä\ ĘĐŘŮZv‹t˘¨G~š›4ş,ˇK*ŞlŹI˝}¬‹¨Ď§3RtÖ­~Şđýľ’h„÷ ą#Ő ®NÂâj7€”%aĺÚě¨e17"GQš…"/ĎKcśH;JÂÝů!ĎďSaŰëGi…ţ ÉńPäőúďe’+ÇŽâÍsgńţO~ _űť/@EҲIëžďˇďĚßwŹŽŁ)q¸Ľë3qŘZúňďŇż­Î\÷6fM$ź -ůăY۲r‰xő•—mŃ_lLl?çÚ.)ĚÚg-Ł,{‚_˙ő_ÇÂÂÂĂeYţä>ş®{+˙3v÷źűýţo#(;ŔuřžwNăîQ3 "i[Oţq/s8Ä­žä%)¶Q€¨÷Š h7µOÁIj(„\şëŹ ň‹âşkôŘIŃ{] „=¶"xúäŇĺ`€Áp"¶Sŕ\ľm`'-F…]q[#M ř4ő;q“_ÜII/żŻ'°Ĺ–ŽÜČ@©ÇßňÔă1Ýwkׯ%-˘ü;E–ÚŢ´DäśÜx‰ń<ämÇw˙´ňŰ]†Dh÷‹#ɶZu­™ Ň2zd†!4qúÔK»aí»O‰ţěĺzp·fŕ€ŕGôGń+żň+żđěłĎ†ž˙ľ0w6¶÷P÷µnó›BS3‰  íĐ ˘°Fâ|k$ŇÖ{¸Ž@’,»Y'˛°i¸=™7жBnMĐZ§´F€ćB‡‡Žm9ő $˛R9»đ»ŹŚÂőh‡D J3”kéRŞ€" „4 q´ÍH¨GÜl†ćµČĂýáÎ?µŠZÇ| ů¨Ë›ŔbŻĂˇűîĂë/źÄ3˙8ţđóżr8L<ďdHĐ<ä-=†ävČŰ™ańµß*âLěŘ×ŘŞ™~^±!‰Ň 3Žő/śÇxł]đwëëíâš°ł˛qËřüç?O®¬¬üŕ±cÇzoƸµ^Rńż#€|N\ (n”ăî RŔy|LvÜ-Ĺ /ŇŢră”Ö¤YłHäÍ#é+eőů:2*˘"Ŕč5·ČŰú‚ĆCďôÇĺ­Äť \(§Đ¦ X%¤«k‘Ś]'GyekL0AhC ź—č\{¦qCbŘÉÁÚ:×€č‹ď`ŐăöJc Śiž'ö t 0ÁţÁ^Ó·ĽëIśţłoá·ż—ĎťŤj*03„ßö¬§fĚ™."o 7ôÝűů8„?s_;ż4Ü_f‹tCLĚÁĆú®^ĽhC˙{‚[×Ůď:˘ldôâG~äGđkżök?÷ţ÷ż_|îżMřÓ‚"űÂó±G?śFĺ`f[¨˘JoŠ[ű’tĄ8/ÓëśS4/FBŘź%­Ó‹ä:ł41×^ç«ĐÓjqľ!É"*Ę“T‚7RŔăBÁhĽlH»P¨`yŕ&ÁĚ(ÖPĚIÔĂFQ”öŘ´ą”yCÉl»jmÓbĘŤ 6¦ůLx^¬ ť«ŽŻ* Ôµ=÷JAČ´*ă­¬¬¸ęrźv8rü8ßďýÄ'đĎá˙Ŕ`a!Q¬Ű:„ßVúۢxny·$˘·N7ČÜé†Ř°®ÖDW4)Ţ}ŤżÇÁŮÓ§»ÉźwöčQt›nw-8h„ź €†ßýÝß=zôčŃĎ,--My˙ń¦˝+Cx­ń¨Ĺ``G+<ăińśiĎ "A`…"Ă x|‘z Ĺ^>Ň.„dt@ä-e’ű¦='>)ČsfGwz‰šy/>ĚÎb‰ŠT0TYX}öŘŕh ŮGrµű~Đ  ísĆH›őš€R ¦u]CWUÓë/Đ:j•äHČÉŐ¸2ľ5HKq˘-ŕ÷ő-O<Óţ˙ŕ÷ŕĚ_üy’ŠŮ:„UüËvŇłňďý@˙ç›qŃł<˙öç’Šj >ęzţČęöż|ň;ťFę­;ýbç>`ľ(h¬ôy×ÎlÜĺřĚg>/|á ?űÔSOI\ůßedď˙ö[ôâ&ú•N.V%HqZöÄüĹÚJmÍg$ęKďËR„€D`gHXôbíŠĆÚĆrëÔúNJôčýĘî­CËś˝ ”* ó+F¬€důP†v~‚şA(ôĂ]Ä8‘+¶…ŚÖ0Fśô˛ťÁPiťč4u Hkü.0'ç–•‚¦Ö Ü;Eö§Ń×`,®¬âţ·>‚á§–đň7žG9FşřÝJ ‡vµűÍiĐNĺßgxŢ]Q€$„?G]B/ůŁż;!¶ŽÎź{ őxÜ!ô“‘ €Ś)|ń‹_„<đŔüHWĹöţg[řűn|D޶*‡`Ta#ěŐč’Ü9K‡˘´H¬FşššBČ·%°â~đU,Ů"xwĆϕӊ´4ĺ;¦áz =řĺŃ=Ë*fh‰G­Š-ň#  ‰J¬Zči ФČëňG{Ha·˙†šďKVµŘp˙`0´óO/L§R%C˙ł5:Rľ¶Ű*‚„űzăŤM|ŕ“źĆ _ů¨Úöäöď# šŻV`y'Ş]a÷é}™ÝZHýž$iĂĚŽÄ}TV J» Hą‘ †(v ŇŢcő˙ŤHŘ+;…Îm#&J9Ĺ<A¨&•őjŁqƉdr3ݶźë €¨ °‰4Z±”°M8ţÖ·ŕC?řCxá+_JfÍOIĚ".Ř$@Ěů÷äÝ‘OF˙öTáĎn÷‹‹K[a˙x» 9»uĄqţµ3[’˙N¤€Cšś^c7uîöÁlÜĹřÍßüÍňŃGýqÎ’üÝ "»×ÉGÖ|Ş–Fö!@UXA &)Ž”="=~666±¸˛&`yőDl…:%xP`Ŕ‹Ť6±zřĂĆ“ BŔęˇCX=Ľ ą Ş„Z,Q°˛9yU]ŁŞu“ ÖtŐ¨ŔçőChĘŕ‰Üě@¦âŰý0 ˘°ŃÁDŞăłŘ&@42ni°GôR·Á{ŻčwQmÜ<ú˘°ÂGń0І#9µÄx¶ý· ŇÄq„Ů%fâZ§}°r䌮ńěżńoâKżńk¶p±ăŢšęőź™ß‚Ľ»ňď"Éxŕ.#µŹüăş„¸çż‹ü}»ßVÝ ~6Éé—ż;gŘ˙Ö,Úű5ánڶfŕ.ĆO<ńźßwß}‰čOüŔµón±Qp§HTîçòťŮŢ}‚Ôá=Í»úÄ’˛j8APeHPBŽ9—W®\0»kÍÉĐ•rXbscâ‰Č1›“ ÄŚŤŃ@_»áćÓÖF›PŐueln۵#–J5SšY„­X@GęÁ§Đź-žĚç%Â;ě-íůi¶ŻU‹"°˛KP9ů]!‰bÔĐ:!H&Ç[cGćĚ­¶E? ‘šY ŹVŽÇ!#ýw<ů–úH1Vht'¶±OÄŞ6" PĺďýÄ÷ăËź˙u\ąp!şď·ö6·$ďr»ŇŠ(fäďgĘ7E˘]Â|­‰ `2ăâąłóýŃ­…ňwč"ţ†lÜ… "L&“˙¶Ş* ”*q3ň“;Âj÷zî?)Dş -€~‘\^]Ś 5J1ÄGÚ×ͻٌ0 Đz|QJŰë˘{ ,WçűO)´HP"LD…˝z ¤c‚›}ę §ZŽÂě@GĐĹ€˘”dBˇÄt5j¸7şŽ'Ç…F,©;ľŃ;N6Ű!Ëk# …‚ŻMg•°˙P¤ç@ZăÇţÓźĆĎţť˙ĂĹĹô Ě!í Ě.ľ›•¶7ŕ§Ýî×7ŕg–ŃŇîNđĘi?ägžúLŮ8X¸xńâŰëşĺ §)żłő˝a¨hÁŮżcí(Ž#Âő×ĎCHPx! 7€#OAx0ZáWřg´A]W(ŠÂĘŐŠŘŞqÇŇeQ`âÇćv°›ĺ¤4¸ODĐbB¤5ń$É„‰zÝ®UZ)ĆQT÷ŔÔä´ 2P‡¨Ż˝‚ę®:Dìvb_rßÉL0bZgź#&—–Q4ťŕHIVÄ*Ö:ńz}´äŘąÎ?Š™Â5E4TÉ@đčŰßşŞ0XXěőÂw4ťo†Ü®é+ě%ďT†ř–ü¸sŁHáŐ—Oö‹TléÇo÷ńciě0úżsC?:˙wňHŕlÜĄ`ćfš\äőçľ˙˝7pvô`Sş¸®on‚HP”®\ 5ă}ĂKŚŁ C,/-CX_[ĂhcŚŐ…V——QWZ4JUŕÂů‹X^)°¶±iőéĹL-¸ń8ذhq$#8ëř¤ő=­«t\˝Vż6:´sc°Z¬n^ľâtřÓŻŐJpިqDď">¨ ¶&ŔÔ`Wůî§ŕÉt4ÄHsöPŤc¢,PWµ3Lň,âĐaŃÉ€ M™ĂIzĎ-Í,žëđł˝ü»¸O8®-üt“˙ě?IJ/:D„KßŔhccE;,Q3ŠÔ÷†đăóßN+f #ă.ĂnMś¦Q3•Ťb™ż¦˝yŻ+Ľ†X»ąćňć„…ĹTU…Í B]W¨krPÚ\¸1 vÎ2\›žŘŢű¤Šßwٶ5†˝… ŠF 5ąn»#tĆÁŐ(:ĐTĚHŇJxvÄÄĚ”C”»TMĆEę!|GqłěľM&´6¨MMŕiŤCř:*`RµC»’;ÂbA& ±÷á58-…kĘŽÜéL‡—>‹ĽgUüĎňBTŽwľ?QŃß,!Ozłş±ą±ŽË.ěcčÖ.ÂĎÓ32𽣰^ Wał°DUîm±\żz7®ßCDŔĆÚ& bUö%llnŔď1Г䕰} U{ć6ŮĤś݉*Ă×:¶+™ëú řĂLO"ďD…Ćř9ö‚Şš@»A>˘•TITÇź ­”çZ‘V×Ç´Šťý5%×fĘóźg!—Ľ}z%Ś$ő}ä/ÁPs:ß6óď±ĎöüĚ)0Ôńě4çcđÚ©SűNţ. ©’]YÚBž‘qĎěx*›_\Ť,a„/ISăG~q Ţ•ő:ŔęáĂ(‡%މ†15t]c4ˇŰZ µëťŮz˘ŹXËMü‹ KŕÔ2Z¤2'‘Tl¦Ĺ^Ę–Ś žoăU:?=ŞA8x!k ‰Ó$Đ“RŘŃż†]ˇk4`H˘qÉF[ď=@đĹq>ÜĚLh&+JŁrŘ—ÓF‘‡ďŹ'6âlŹBúł]ňnÝG?˙~+~ć †ęt'ŹťˇpęĄďŢňÚ!w3:Dx[]E]Ĺ—)Íš €ŚLřűń`Să%3TźŰţ~ż°ŠűŮŔHăA†EČ-ţ‹Ë‹¨«`0e Ł Şń$ ĂzÂwÓň(ÎçRč"‡Í…ý E…Đhüp#đÓFË…'•ůběRě6f÷%jÉtěOá;Ló ŮÚ+ä#0bě¸!8ĄŠŔ1Z×¶pŹť‚ÄťMa,n¶V»KDz˘ ŚdgAHÚăşĂAŘÁtżŮů÷>C"Ţ×yüĚ-0$ýç…™qáősŚF·&öłĂ€”ĐýÍĽő—c`ś Ůȸçp;'ZB4 V ;Ďéh­ďí{Ű­—%Č… Î^pyż˙bÜŁÂ’Aś-6äß‹ Îś_䌄>oâĄDŰĆďKÔK4řŇ({O3"°D™NĄ6ńч¨Żžś€oqŤŘI•í[XŮóED(‹EŃvĆG"’sä!ĆúčÄ ŞńUDš¶ŢŔLSy+,.ÔD?|a˘OuH룦EÎ"Ó9ő.ňN Ě%ś'@§†DשłÍPć*h|d«ůţµ›7qýŇ›–üem™őüsGÝŚ‘HÓÁ$Ó ·ňţwŰŃČ@FĆŕůßKž’މP”%FUY_­Z7Qč:,ĐN pyuăÍM°bÔÚ`¸PBWŞPŘX_ÇĘę!¨‚qóĆMŚGcçíIÔ’‘BÔ Ôäçí~ "Ä3A˛7„ˇ%>R»˙&J1xĘ#‘§Řæ9y#Ć6% L®ŔDśfŁşÖ¶Ý°P–Ô][¤í.pź—fhV˘ÁOc4]TĆ‹±-h$Cé Qc÷$RĂ>ä@!˝4 ?2/A¸ŞÓít’™ľ÷F2Ťb Ęr€˛,» éŕßxHÉI7‘1¤¨Ś`aaÁδpű§µĆŮKŻbqőPŇÚşe¬#j""X^9„Éhž_¦ĎZË++m bŚ˘˘(‡ű6Đź‡lddÜ«D"śăB°FPW•ăvîÄŐš@ŞˇLš0ţęˇe,- Q Jl¬m`őđ!l¬Żc<cye+‡–±ľ¶n …Ń(tHĽáX|ť˘@.ďN ¦¦¤§FńO"C!"¶Č°Çf"â’ćH…jÄYqq_.°·RĚÎC oYHoźL°Ýä'+*čJĂ8­4\ † Cčş@­kۢ©“Ń$őćLsÜŢ–±Ń‡…lúQ‘0#U]bđß[WlS=^ř<áţNĎÓ]űj2Ćd<™jíëﻓĆŁQ0€^ţîw`Ş*ĘýĎA»ŇďͰqăúüµĆ`}} ĐĆŞ2A jÔŐxO$úęxŹćd #c ?î Řž@-/K ëcѨkíů†vNÄu|ţއ@ëŠpéâ%§˙@.,ŕćŤX»qÓjükÁhc„…Ą!nܸr桰ͤŐűžZ ĘŹ¦tÚ›‰[Ú$îĐ÷Ć@SČO*ß[â‹đ¦Zä‚A€ö7Íü?×Óď*űĹ@\~F Y[#­C×TC$QÁD5h Ä8k§ ňéOň¦/EQśAҤM$2vJŠ%Ń…đ) Đ”Íäß ý3â°őTÇŔŚw\šŠöPj¸µ¶Kó ü™çĎľfÉ?!?š÷Q™†Ön”/ćŻ%pm¤bÜŮ#Úâßj`Xü÷ťŽlddlaŃßRÍM»8~á6Ú„8&ąŃ¶–|SröąUr4“ńĹ @=©ť˙­­ęź…ŠÂ Ö, °±ľŢňN(!+H]×4-‚! ;ë”*ć_Ř‘đ’HË?l7r0McP’§Đć˘Ă~"0”R0®b˘®+LĆUőĐ– Núú#éŕ ő´ -í± …R ůÇCŤ˘ 9˘É‘fÂ9ˇ™Ţ4EĆĹ® ř1ŇaĐîî€Ü×®]ĹÍ«Ww˝ĺŹvř™p/ÜÂ0 ˝– €ŚŚŰşßýVŔľ$BŕĘyĺâú}ČÜ$…[Ţ“ ¸˙Ä ÔşĆd<Áęę ´1X¬ăćÍ›X^^†®j¬]ĹÚÚÖ×Ö‡ÚDÚ˝AŃ´nÁĄ‚''úúĂç)pxX]}ß»÷q›˘?×z(ťáĎ˙ź‘$9l. AD[ŻßŹM6ÚVhkcBq˘$DÜt'XŁ%*hŚÚqťV´‚ÚrŔí++­"F˙™HJ—zâŰť!|ł˝?sĎéąóř™ÇűmjŐ¤ÂĹłŻíIż?íđSťË 1çzá‰ţ ~62îIâOz“oSŻÉy»˘Ľ("Oî5ăó†A¸&­˘ŹÇ¸yă:TQ šT¸qýŚ1ŹF0Ú`}m‹ËK¸~íF¤‹/­>wßw?®µî-…ş0ř§ÎŹ~Cđ-‚n.Aděřmh\`…Ž„¸)&¤¤2ś‰Ńб ’0T©`´A1(Cš€Ů¦RŘ©zKBčZ[5AŚGU§LňLŃDťË{ŔOŚIµ[?3[čâ{¦oŔĎ\3ĐSȇÝđďö™S/;†=Ŕ>r®O+Ĺ˙>Č@ĆFůď·EźT+S– éçÉÔ“§˛µ rŤl«¸qý†­NŢ:‚ŕŤÖ5FŁ‘Í*K~^c߀˝ŽęO-¸ â¨V IDAT’~"_ÔCąu'jş“Ŕ‡Ľ]…~LXFk/ĹnóńÄPb’0:yw7ŞZ·u ž4“ýţd[â¶§Ó˘F–¦ĄŹ\EżASýo´LbMÓqé¸f‘LŻÉLd i ˇé1C„îĎNř(ş_ŁÁCMHÂýDą…Îňß+ łśÉMClŢßGi˝BŁ™ˇ–’ˇ.Ň֏Ǹ|ţ<†++űbHoë™k˙xOÖśŰ]Ě@F&ţŹ·şŢJíť,bN`¦P VÖ{…'+Ĺ.ŕ§Ü—ű¶Ĺt¤ç_?ŹB.-`´ľŽŤ7Ă ťµµµ$ĽLDŽ ×®^ˇ}˛‰wÔµnB÷€ ŮŰj"ëŃ‹Xâ÷=öŽT…sä˝čޏ–+ë±k­mn_`Ă„˘¤5daŐB U;c}W‚4Dč§ńi»Ż> `45éÜĐ#ĹŚZk ń×Ue;+‚,aF×6­Aduśţ*Ä %í~­khuLBž”°ż'Yéż ‡Ňe‹đuO-@Đh6Ń\©öëŤV˘×źĽ˛B‘®‡!á g,‰g^yđQť( ±SŇľ›Öť»ŤđłqŕĐîßÍŢnRôýJ) ‡Cpi=ć źĆ iTâŚ0ŐuíTí,)`E~A (Ż´ĺ_=!1Śh(%!ŻîC“6…஬¦®Ń 4ZűbbUűjUUPnn€ĆcĎť ű®}¨Ľ( e‘ôúc8@]€4łSüu-N»@üŕ”N”G`# %´Ń ĹP° €¨lÎZE?fwڱ)&˛‹ź/örv•=Š#/Q%9µzâÝąv#ŚšHNä,·‹“ŕQ_^imBďëQ(>)ÔCW­IŠţĎ 7€)Ž8 5$®°:óňI¸Â  !$"¦ŇҲ ö’,c‡ŕÖ7uĐ&f ă@yýwr/ťŹćsČnž˝÷Úś^şíj3‘†®őČ…cČýÚ¶™HŢ`'w›”çĐÉÄ<›Â60µF]×0.GIĚágiŤO•4áÚőí˝N •.öż'@ʢ” µ2Új9Ż_Řţ\[­o|˙ż $Cm4@ŚhčşBQ\šˇ‚Ö…Í·úQ§«1Ú”…‰ Úc˛Éń¤]<ÄőäÄă«›†˙%’EěŞĘ—ô‡đ’\˛kicWDG­üĆF«0ďD Ş‚†F5ŃM•v˛FJҢ–ŠI\]»Đ;Ať‚•%#3j—ŹfVŃbjŠA 1®…‘’í{ Ţ)lŰź@ şËŔâ˘lĶj q˛­€ľÓÄ´Ń­o€Ł( €“ń$DNŚh\¸ZJŰă­« R5 P±FHsţ;3Ŕ·QzYŕ¦T’RĂŠ¨UíO‰pçá8Ę ]†bO~G-@fŇ‘Îb7m±Qwj )JQňG«ˇŢâěéWAŞHö‹âÁÔgůĐl‚n Á0¬ŹřžŢ*ZĐŽý'٦3˛qĎ„űo›EOÓż`b”eYşü´ÓžgBQXŻŐ“3ţřc¶Ôů’‘­®…Ś„Z•ÜŞĆL„r0pă)ŚĹ%'µë‹˙|aźÖ¶6@km»÷ d:äU5z»!(°1  Ř-¬k¨I Ą X×`QýôµŁYžěÜU(ŠUUŮľ˘€  h Uôä‡+AŔEáŇ#¶ŁÁ˘P(T -ßQW03⤒d–Cz9Sď?‘˙•8 - ŇŻ-úĄ}Ó*}ęůLÔE˛Ĺ€ LIű6ç;WT  ăÔK'CçH×AI M…ůÓ[F¶0:$„”Ą©FAř(l«ÄŢŻWť ŤŮČČŘ˙p˙^<Ř;ř‚J׺F5©śjśíQ÷yčZ&@ť6:ąGÔxžÔó(ýSf– 1ă‹ J1ŠBA)duu][’-  JŰńŞZ®ßőş‡aCHj††qýěÓ ZęʎęÚF-Ś=r`m€8%Réf}#17މíÝ/”Bz®#5ľ–¸Ź‹1ŔčU®˘= ,¶µ~Ź"ŮâFl¸‰ $5”(Řw·•€@–üŁIŃa(΋ęS|~^ZF¸'Ăpä´ş?Ňđ!QŃ`ŁŔč˘.ҤF‚FĚ„óçÎa2w[9ú~ŔUÂŮ©DłDŐ\ˇ{jG¨§î˘cő.Ż 1Ů·ÓŠŮČȸâżŇî=Ř– ¸/\kúë=Ůp·b•L .Ą!&ىĄ±}özRciuŐĆŮG}ĺńĚ{@ ]KP„©&*®Cѡý>iÄg\íÖÚu¸(S ?®× ­i$e­ŕ‘í"ŕŞj Ş+HUCMĆ`c Ű”«Ř÷ˇz1iŐ<+†*ꪆ1b_Lé"°…„ˇqę PâA’¸F2i´8$⍊Ąp Ď·h彣ö7Ë•Üt`OßgÜ›xżĎĺOŕ‰ SUřťşý4m¤Jś ‡oĽMă‰č.Ťj H7ŻßÄŤ+W@^çżÝdß9lGf†úiĘ8ÔC—Xh:ÍDł7gĚř9[FnaŤčZň4ŔŚŚ[őßîi/lňň».LjŐú`˛yxízéɸPV9Ď/DP¬`JÁ `q°€ĺŐe¶ż˙Ú•+8třP|ăĆ ,//cíćV­˘šTL&X=|7×1®&v^úÚ `ŐôŠÚXą` Sˇ&†¨0(ĹqpŠU2].Äśr‰ vŢĄV Ä ŮŢűÁpVEČŻ?ŞQ®žě~Z-€¦MˇűL±"ăŰ˝çGѰ!çĄ'„Âë.mÉňRkú_äzұ#•Ů ęow€D÷:R €éů:2]Ą¬™’SnËý&Ńn§¸#˛Ő¤â©„µ18ö ¨PÝü鑦^ iCú „¸ ˛őť^í ‹đi’™é"gĐî~üón§'łqO“˙í$|Oúľ·ö'IŐ;­{ٵ­Î.ÚH:^Ä ćŔËń•¶9ďĺĺ%„ŞŞ±~s á CÜĽ~EY`0Ś7G€őőu ‡Cy0ődzŕ+EU([HIíą%"c «B¶Ź}›ť6AŁ , [< J€M䙡aŠF)h10FŁ,¸`,.,‚ťN€©µU+t„_–Ąýńd C~¬÷ę˘LŹ L “I"h“Š7ąÁKŇ´ ’PS]ďÓ„h”qäŁK+Ďí˘$Ť@NŇ(=ž° »{ěóY‚8ŃJD]!áçŔ»ělŽŘ8`w­R˙:3ăŐ“/%!p4ĺX'†B»«‚zŚ1!Ž·AQ€‹ZŃ„[Év’¨ĂÖĎu;úw[łqÇ…ű÷›đŰ6ďÁ0?%NČ…ČŤ ®k€ĆPşd ll±žln[,9žßxÝÇŢí‚m$ę÷öůt´Š˘€ji W/]FUWˇ ކ íW’äŰŤWµŹPÔGÔęr˝&ôď{=~ŃNâ°Â<Ěcőú•ŘÚë ŇěţÝŚ$ö^Ű cßÇÜ(Ö¤tQ ?OěÎ0ľ -2q|Ž›kü»Ů !§ÍM*”ĆńÄ긎H[•đŇwWÄ!|W@'Źl;R?4ó’¦Z6ăŠ~?Ż€˘z›1±bHB:Ó ĂôI4§J1νvşÖ­i†mo[zÂęí‚ÉVQ w]-ÜJ 7ZĐŚ§ŰÖH]ß1Űđó/$ą×^+`62îŹ_Úńü`›ŰbÉ7ąuV ĺ``ĂŰL6|íH·®¬äí ´úŐ¤˛ }´®]8ś°0ÚyQŕСUś?ű:ŚŮé2tÖoÜLZýwŐÚŐ…) ˘ÁʶŮ];i_OĆ".Ďî‹ČW]o`´A͵#X—D ´Ó°“ ©5Śhl¬o‚ §pŕŞőíy˛ QT“E;üÇéŕ“X5BEމ¬ř€ď&pŚLˇK¦źŔŘL śö¬S‡žâ"LI˝Ţ=†%cZ&ˇź;˝ívľFԧ˵–¦ŰҤb1¨(u(0Ňţ·ŇMĆő˙_»zk×o€XM¦¤‡rO@kÔđôż)ŤŽ0’”‡}™Ł™* l¬Ł8R@Aßaż9üNîČ@ĆmĂí ÷ď˙v˝®? "=vű‹ŘˇIOšö}qŃoŠtˇpc ŽŢw ›ë–T}ŘÝ-𱇚 ©X?평ˇ †-¶´0´8ů\/Ţ#Ž”˝><Śëé÷áy+M,ƙƒ11ˇ( Ń`¶FĎD H´LĆc°Żŕoq‚íLPazŢÄëÓŁ1"3U5±S‰m×EÝěÇ‹-fL ĚL žĐ}ęŇtZ ˙d{5CűĄ4˛ŰŤZ;î ň)€0…Ńçß9*ä㩾&OÁQ&WŃď Ę0lH˘@cjŘßE© ?żˇŞ+Ľqîő0á11d§ů7;pËP ‚´ć3âßs1č$ijjca–€vQ62˛×ĚÄÇ0˙4@J%rťÇĄë›Ć@U…Ë»{ruš1˘ĆXŻÖ§Iüâk´ĆŐË—1™T¸qí‡7Ră‰ŇĐŇë ň˛¶%°€“"pk3ŮďW U`çÓHÇlkˇ/ä«ëRŮŞsĄŠRÁč&LdăÝČ`x€#d#şčÉJ),,.ÚÔR¶îŔ¬Q¤ R p‘ˇÖFkEi÷ŤĆŁMŚÇă ÝÂęQ($=ź×“‰ť·ákDS×ŘN`ż†e #‡űďÂßíEŤG˙?{ď,É–•‡}kíťYUçôéwßľ·ç©a.#– €!BŁŇČŚ !‡%„qH`–ŰČŘ–Ťm!G 0ŠŔ–edp Ä ÁC ÄŔ…fćÎ}uß~źî>Ź:§™{ďĺkďť;ëÔ9}şowĎíľ•w¦O=˛˛˛2÷Zë[ßú>…čą`]÷W°~îząRpŞ:©VBěwnmÂÝíťÂ§5­:^Rýç`GÚ÷Żę &H®`ŐÎ×C6&b­nSĺ+iŐˇÎĘX>:r j˘…1APW!0ŞĘ i•S@YŐPbb |‰Ćµę‘`ŁâźpŕÄŰ6Ť~}ć8ĺ pm Ást]Óśđá ëSfä'ýÉ­”1z%!’@¸ĐO(Ń˙ň2â~ę9öt ŠđžŔ"ęË J˘fÎYzBAI:ŠďU~Vň:hfsÜąuĚfIa~”O8 á±4:ĽáJßťň±rŃß—Ň`°l;HDo˛-s<®|ŢéÖ„g%ீŐöއű—Iú>Vo•śQ»Ń˛ľ~=eŮŮ8†–Q`ĽŞk„¦…o<¬µ·3TőD [i0§XQĎg3H†âqŕ{tßE `t,¨ł ÎŞv‰0çłÍn_Ś•4ÇcL wŢ{xŐűś2ٰN<ÄcsÎGŁ™®âÓŕŰéĺ«GeWD"Ł„EtĽŠfŢq¦Ď@w­ë,s Ť=ý@!MD¨ŕ ­cá.RQěń‡Ü«‰ ťŹMďǧ~+żěŐçľÇ˘úźtÁżŻŘ'ą T&´ČŚďébÍTŚFç•ËŻ­9¤ ?ŞŚ¨7s_KDZPTd:<Č'Ś;í…â{eÍ ˇ8vQ$¨Ľ¸v­ÜWŰj{ŔŔ˙vĽižxFżÔëE˘Ĺ-•#ÜYž5‹±Äü ,ôďOź>¶ŁŃ&űXc°vbăÝ0lß»‡łĎ=‡AeńęËŻt•WęťGZtŰ}đ`çŕ"kÜłQ~xTúK$„ •2¸Ó Ő–VţĄ|¬&Cä9„‘VÍ~# mfXkZ‰•{!Ęâßéz!x—Ú*>ö–cň|(-’ŁP×HĐׇ®2Ě×)´‘~"&9ă°39#&fT$ąé7*†˛n@Ö…ę`’áÍ>Ŕ’˙˝|$FçţD@‚´Cob€¨źm”¦@şS$ Ýó† .żúąĂď:*Ł?fO‡Ŕň‹cŚK-Iháżś ¤ßhYRĐ™[-î‡î#őń¬üU°ÚÔ˙v†ÇúJpoýÝXĐHÉz=yĽd˘w Ľ,˛ÂŁ×îţŢ \ăśÇÚą3ŘßßĂŢx¶˛°u…˝ÝĚ­ÎĹw­ęŰÇýRµ=SYéĘTÎÂ7Šřśä%Ë^˘ÄŔ'c˘~€z Hśpä<Ł=ySUpm‹¦qh˝BţÎ;csŕ¦ě(Ů4ÇłUNJ óŮĆT1Á)éá-ú®2ě‚~š‰EëA[=ăß¨Ś—Ň„řůT*î–Hďp.4–=•@…–DgŕlúÔţýK9ă ž™aóć 4ł¦_c™v’߆ű' ‹_ŽHč`öL ]`Y@ č J!ýŇ_˝+fÉNŹapş¸\mĎ|đ‰ĎŰVTDRbI©OÉÝÔx!ă*…ęťj¤ą˙ůt !`6źŁmxç˛3_Ҳ˝QµĐ©¤Ą$ VîÄ:žç‹ÇÄń˝ÉĎ®ő3+]$ľO+öÄÎ!tj„©Ü=öŔ,A\TŚë¸¤ ­šľőĄemŇđ9xß"MDŠ„©?¨ßĎÓ¬ś§Đs–yÄó_ˇî—YÂ(ĺ}:ÝţxÄTş(4 ĘbB}HKČJŚýţţ¨ ×ëë$ë1$Ĺżň}IŤ0#äî|0&űcÜ»{GůÇ ÷ËNqlÎ'´E–¤t€pD‚ Gˇ‡L,Š:äýôČźv‚ŕ*XmŹî‰GUń/˘ ÇËşE‡H`ŚA]W¨Ş*ŠÓ„ ‚ďJĆPBÉŃću´6B=aPÄăôů3Ś÷±7c>›a8b¸¶†Éţ>|ŘşsO+?Iuš„4ß:™ ZŽ":Ě‘C L®LrÍ|r<Ť¸ĄŞŇIůńß{‡*ÔÁë8ŁŹ:" ¨ŕÇY€Y·[ץ đ1k`¶ťęß‚r^Ňäϱ´ÇĄB/!˘’Tăy–‚, ¸V޵2ßN:_*ąěÓ;{}”B‹s*]~ iĘ-ô!|*Ú9S@'-Lĺ÷0Ý4^<®]ySћûW Yx^dAŞËĐZ’G’ ,Kw\JÓźJÜŠNaä8PÝ­ O3Ap•<ĹAřířßÎp˙â±çś=‚`‡ó¦·fÔşVu»¦íA…Ůĺ®ăxw˛­ĆŕÔ™ÓŘÝŮÁ°`6™awg•5îO`* 7­Q{(¤ M|„(˙J×4đ­Ę{ź4ßĺ€@‹dA±hKÇĐ^ÔŐË߼起®Í¬w(_ŃÓ …Ţ}7*I—!&1ÁĂűő ˛:`Źo¨Ś'…ś×Čśµ„$%$’}zd”B-‹#Ż ń7 šd9š …q©,E@ěůJ›ŕEuśÂćW°ü=ҡ/ť¤12j’“,&ĽůĘë &?÷»”â˝ |©,1ě+.&ĄÖ`ßó0goČ‚K †Ę WIšňŮ =PÖ‚§™/°JžŇíô‰5 °–ŁČډîňÁéđC]čôe7ig?úűĐç Â+ŘßŔ9‡vŢhĐňőő㢞 iŠ ÜŃă±»»‹˝ń^$â!÷÷v¶¶˛|Ż‚.¨I׿JČ€€`€Řż_XčŠcQ‚|/ĽÇőś2|]F§P,ňÁFqˇšŇy.˙N3öéz÷mŰ‚â wŰ4 WŰ»>1ú© Ú) )JA±#ś4úđ{2*~äík–NË ˝ŕ¨Űňş”Ű&EŻ80ĐŮ—ĆĂ‹Áż?qţź™qóÚµ^BvĽ˘Žřsi™~0a8Ŕü/ŞI”ľ>Óß#÷d–đ ’öﱞĂGKµĎgŃ p•<ĹŰű˙Ě÷DĎt]ä(Š(ů*˝*ôä>S…“áäĽ8„ޢ-+IJúsVuËQI+KČÁ÷‡=]č‚­źôŹ«ř ‘eĎwÇž›Bd´ű¸0űCŽŔx/ýóĹîŢäóá%Ńt$Ŕ{n5 %˝ĎÇ|€a˙Ô5Ă!\ăpňĚ)L'%ÁŃ!Tők'F0¶Â›o\Öä }ŻÔĂŹ m'iĎŁ„±–d"ĐaŇ…|­Bô1‰b>oĘ“ĄĄn7.čH+áU/öŽőX)ΰ3z”|ÁBź]GÁŁ?ó ‹ŢâxGm«ŕ)ßä-ţýŘč ť#żgđ>ďÜĘć7Y/?eđ‡ 8I?3ß €W¶îÜE]׸üĘk`cĐ4sÔu­vĽÎÁZÍÉĚ‘-—GŔŇ(a.¤,ŚmSo•B-z€ŠŔ—“>čµ°„¦٧ľK艕*v)\§IťZP_ŁN€Ö8ŐŻNŹŮI>§ś*ÇdŻ›żCtlL< tDÁEa»Tů÷xgŽýwáâśvdĆĹsVň땞= çü— Őýv őŔľ:ŕâţŻĽţzn=x·ŤîóÂ>,Č’@|żˇ+Ç{}µŢĚI/(8ăHĺbŐĎŹ|íZ佝ýOV Ŕj[myc;‰ Ĺ}(+~>kŕ}č«óÓ«DµĄ¬ 1+Ď*¬#Ŕ;€€f>ʦ:Śy3Çp0Ô6AŰbăĚixçp÷Ö&|p] ż”É!‘Ń@K­~ĄĐ`ĺŢüWŮžčHWT¶‘Đ1)üí{k®I QD’ŕÔ¬h˛żc-¬­ŕ\ HŇ(OđđÎŁm]F%DşŞ_»E© B:㟡e) ÷ŮÖW"8©Ď/BŰ^2ҵ;b›¤ËLžąšŘ2ŽVŚîI:žřžd–$ŇŤó!+ů)y’c.–ńCׯľ©y3+Ç [ ä´ä ů,Mh™ČP/))$=®A,ę >8rČşPűŶâ*Xm«í) řwcÓ!¨ÎÍ3¦RëZÎZç]â\=`c !ŕôął¨#@í|¦u>`}cw7ďbm4‚s Nś:‰\Ű‚ Ă»>ÖJ™ ĂÚ*ęň[„ EÖJŇKÚ+7H::ňQ@î]ç˙ í/ŕ˙2ýÎ}ś~|i‘ úűú¦˛ŮÝÎ P‹yÓäD–ű Ĺ|}"Ž u LV,žžŐ.őZ=dşHě$¤ý,Vµ˝q ŔPŮéˇ)YxąÔ n>Ł{‹äR%r°¬Žµł˝…ÉŢڵëCŢIE @č>IĂ2Yá##1•?cď/Ž’Rs&‘€-X1ż…5bŮş°r\m«í)ţŹęƦrÖ9VšÂ€a[ŮŘEúAC{´š0$b]€`şżZÇŽww`Ť…í|ަ™ ŘŰŰ 7ź`´ľ†ÉxŚŕ"D{ěDjěS[‹zPc¸¦V´š08´MŁwU#x—Ď…1Ü31Ň@ş„€ß¶Ůщë‚~ °R’¶KëZę[÷ZŢečÜĄI ĐÎ6`ÓsŤQÍ:0Xş)üŽ|Đ™1)ęb’vB©îWTáÝ0ßAĹŔÓĺ@ •Xúč6YŕMô`e,Šţ”ꀊ>k6źaş5)´ŽÎYń€/‘ś¶Pďz?4D9 YXLG$KYÖoYD –ń Žż.”˙~šGW Ŕj{,[č-d}–˙#HĽ[Ŕ_¬üĺŤÝŞ)Qm6źF“ ť˘Š; 6Ń‘M"™/Ŕ°sľm1ŽpëÚ54­C]ŐN÷DPŐ5 i 8őŹÇđŢÁTőh€ůtŠ fĂŚŃúH{ëĹ`Xu ‚ŃńRk€Ŕâă^¬Ŕm'Äľ73ŤÁ{‡†ˇ @ŕŢşśp‚tŚ'ĺČlŕâž<&Ą:Ë‚iĄ,÷:,x’OÓ|çţÚđ,Ž®€Őö©VgOť ^z ;0ť7Îf:β¸|^ţăą±”ĎR€#ޤŞí űG’Y%µ±1™žŮŔ2áÜąó¸w÷.>řˇ/Äîî.Ξ?‹Ď}úexďđ®÷ĽĆ2vîmC‚ mlśŢrą‚Á`˝Ý1l]a6ťa8 ř€íí-Ěg3ŐűgĘ&>ŠôŰ l”TčďĚŠ`Ë0Ć‚™áťkťÍŕá˝@óÉrąÉŃ.›ŮDŇE- ‰ř'C„ĽG3›ĺJÝD‚cëň|ż8ř‰š4IÉü§‚Áűřn'Ęî‹’Üä’Î>u?Ůé/éď‚Ě理W :żHÇ\S§÷Ď…§ąCç,•Rôg!q•½L¸zůŤb˛ä0!źŁ2ňCŢł(xčTÝ!S‡âĹŠŰ2„Ç@»ńË>j°hřŵ)ÓGŃÍ˝Fôś3źÁQŔU°Úm`%ÁĽűü˙üŻ`8¨ 7më°µ»Źßúô+řńŹý ^úĚk .fOťx˘ý:*Ëâs`¬A]U0¶Ę űô”[ä Â!CýM3ÇsĎ?Źýý ăí1Ξ?‡ýń`og k,x`0 QŐĚç3Xk1™N"´o0@L:Fé=šYďl”'NúśŞLPdľSděSńő4…ŕ!ÇcłÝ‡m^„âń,ßSÚD>ě& d?'fÔU­Ż#U)=ŚT hŰŔ·!4ʱ0 ç<Ľź¨îQž-/ä‚  )¤sąD,Ň×älŹĹŽô…äÜq¨#]˘„đŰ Ľ“rÜď Sŕň*5Ĺä{wnc6ťľĹ›ŕu´D0l1Ę/KŁ%hAç™Ńo-H_¸łm,AM čsž`ˇ±JVŰ;ű°!ś;łŹ˙‹—đ+żý™ŽĐD„µá_đî‹řč—˙ëřÓůCřŢż˙Źđ3żđ6}27äc ř‡®+Ýz•l;W \ă|ś9c€ťŽć¨Vď!łß§Ó)¶6晴ŹU>8UÜßŰÓí|¶łE2‹ń:}ŕ˝Âçư5°Öb6›e%>c Č0¤u`"Xk:µ=&'KŮĐq˘ş+W!~†÷ľ?óNťmFČ™2ˇ ĄlnŃ gR.DŰ´đÎőő/HemçÍ®i‹@©Đâ ¤*¸S’ŤDCę©Ä)†ä÷WĚ”'č_8K/z  śv(2)„‹U°$H ňi)ů›÷]$ ‰M§¸»ą©‰$/öÍŹ{Ă<VţČŘÁÇdÉgěçSń›ńv‚ôeS6—ÝĂYkĘ‚c•¬¶wÔöŻ>ő*ţĎźůĄčÄ QE ~ř{ţC|ç_üsřő—^ĆćÖöŰ‹pŚâ¸Ů}Q§Äš7ŽńEfÖ~mj,Hń¦Ź ! mÚndĆĆ`á@Í…Ş !{ă]ŚÖF¸yýz$čb‚Ť›ŘߎĆĆţ}Ű:°'í›s'r“şÖL húShËkal4˙q­k•żôůSŠGťM+GyŽ–­™F— ětNbo_Ú⻞wöIpú˝Ľs±Ť÷бŕ‘ˇ/…a! Óý^‘5N}=9 Ë_& (FţJEÍRY“:„!żRöy±Š/ýĐ×Hčé,, WŻľ ¶¶«Śé“€ŚüË}°ňĺILwŞ–ąŇýď*>›ăwćă‚$ý÷äß:˙˝€T-C5čѬ ‹˙~»W Ŕj{<…0Ąąu%fLˇđąË×ńż˙ôĎăű˙Ł_ôâ{ń ˙r;÷’ÓüvĺJsÍi:»(Ig»S:˛ŤÂCr‡ŤŢ÷Ć.Ž«HZ´S•ţUŢSZˇX+SŽvľŇ±ŕ’hP 1@=`´¶†Ö9°µ Gç.^ŔxgWĎv=‡ľE¸:ÁŕB ˇçş*š<”ü_$Ä\NrP1F‘JG`pę,ŔzPś†Ăc´OkGX[çŕ–¤‘Ë–3çö˘ü°Á{„ubÖĺĎ’ÄEĽÔ˝‡Âş·€ćˇ öQ6ż6”ÉBa)LĹ€¶=8Ú ‡x ŽŇŕż;łÉQiĽ8)}"!1ăęëŻö´:9Ą8.Cľ$Ö#¬=ĂžţMµěF[\@|vŕÄ8(0Ôą¤d)M”-…éHë[Ť÷ËÖ„§• ¸JVŰ“O01^yó&@ŚçĎťD°ľ>‡?ô|ňĺ×á\Ŕ×|Ůă‹_|/~ügW®ßĚÄŞKĎá«>üEřŕű.ˇŞ nnŢĂŻżô|ňsŻĂy‰„şn] prýţČ—MŰ>4„÷Ŕ7w§ZŠžNy!o›«ŔTr¬PCQQ&Vw~­dćű˝Ű›ŘâÜ@Wµ;blŢŢĉŤP"”€9±ĎCżŔŁ˘d4*Q\W•"ů{Dßű<ˇqŤ8IçđMUE˛]lÁŔuT;Śš5u]ŁŞ*íŃŹŕŞJĺ™××O("ž›4ú‰ÖąqŽ Îy4Ó9ÚhtT@čȤà ‰HĎ}B„:F"g&ń ByÚźp,'”†dÁO٬LĄŚÝĄ‘ÓŐQ¨f×Â’Ŕ—fÚä—łz!n߼vŢäç8Gő~`ąÚÔ3tř{‡ď˝M–=Atx2•ŚŽJWJKGN_zIFuŚÄçEŔÓđW Ŕj{›lĂA"`ŢĚďyţ<~ř{ż ßű÷ _÷ŃŻÂWéďÇöî~îW —ŻkÝő _ű5řéP×^»ró¶ĹGżüĂřŽoţsř™˙ď×đßüŚíť˝˘'ęń%ü~ŕ;˙2^|˙{đň§?ą áz8„÷–oîĹ *AĄFamcuś.ŤÎ%”€™3,źŘă0üŘp7ŹĎá0÷Ţ[×bPŕ\`w{kë#Lö'¸đüsp­CÓ4ďěb¸6Âl6×)€€ ¨×F pM““­9‡ •eŚ„2©WޱŮu|‘#Z+0 *=Ŕ!i ŁťŕhôcâyČ®€1Hł5X«ly”( €©Q eT`´EôěŚ;}…ŽAźĚ~X¨çĎĐI$ÇŢza}+ŇIK 2]ż˘“›-ĹybőßzętB?öu^ťYQ:–.ę:0čcűűcěloĹŇ%٧Źp˙@¸˙Ëňg˘„RňŕYÚ(Á˘úăa>„‹És„[čđDaA8˙;‹JĐý˛śŁW«g$ீŐöd·ě‡ŇďA31ţč—˙Lg ^ą|É@†™đ­ßđµʧř–˙ěŔk—Żc{ĽÁźřŞ?ď˙ŽoÁÇ˙ĹoâôźŕÚ­;pb8Ä×ý±ŻÄßü+ßfĆßü˙W´®E‚.žÇßýžo|Ă·ţŢw} ö¦ł'á- šÖZT•…ĹŠ›ăúĆą}"!ÚÇĺÝT†I™î"‡8ń9ś>wăíěŤ÷°qú$öĆ»çÎťĂÝÍM †C!śąp;÷¶°·;Ćů‹1Z[G3ź˘ŞpľĹ|ÖâĚ™Óxăĺ—’óZt” Ţç`jA&QkŢT]k`ŚŐYvďŕCÁ9`Š¶Ç‘ŮĚáC€Ŕ|6…s†©ÇčfÖńÇá°Ŕş)*Ă`kŔL¨ę ­sđÎÁM Ú¶EÓ4hfsmł$ˇ˘n .sçy@ˇ®C•ĄhH6*M 8uăLčBé䍜4 đ1`IĎT!tŢ EP]ŚuĄ±Ňb Ŕ{‡koľ ćÎŐ±ÜAw á!n⣟ Ń Kő%_ú?,±(l§%«.ÇqRő˛Eć”ö$ňú˙ú»g¦jał|ś>Ŕçß;d•¬¶§1îÇ5őxőƨl…óg7đg?ú‡ńo˙éŹŕcżü[xůňµüc NžXĂ·ý?Śk·îä t}m„oű¦ŻĂËŻ_Ĺ÷ýĐŹa{w?µĚ1Ţźŕ˙řéŹăÔ‰5üőżřçń“?÷Kř•O|đľţOŕ]/ŕ›ľóoăW?ń»°–ź|F_Ś•őzš±#fXkňŘQdAGŔ€AUAE„ĽS˝űŮt†[×o`gg ĆxwÎ;¬­­á•;wPUu|ýű»»‘?áBŔµ7^G=`˛·ŹÁh„¦i±·» ¶€&E ‚6Úŕa¬A5%*˘ Q[°˘B1¸Ŕ›Ťµú>VúĆ0ZýC<|`m ¤™ďȓ͛\ů†Úx}Y‹[B] `« ¶®ŔÄhš&Opd«c ŢĹ"qŮئľĆZ‹¶5‘ÔZ&s¬˝}"=gśţ3`c:$fEAŤFŤF™1Ś†Łľ%pÄ4€%H$rDzVË ŕŤ7^ÇéÓ§ű™füN!xlś:…étr8úҧ^őNG`Łő5 †#^Wś·ń7ŤMR/ČĎzŹłçÎc>›g¨řzP~ŕ}Ŕ©S§áł»#ÁVÔĂáá¤ĹwضJVŰăřř–?óGđ§>ňáč–룞;w Ö2ţŮ/ü+üťřO0oJ‚ň/üÚK¸vëně'Ţ ľđ}—đE|/ľďďţ¶w÷@l:;`bxńř~î—ń­ţOákżúËđ+żůIl¬ ńµůrüĘoţ.~űÓŻ¶O*ŁďRő„bŔTýúf>‡oMÖ+g ˝HŞ`«íf>S5@€ŮlöĐ4s¸Öe÷@6Śů¬Á©S§qçö¦÷âÉĄľ\żň&j[E-ŮÖ6ęŞÂÔ9¬­Ť`LĄíŁH„ă"ŻbD•‰NĘCphÁA¶<•Uß?ÁÖµµhÄ! n±10Ä ół‰Ç©‰µ&WľÉÁµŞj[¬«8 A|)&šl 0•ÁŔ0ôÍ©öBN.mUõűű{šúÎgľ¬*ËÇҵҶ­ĎĚr5fNQEüAX› A«äédíŚ5Đßn6ť. s˙r°2Mmš›WŻao|P·€°GëëŘÝŮéGyżÁúĽÁţ޸ÇÁYzđËȅ˦Šž˝‚áh„»››J: }kjˇĺÇ´łł ďÓÜ ˇŞhf3<.ᑣř«`µ˝c6°ł7ÁÍÍ­lb2wăń>^ż~ źřÔ+řě×”˝N¬Śě%ľrĺ:’n@ _đľKüÎg__Ľ‰wîmăŐË7đŻ}đ}°Ě¸pö Ţuń~ňcżÖűÇvŁ'čúÄąŤŮ Ş*Żlvc :Ą9 „dڞđ#t+!2kA†qîÂy°1Ácş?ÁĆéSđ­ĂÉłgpëę5ĽđžKĂŃ>JűÖiŕ`Ć­k7ńű^ü6oŢB5`ăôŢ|ý ČĄŔG@đpÎĂůÎeŹYą÷AŰ-Q&cUÎĚ ±w#ôAĐ6ó<“ďŰF |ž0źÍ:ŤýĐŰűmŮ´h]«Ł„¦SLňČ®maڶ˛°Ö ̦S´ó6’#=ćó&z t„:ôĆĄ×/Ψ@1Ďßq8;őéł˙» †˛ Ům1őáIŤí!2q§P&"Ůn8–H„g0Ć;ŰŘßŰshuŽ”DĆöŇ#kď%˘k$šf>K/ž –™cő>ÖnHçIŻ]2ęZ Ű—^`t=ś±ĘC'őE!N ä'đźľŔ*XmŹ' ŕ§>ţkř±˙÷çC  ‹_ˇçgbU$ę7™5°3'7Đ4;{{ “ňÝć}ŔćÖ>řľK°ÖâÄÚUe±yoünô‡Âýł0ädZ¬1¨¸¦…  Ôŕ"Ř%'>ď=ŞjűŃ[+ÓéÖZ †CĘâîí;:nÇ [WoÎě§~9DP‡p®Ĺ˝»wŃĚŘA­Â:YÓČ,LÖ.^ŕbß9—µůóxdęĎ3Űí E3źg†Ľk4­cş·§1€VY'&ŞÂp4ĂAApŢ´MéţĆZxÔ(Ę«MpţM Ęr“OĘÓeD(´¨§u€l/Lyľ?{ttŔB8ôM>Űüf]é÷ýÓčhľˇ͉<Öµ¸uă:Č0îÇpŁeŐř!ÚpÝçůE3 …Ç—I/"˛Ř - Q©_Š$M’}ĘŠ¤Ä zo}Mxš ‚«`µ=¦ cěráÄeŚŃ7ŕ†qł­é}n.“TĺŠ[üA Ďe’«oŤD=ň\P†€¦iA<ëę¨Eą<%…;Ä+a͵±ňv–ž· N˙?źN°·ł‹ ˘í…ííRĎŔ¸qőŔt:…±A6VůŃHhć Ú¶…‰ę=>&& Q(ł8Ę• rL®mrLô­‹=ç]ń#¸´ ˘…KzĆgŕ}PŁXő‡bQŕÚ8č‘§ţďV(‚Ä÷b`7ú_ř’ŚolQ@¸cý§ăKI€ć fa,.éôĆ:éĐÄRň,ű˛k3ťOĆ›—/Č#ž%‰eÂrQź#ćűŽ×8\€#Ô˙°$I >€@‘# Ľ°żňß%Á č+ʢăA借5'ŔU°ÚžL/ ©q˝âÍť­ Ş çNťÄµ[w–޸•µxîÜÜŰŮEŰ:ěŚ÷1ź·¸ôÜůĂŤË;„WŚ™!@ey›&2˙´Á+·!‰ápi+ë‘Ék޵«'7PŐ56Nn iĚ'3ś:săÝ]ŚÖÖ0ŢÝEekĚgSŚÖ×póę5Ľë}ďĹt2ŃŞż˛0d1of8ućÚÖÁ‹ŤÓ'±?Ţ­klś<‰í{÷PîŢŢTMáh,±ňÍpő‚Ň őNAµgŤ„¤ Ř9vŇQDůÖf`ÁZ$ŽDŔ€Ńpj8ď3©Ň°ECJˇmÔ#Ŕc2™ôÜ*5ŔFRŮ_pßaVH˛Ja¶ßÍę‚iüĎt#śRT´ˇśůďéş›Ž)B)Č-ŠţÄ]cpőĘš@™cÄíśQtŰ]úZ>ţ흪ď.Ń]˛sˇc$RÖű„Ĺ×ô’â`KJç¶<ćŔłě¸JVŰS±1/żq!ţÍ?đ!üög^Ĺâłŕ]ĎáĹ÷˝ ˙čź~>xÜŮÚĆ×nâ+>üű1¨kŚ÷§ź/Í2AĎťáŻę*“ý(±Ç ›bz@|Pľ@‘L¦ xëëë¨ W 5}ß`¤íŹ­Ť°u×G¨^ŕśĆ™sç°ż?†±Ś ś ¨µ˘Îc88=|ŰjŐN©Ź!Šč„26:Ř) Đ „jX+/’ŰďĆh%f¬UŐȸ/­óxmĹ1·x™ Ţë9Sňc@Ó¶zľłÝĄ¨žłú'áŃQ’h1c˛Uo"|=łéXÄLz‚(ŰŰŰĘşŽĐ°oU?ů 8§¬u×:§űĺW_Qâeę_Çt0ŔVu=Ŕxwśu l=P˘]eât€Uy)GUU¨j đmÓ‚ kPM­&ŚÖF¨lĄ=y|;@][ęz2FŐëZ ‡ÓÚąĎK·Şj‚ÄĚM‚lű˙L€±Ş P±Ő}¶J”Śżůp4ęţŚkZ ‡#¸ŕ”Ś«pÎŇľJúŁR˝Čç0 ö„HýG€Ě-‰Ž‚Y®¨°ŠBWŮćbU˛b!DĐ4sÜ˝˝©#šËŕ¶ĂłĐB ŢŇ0Ô˙}$‰‹áÂ}! ‰B/I tc‚ťđ’T„ĘŢQŻ@ ŐbşJVŰE˙ĺ-®2ńnš?ôżý~äżüü˝żő×đ?úřôk—áÇůS§ńŤ_˙Qü…Ż˙ăř‘˙ëgđ{ź{C+Ł řż˙ŮĎăŹ}ĺÄý]˙le0ŹRŔO$Ł?ő $p­Ăt†¶qß­Đ)1Ŕ¨mm4şń®m`¬E=  ±»µ T W‚Úńv2¶Zíf•¶6 ô}ĺApFŤtlUĂHgpŚŠýřŕÁ‘ČÔ)¦étk…ÉưÂďE ČX k=|P+]˛&&*¦˛7)UmÜkIô3 đxń`Ŕ6šmŁx•„D^Ń IDAT'ťLđ*˝“µ)Rb#˘„Fh]Ó3ăQ9ŕ÷Txł8’`QtČSˇSš,Űͧ74%~!ô"]ˇwźĚ†:±˘«—/«!Ó^‹ŚĂ)ÚŃZ~·÷R’Ă3‡e4^*Á!ÉsŚ˙$ i†, ‹IýÇ|ë/¶ßΖŔ«`µ=rĽ^‚`{gMëčf ĐŃÁ¶mÜ÷L„O|ęüµď˙źńźüĺ ?ň·˙cŚ÷§hZ‡ÓëŘźÍđ˙đ'đc?ő1Uź‹ö˝ť1ţĆü0ţÖ_ý÷ńßý§źúť—zzqô/™ą.]Cu?Š^­P-GÉ]5˝ID;‘€´Ô[kŐeŻu8sö¬ÂŢÍ\UúJH:Ďźą¬JW8ËÇĹYŇüZnQ„ŕ‡†fÚf(‚%E1™ŕSU&ľ„€fŢäcřĆČe¶|‚oçÍ<Oń.: Á9ŔX¸ÖĹ`:yá4úÇÜ‚Äi’ hümŰŔZ‹ş®A>ľpć%”ŠyTŕ(Óý™`ŤŐÇŕŮEž:Ţ\®©ü%tç4Ž%v"€’G‘ČšÖi:’Ů÷;«!A©(¤í–+ŻżŹű#ôľćAŰÝ$Ă‘}v9dG ŹÓBgµĹ‘lś;|¤č-`‡śLť‹÷<Ţ€źÖ†ÇŤ0®€Őöö«ú…đÚŐ[řĆďţź°µ»÷z‚ËWoáßýë˙-îlďĆ2Ą`3@đë/˝Śoţî˙/ľďŢ˙®ç`­ĹćÝmüŢkW°yw+şĆQćZfĽyó6ľýżú!Ľç…‹ř_ľű/a2oŢŇŤť;HŇeĚ sťq 3ÁÚ e¶[kUĄĎTÖŔԵΪ“˛ő%ě ŽŐ|ŔŢxOź“Nóľ#“uŠyyrBÔLQ׾ OÁGd ö~Ś€]Ç!%!ue5¬<ŽáZ/äş‚16Ş ĆVDţĚÜaH™˙iN~ŃäH`˘Ş^ëi¨¬­­!ˇmćh›VĎWăULČĆ6©¶‚ó>Ű 'ĺ8Ń@“^DŠBQGÄËă *q,9€§2´ĐčÓý ŁžŘ>ő$±™b’Ňé÷ŚzĘ‘é=ŚÍ[·0źÍď3ÇĎ÷o€ĂťŽuŹ/O č´l1IčZ)ˇ,ÜŇeŚâĘćŁţ‹˙‰!Ś«`µ˝íďqĺć$W·ă, L„Ć;\ąą BŞŇîŰÂlÖŕĄĎľ†ßţô«Č}SRaZ˘şĹDp­Ç'>ů2lec$oíƦĄUNóaŮüm3W}üHč“ăC˘Ím $!łv>‡‹˘FŢ; PşTŔĚĄŁ^F⢨nĂ%“:÷0«âžál¨Aśá˝‹D<‚­,ŤŐ¶Ť–ĂÄU]Z‚tĘŔXÔŠĹX“G˙Ă!ŞÁIH$žű†Đ:Ăę3ŔÄpM«3ޢ†HUUeő9¤Ńó'ŃBX[ ‰ŕ§öÔÎ"Ő–wú|e-‚á¨4¸Ěĺń|G!šÔH< }ŰaéÍłg⎸.‹z˙ĺ´Lâ"Lö'Řş{/&3ĄÂĐ\Š6őömÄ1 CP:&±($CźŢä^1V+%r 9…,sÖßď!ÎÇł6 ¸JVŰŁOň=ú`Łś™ÖtäÂ¦Ž® 6q´+(´{?Is>˘ý÷Čť¬qҢ"a,kĎĄţ.ëČ™÷^źŹP7EYŕŕtî^â yU6Vü’Ů÷ÄÔ1ňc"ŁÚű6ŽÓiuëś×Ŕ!uçuZ€ĹꑌEu|$' ˘ČKp^…|€w-ÚŘÓ!ŔÇp¦E۶` ŕš6¶ â=|ë˘F„ÚkbDAŤf$J ŰZ§! €€ŘĆéŞÎI“˛ý%&/’“J­¬áH˛ôhťę+¤×uN4Ô9ŃÚ“5'ÁT»kŇ'ĄE^r”” Č>Fé†ăĹăÚŐ+…>Ýżŕ?*Ŕ’<ú^ŽH2ä¨CŁ%ÇĆG/Érô Üź$¬­đMČí ?@ě–GW Ŕj{ÇnOęĆ–Bů,ůĐ[Łę}¶Ş´‚(‚Q: q„ŤŤAđĆTÚÚmă2ěZUu–Ç%A´ĺeďáŁŐoŰ6h‡Ş®˛j włéähŁ&^ۢ% ¨:Ź8ň—Lkd ,$ňĚ€Ŕ•…'F‚j8µé 0΢mšč/ ~!öĽ¬ Nđ^cn¬ŘMUˇŞ2 cÁ•€\ĐsgMÔâ÷pÁë>˝ž7"Zń«Ąň"Ľóđ˘¤B^¨Ď5€SžżĎćF’H‘ [!ă[‚nzOúNY*@}ť9!1YYäĹ6Óĺ×^‹í&9˘Äż_K@а÷8Zrâ0/áŢÜ ’$PaÄË?łL˛”)ˇ×ޞ=^’Ô…Áł8 ¸JVŰ;-ě?á~eăŃN´Żďůč–č•4W®‡’HuÄ{ŃbíäIĚ'0K”QVFűÉ3§ŃLgĎE ¨Ş íĽQו¶|@ UD̞Äm‹Ş¶°UµP]©7ÁÔkž<‰z¸®8DťčMňtđóý]4“}řů€ ®‡ŃJkkQ ĂŚŃÚd¬9ź±ň!ŞőSX;q¶ŞáSžHI‘}śíla6ŮSEHďamc»ŽÇF@±¸'m‡dM"‰Ł°Č„ľÂ"¸hÔ‹@÷Éť0PrEL<…ó qč Ů…401ăÖŤh[—ĎŰÁ«YŽLJZÁ2rüه¸f\r/‘`áË9Bé†+–& %rpčŔ}3”ÇVd¬€Ő¶ÚŢU˙“Ďä).VťĚŻĘ+AMGę’¸ 1…ŚdCž ÁP{ç"8uúNť9pwswomâą‹±ľľŽůĽQ‹ŢvŽS§Ď`:ť"xŹŃ‰îͱľqÓÉá®ipůµ7Tńoë(©îĹđĄ#j!ŞîU¨OśŔĄMô4č8ťĄâHśŕĘoüć®EđMžT XÍÚĘâłżřłęćW׹÷źyŮ>w°†÷~ŮGł‘Bé_ś)Ő‹řŐŹˇťOuz‚Á;„Đ%z>f"Tu ĂÚSOÄ:‰ă–:˛¨ >µE¤séŁ áVâ $ e uD”nî]¤#ŞĺVSŕâqĆxg»ŰŰjňsHáű\ËÂąëÔŤd˛<ę«;h˘Ł•–¨-Är=tX’& Ȇ hOČăĚ~ ţţ‘­€Ő¶Ú>o „< °˙X·řř¶Ejť›ŮúžAÔą¬Př`ᇺ®a¬Ĺ|6ĂÎö6ęá¶Ş1ťNóÇîŹ÷01™L0Ů߇k„ŕ±»˝SgÎ 8=î v¶ö‘Řčé¸qTГ˫Ë^m+p5ŚpĄgďr]Ű`>›"´-€yÓ¨ O|O–ýM.}‘ô |Ć`DUa*@ť¤}ŢçE~°ľŽf˛Đ6@R÷ŔZ“EÖZبÄȤî…yü¤–ČäóôB€äéÁ ’I–)ƤřWÇÇČ&?)Ĺ@I’SĂÄSđŃäǤľ?ĄA˛[4¤~ôl@éҡ2²´˝ź«űĹ„ ÷5Kr!AŔ›_ŻúÓIFú¸÷÷Ás@oymXüw"Ö®€ŐöřŞKôűqű>úzÂç`qIŁ…u‘ňŕ–Ť ëÉŃHžéď*A ş”†™¨–‘ŘO„? <.żţz$L łěŹÇqßK=‘ Cđ¸}óÁÝ;w@D8uúŢĽr9&"‚ńöŽŞë±QĆ=wBB^Ř(ăľJíĆ7ŢŔ|o>Žĺ!~V?›ÂÍgJ`,ĂxÎ(‡$‡»ŕá]‰JČKĐ8‘sźúřO˘­C8Ž Ć‘=2ë§Îŕůý€f“)öĆ{mŁhIŚHé}ú;čű[×€¦‘\őöĎ[Ó4ý=ąô&SžčcČĎý*<  ř;sc(<âŘ R(đćë—ŐŐđČ+ţ/iz7)ÝçNĽw¨÷wŃş6Kĺl=ĚcŽéÚ‘llÍ{<Áçß…˛(LÉĎH“+ÉB6x_ôŢCÔü—Bsľ Č×~şOB7–™… ý;î?‰âUD7®]ŤĐcTŽňbó±vüíľÇw¨`‰›ő¸€”8 ˙‘Ă‘ÍÁ3zř€˙4[Ż€g`»üÓ?5đ­5şp'™ŢÝłL/\ž`©NŹřuomAúç?÷s¨¬=„÷čnî. č¬Ě%‹Ă GÁ€;8Câeë2’űHz€z¤“ٵu´m‹µŃĆělo#ŕ˝x?ŘĽüÉOĺ*S…ţl;ÇCŔl¦ZĚ&jáDĽjüOg°óyöh¦SLw·ĐěO´‚+Dô  Ŕ•k´Í<ꄨ“źĆ=Ľ*š+|E ÔF8¸Ť÷9 "`cµŽŽ‰°Âö kŇ2@!»)&ě>ËďvŇq9äQ6*ę”#¶„˛ş őî¨ äŃɬRÖG˝2¨Ű[w1ŮŰ‹&GÇé*É·Â!÷šĄă—ĚËş R$:‡&‹˝űĺľýăç^rĐouK“r$B4 =`€î»Ž,Ş~> •€˛3žŞ Vu ŚFJä›Ď ˘EHĽŠňW)ŕüüżÉ@Š_BE‹â{ŇoźŃ / úGÁD3 “ýB‰D‹z\{óÍL®”pLŘý8y$éĺQ*Y…~†,Ť±ú<üg¤sݍőÝ˙ILBl3ťşhxëË"ş¸\mO,¨ľ“€eU˙ł°·ua­…1•şÎYuµ«ë!ŞĘ"x ~ŕâüHÇÔ@˙Ł }FT$¦™Î°»µk-¶·îˇŞ¸üÚë¨ë·oÜĆl>EćţwnŢÔ}`´>1ăâ».áęĺËhš9¦ă1\Óbş?ÁxgU]a6ťŔ9Ź;·6áśĂÚé30‡Ń Üľv hö0ď`w{á<źck{wîŢĂĆĆČöÇű¨5fó9¸ˇ,p„*g%’Î"´äćMý=Q§ŔR'ÁTM§ąŁ±·»‹ńö|;‡k[MňÔ‚ö…Cä('€»sş—˛(ĺD‡¨+ WŐQY.¶ŻĽ×qÂĘ‚ŤÉ˙i[.>fmlŃQ”f}m ëëëÜ»wÖZ„pbcăčrü!EmBđX_ŰŔ‰Qűŕ‘ß !`cădďä8ĐÁ1P<ÖÖÖ‹ă÷ŮłŔA=ÁD"2 ˇŞ`cń¨ćźžv‚ŕ*XUýŹ=@&‹Ř§=Řß˙ĽÓŇ:§&:.ÚĚ’Ţ9&¸(}K!G žP#Ćy¸Öe$Ó;Źů|†Ş®áÚŁŤ ´óăíČöŹŤévĐ6ó<hŚĹŢŢ.Č0¶·îA0†Ń‡ÉţĆ;»pŢéě~6®×®ţŕŢ=¬ť{żHëĺŰ7®boó&Ü|Çă#3Ŕ×GC´Ď_D=ŮĂ0Ś0Ýß“ŹE©Lmë"VRßäC_µĎ˝¸ }âčlUëaîéďÜŮÄŢö=řÖCÄ÷Té(ÁÁ„LLsá]BPü@ĎŹŢÖ5Ú¶ÉÁ?ů/xďĐÎŞ‚ rŠÎűĄ¨'ěďO@Öb6ťâę›—ÁÄ8±±˝˝1ZÖŃ[Fě÷Lö±ż7?Ž@DŹĽěř4•8ř÷“é{ű{0†ď_Ęŕ}@3ź©Ě4!E–BpXŽű?Üšđ4W Ŕ*đ?‘Š˙ią)ŽC|0|”sPႢě]‹–Ő–$ …t HM§‰€ j\UJdôApöąó8qru]Łić¸đÜóŘşwÓéƸÖaăäF†Ř«z€Éţ$ö÷ĆxîŇ%´ó9ڵ:şf n߸ťíťŽ•źG ŹŮí{xéc?€0ßŰSˇç ;8• ćÝ/ŔĽqÁ„Ę‚ŮFů`UĄ B˝ AHí ŰK—ŕ_}5[č’aX6j7ě|đîlᥟý ŘŞĆţÎ6ĽS+ârĚŽznqÜ×˙ŹÝ.Čĺ|~ě\fJPěE:+ćň×O3ěů÷ŃDĆ辯_ż ¶6î3I“˘Ń‘s;rČĺ8‰âđÁëřQř]Ą~<Óc_ZmËá‰ó˛tGH`aH[&YPŁwĆŃ-Uóą”ř›‡ţŇĎšŕ*X%ďx¸˙±Cx +7ĹhC†am kM\7MOFODŕśS9Jç®­ź€ŤÚţóů »;»8yę$¶îŢCUU¸}ëĆ[[Îś=‹éŢÓŮ n>Ç|>‡aétŞÄŔŞÂÝÍM4ó9Ξ;Źý˝1šyçśr‚Ź$7é„VTÚł˝m4“ýXY:Ht/T™ß8Ă@VšwµÖCk@ç·Cř[·ÝxĎ»îm{c%%†&MŽŘÔ¶Áh8Ŕt:Ăl:CđÍlж™ŁŞ4BŇ(9Ś)Ő®cú+©Żłˇ–Ĺ11éćţ“őÄýt¦S`20ţŐé9ćó0ׯľY|žnYďtX`/’“"Ú/ż©…<Ž =ń‹|Ě|đžŕă´Téŕ[%KhĄłXh“€Č¨Ý3"˙Ž; ™ą x6ťW Ŕj{GĂýO ÂŁ˘LJîzDueŔµ&†m^䛦…k[ŘŞB=¨őśA=¨ŕĽ¶hNpó®Ľöz&¤i@Ó ť­myĽ-]…&…¨J ŚL„ńÎ®Ž“2c6›‚ÚÚ‎jéSŕá{ÉôTň¸s¶mĚÝ{p_üEÍ;@]Á~é—‚?đ~„—_Ďg@đűßűŐ_÷ňg~ďł@Ó`úâ‹\»•Ő‰Š„Ţc6ÓöG9ždáYᨹź¦%…v’¨OLÂD$Ł2IČ8é.0úľeť™“F‚r]éóÓ ů_Šu›·nŔă0-˙…BĎ5Ź’Ę'©éń–®ţ#˘Cž+Ć eYň#Ĺ$aLťzÖ˘%¤ K’§CÖ†gÝ p•¬¶Çřß®ČIJ›űń˘ýD(ŠÍďZL§Ó:ŘĘŞk3śpMŁN¤˝["ÎDŔÉdm~=žżô.®q¨5‚÷8{á<îŢŢÄ`0Ŕl:…÷N킉ĐĚf¨CHđ0uËűű{®Ż!ř€ŤŤđAŕ[‡ëW®`<#aŰŠµQz5* .J± S®e‰ÂöĆ-ř?ŮĂ~ń/]yż÷Ýŕ Ďé5´6‚ ŔĽř!ŔX¸O8yćµWC `P `,[´ÓB*|4°¨Ś±ASW`&̧sĚf3tĄ?uJ Ľö‹¨`PRÝKA_(±ÍűeĐí ÓŘΚ9É3úH'T3˝·…áą3]ĎŮ̢XĎ’O€ß/KĆűPČ“¸ůŽ< er$K i1oĂν#×ďU°ÚŢRŕš&žL’˛l±¦ Č6°IéĎ;ńÎř@˘ÁÉ™ŽYÖmëŕ]1ˇ޵®w-Î]Ľ€vŢ(j`-$¨ŕΉ“O&8ń"ö÷ö±¶ľ6÷îl‚cęTuŤsçĎc>™ŁVŘş{áld˘Saľ n–ŤFÖŘמ9CLT÷3Ö Ŕó—Ŕ—.eŰ8Ž€á¨PGÔŞť?đđť; ş1!8´MÁˇUë_ע"A %G6m Áy—Ť…“`;­˘ě· …đ˘q¦?ŠzpNŠĘ ')âH©Hč 9† âD†2L ‡éűÓń‚ęa×s2˘‰ćEQçążźGu/0-íÄýßĎ çPo y€[Ť–üÝI…w ?±5g’°JVŰ3üßîŰŁ<Îe7öáű^čć00`*áÚ¦ŞŔB 6Ń%O«NçĽs*Žg Śa ęˇÚłŇŐöĆcĚf3Üą˝ 8wţn]żŽvŢ „€ŃÚ:ćó)n\»u”Ň ĂŚ{›w0Z_Ă…‹±ż;ĆîÖ–:ë †q„ŃD™`$~>)YŻĎ ±Zvä#¨nÝßąn[TW®ř+Ł> EŮ]@¶·c@'64)`!€żđEÔżý;@đëë_Ľ˝łgń®O|BE‰ćű#l5PReÓ ™Î:ÁBőEE%~r?µ;8‡ęN8AČE<*ů’TĄĐ  ’ŚhôÂl>_B‰#,‘˘;:Ŕ?*‡ąÇ}=ük‰ÜŁŚâő˝ľ=¶ő°DŘ?d•¬¶§%đżÝűüŹ*A9ěĆ~¨}G–´D+Řş^Ŕl`­€¸Áßş¨ž'0! XË^çࡷ'6600›Îŕ]€s-.ĽđĆ[ŰÁŁÔŕŠ±qrĚ7Ż^s/Ľç=`cpăęUlll`¸6‚µDĎ˝pk'NŕŢť;Ďf¬­ĺʵ®kělm"xß|oĽňśsp> iL]ŃKżöůçŃ~ĹWŔŔĂ×AGč ˘–ŹdżG>uţ _„÷~Ţ ~ĺUśľ|Ťó¨ Đ4M4"̧“l¦Ł­‡ŽýMÖÄţTô‹´1ŐG®Š»ęyÎ_…m9ň 2˛ÉŢ•ŠĎánl±z˘QBĎgKŚďäđŕ·âz^>b/=xüľ(ÖC¨v,ý¬cI”çĺ@‚pź/N ‰Á#Zk–ü•ŕj{¦˙Űî Ę#˝±©ż \;Ç$86 ,ŚUC'ńÎ…¬ gÇ0r·jQ|ŔéłgaLfĆóď~76oŢpń]/@ Řľ»Ť Nbmc·®_÷.^ÄÚú:6NźÂő«ob0b´¶[WxţŇ%lom#„€3çÎÁ‹»wî`´¶†ęÁD„ÉŢ„z8@Ş!•xŻÁĐ hgŚjo\»\8‡úKľDrôtĄŇEpćh”+Ŕ`oîsźÜۆ Ęe0l !Ŕ†Ž˘*Ňé†ÚĆŃJ‚a/AŰVGČ\ëŕC€­*H[l ŞĄ'ĺ8Zk˛gŚJř®ĹdČ0ŮpŢc8býÄ •*v>ĂRx¸hwĚÖôdŃÓ2ý W–üŐ'ÄyD,~‰Ô3SăüĐ‚ř!‚d„J¨pS\d˙ Ú”ßDIda”óX(‚hô]ňčlĎźµQŔU°ÚFĺĆ68 IDATZFô8íŤ-KĎa(ú°"@p^+S&xjᜀ’+ĺ €sóé4‹Ę\}ý ¬ť8ŕ6oŢ ­­AD0Ýß[‹ť-ŁűApóę5Üľu  ®¸yíşŞĎpçćm4më' 0ťÍÁL¨ë6NźĆć­[ h›9ööö4ŘZBpÉ0 Tđжµ-ĚĆ łB˙âÍL…f;ňÜ˝€76@M«‰ó9m3„€$ŮâąŃÉFđ€Ŕ ĎQe<Á!H€÷‹źŤKIŤl*Ô5/p®Ń}‚ŞŃyçáÉmĽîËŹvŢ‚­Ž–>4Iĺ°™·¨ŞzˇÂçđđĐ<ő{<‹ú*>ŇŰË9Ź8dKÝ€bR"}őÎă ­v— ĐÂŢ$·”('¤c—Ř x–GW Ŕj{¬0úŰů8ůŤ˝hâÇâ$ęÝKí›Ap‘倉U ź*ť4bUýBP«Ý$Lł>XĂdwśGń4X9­Đ˝šu]ĂąŁkĎlm1źNpöÜĚćsŐ¸sk'ĐLgJ¬ŔV'Ož@Ű6A`ë÷n߆e†Ő"¨ŞJ9 DhŮĂTĎ=˙n\»†: ĆŁd0€(i1$?¸˙öޤY˛+ËÎűö9·q÷×G‹@ €™ĹŞ"K"«$$J’S™Ě4 ™~€ţ¦h, d&3i"3Ť8áH*YĚ*VVeV $šD÷úçííÎ9śs;ţş@ô›†|/žw×osöŢkŻ˝–hź$Ä“ ëľ9‚Db*\U!Ć ĂX¤­*‹ĚóD{"@ô5"–"/0•ˇ,«ŽŇź?żĹ˘U” ­XWŕ˝óßQQ̦“€dř¶…5Ž<ĎÍ&DIŚŽb"ńÓÎú˙f‹)QDGĽ7A™S•yGéŃQ)UQ4Š…MJ$rŤxuypwÖ`Ş[•^gáZ=+«ě x/Î9Lĺy+m۬ďżS[ň¶Ľ«‘†ú(Xç9(ÖŮ%ňe:°ťDľFq¬µŤ’Ą%¸O^Cđ÷apť¬·ď FS÷ó{ë×YÇîýwřńźţSv÷ö¸wď˘XŁ˘á­[Đç¨Ô*mµ’šęŚ<yŕ8M©Ş”ŇěŢľEś$cmŚ(ŠQŠ$I°Ö‘-2”Vč(b8Ú`1÷ŇÓń„ŃÖq’P%ď9ĂÍM”Ň^m0I0•%Ncż Z‡_C=_A%1óĎ˙ŠŞ4Q1ťLźž’ îÝ»ÇééÄ1’¦$a\ü‚Q`PÜŢ-˙«µíL}裻<Ă•*3~ ŔYÓkQĘ·C´Ö”yÎ?ú˙¶,=áŃ[v,w]żŞv}ŔŰ-Gۿޢ$Âe žullo3şűacî$Jů¤N ÖvEV(˘a"ü«˙ń&MÓ6 µŽ4ŽÉňĽ)sťíč0„VFm9h›é:Pul‰imlq.BĂöö.gg'ţ»Żi×TŐm iFNëÉĚ”°¶ŁuĐosë$ ‹ĆííxöcÍ8CQx6@šâ¶·ÁX$4{p3X)+EEG¤A°BÖhQŤë› Mő‚¬puÂ….4–Y*~k „~5îşčzÇ7ńÖĆ®‹ IWŚ/!kÇ:iźŘŮu”čŢDř>ţ9­¨QË©׎´N('xîb+Áěś4šµ&‚cÉą÷ťÚ¶T˙řIgę‚€ŕtĹ{ţłĐŇ'eZüůîj!Řp\B¦(X/Ý5hZyţşÂŇôI¤nµčV(Hú;ýťČ,óÖ Ŕz{c·7îSt\'^yL•âôĺs>űËĎýwîS˝˙ČKűFÂĆ;Qâ‰jŇa”×kşĄ…6ëłŃpÄl6ińÚyη;5g0ŠcĘ"Ă9Hâă,JkĘ,É 6;M5 ­HÓi’8!¤äE)«ćą"^Kz6ʼn‡îë¸đôńcżŕ:çýśŁ¬JÔ×_c~ôAxL/±·oÁŢŽŹ-‹śäč|oĎW‰YŽzö ±A×ßúŞ·R#$Z+˘(ć˙ć˙ŔŠlľđ6¬5ç ž¨E€:E:â2˝kKşě~ŘŢŢf2™úż…Ç­±|ô‡ÄÓ/ż NStGŢ0Ësâ4%IâÄ?ĹÝđż˙˙ŮŰë]W[Ű[LĆ“%uŔä6®@ŻW<ĹÇŁ>ŕÉ×_#Z]đôW÷đÇg“ńxző})˝FW!0ÖňáÇóĺo{ŢÍPV$×â°Ćń'÷v©¬E90q4`~vňúĆ(/¨ö(Áu°®úßę>˙ëúěîM})а,UŞ4:ŠĐQ„DŢGkĺ{ßJůąöŽ-ÎźÔ_Ő˝HˇŁkAias{‡˝[»$iÂ|ž1(Šç„»÷îňřË/ŮŮÝĹZ’8e6ťzDB E^°»·Ëbž5VĂƶwv@„­ť¬1 GCöź?`÷ö]ňlAYU"GÇ1Ół Ń€(ŽŃ*ŠtRVj0da fs“ěđ{÷śť’ßżçxPŰ“AŠM6'Sći‚űô×lnocŞŠăIŕ9\i!J˘"_T$”Ş4TEE^–Ę@°ă%ŚúąĐFié üţAsTŁW ńă‚^Ź!ńş 5ú$‚(‡ÄáÜę­#DG,˛:NšK°FiF 66ZżzáeeŰDeŐ5um‚~?A5Ć‘ ÄZËŞ§\üĆr˝ű$N†$iuţŢp×ŰÇĺ{§÷qÁĂ"ńSW}w'ž¬©#”xTI ^oŁ>żŻyM8—@ţ¶uđ{řßć>˙wá˝ŇMíşU›ëŖ́Ŕ:Ŕ®ŇĘî:KHB§4żZęČ'á(Tëă“ cű/^pçŢ=ćóqF;[eNš@SťQ%É iPŤÝť˝ćłĎNN0UE’>`>_¤ yľ (s6·¶¨ŠSUŢŽ¸2hQšśĹlî‚$¦4E^PnnňŮdÂG‹ŚŮÎ6. Ő9ÎXŚµŘ˛`ôĹ<ŰŮ!{ú”]%X$é„ÎŻĄéĎ{rĄWGtˇ'ÝÜ‚śŻ[UĄŐPľëĹŐ‰&­t° S ­á="\íX÷ćAM§™é\}âzÝ·¦Cpć–ËçýeU€\pU˙a±mˇ {ËŐ—ďu“ŽZgÇ]ŕt©ü®»ę1»" rĽ&ŔhŤŢ=›íďbMXŹ®·TĹ˙Cëűľu^+„×ôCű0iýXŁŹ ˝ÜN/”kâJĂÓŞ×A±LNÇĚ&†ŁU^P{\EGRV9Ö´kwwŹýůs@Čć­ŤŤ¤1ÎB’¦č8" -†ý/°•AGĎ?ńh†(ž &E•ńD¬Ç_~ Q„JRdRL&ČÇńâłĎQö§HĺEi?ú`-Î&Ó9ćńěʰ‡/÷;T¨Š‚IUŃ ÓEŽu¦)UY†­ÎWju¤WŐář5Ň÷™kůý–O“I'é=Ĺb†1–X«pÜę~µha…ŃŔ%U˛\ŕ»Ű˛S}>„\U‘Óo»_g/}ŕ®ăYJF.zN—ĐKä|Rµâ‹IM•Pý¶˙M×…îő´v\ok¸˙;Úľëĺű†đäÜJÖůQŰ–şQŠš -Mäw®ÁÂ"&lďn±µ»ËŢ­ŰĽxúŚ÷>ü€/?ýŚł“cţđOţ1LJ‡LĆgÜ˝˙Ď_%1łÉ”­ío¤ł±ÁäÔ÷ŇÁéŮÁĆáĆd0ŔáäJ„íťž=ý†ápČ`4b2>٬*﨧„˘0dóUU…ą|­!.‘<ŁúđC˘É”l2%ťÍP[۲ lËJwłS.ć¸ń„ěÎm˘ÇOšĹ_)cg˝? Ż6ŘpÜX,Zęq@H‡ ůŤ^’   ‚ °ëś±f݆ű»N|2`Ť”eI–e^0ÉŐmĎůĘBZ®ŠŞÝň9ĽĂ˛»î˛ĺôŠĐ,$ăňŢűuáűó;+¬‚.ŘŻüjé ö˙Ą1gX’Pśóeđďdé@A7^#Öc€ëm ÷żĄ Ę÷áą ÎrÜ1íHŇ»ł›zj¦´ZÚÔ|Ďy¸1âţĂŚONąűŕ>óůś8Ťą÷ŕé`ČŮÉ üäÇ”Eďř÷źž˛XděŢąĂ`2_äěÜ˝Mš¦O©IşÝv‰—¶MV!żŰ:ř= üo»|ďMŕĽďýXHwéo…RjŁfáK­ÔĚĂ×É‚ř€Eă8Ţ?ŕěř„oľüŞq˘ł•E”âŻţüß…ţş?®/ľy(5˘€gÉSŹI q#"LÇcň#NŇs=z×p:Ú A{bŐNM}^Ő®Żü'ç«ö«~ßrđçQýUłŢkAbâK„Mµż”$tQ©˝§V‹ ÷Ţ5&'^ş¸\oż“Júm—ď}ľĂŤEikëşrÁCÓÖy˘–8ŰźşNŕ[#Ú>`c¨Ś×ßß˝u‹ť˝=’8ćůăÇ<úř'|ö«żg0’¤) ŚOO‰‚>ţöî.§GÇňň¨˝Ëţó—ÄIěÇ÷⇟µ R&“ óŮś(I±N¸ýđ}¦“ łłSTe(O&ÜÜŢ&ËfĄE˘˛ŞĐĎźsďÎ-rëŔň­mZŁŹ(‹śÍt€ d_| y†+ äń¤(Ľ¦{ CŠ«ř EYˇŽŘŘąC'”ÓSݞó˛Ŕâí–kIŕćşsµ>~¤ńĄęţ5™štx~µś±<Ď<2Núž4K>®ŰýiĆŮĺÜŐąfÁr_a ¤®w Ň3'ľ*ňݤa~ŕş †[˝;ŤŐŔŞ$á|d—FÁĐÝŘř6˙‡ŔX'oŮöűhÓűĆ{YýGé,jâhŞHQuo?ĐŃűŮ6ř×\š4č •…h¶··9|ń‚ô§˙„Íťí0+- F#vövŮÝ»Ĺóož°wűI:d:óáÇ1[Ě)ł‚ÝŰ{źüÝŻýý'čźţ”DŕáÇ<ţŮĎ8{ţ‚íwîs°€++lžűä§2`-ú7ꇉĤЇŁ!˘"’Ń&˙éżřoOţźĂb|âÉ€‘CiEU””A°ŽęVúD@(«vođoß6č†~_ŰGQD2H;^+éjťCá¨*Űq“sŤLŞ €Wp ˝ikxůě?xź_˙âďĽP¤Ů»{›ĹlĆÉÁ!{·oˇDóĹ§źˇŁt0äéă'¤!E‘óĹgźsçîňţ[U|ńégllm1źĎ89:ĆV†Ăý}LURĺ9ăĂcżţŹŤNT–“aÇc_ˇŰ0éBŔŻĺ iZ•1dYF§ Ň”Ŕ<Ä"ĄˇĘ|Ďß… '1Ue1¦ęWß]ľę†é´m¤el8×X9 ăń8Ą¦ćz[öËRµ,ç*űëŚç]T˝/˝Č]3 «›^ÓîjŔŕZ„;éĹů›%ŇA3Ôú>Ń©‡şÉśÜŕX%ţő68®€·0đŻűüo„'ç?«ö›WQÄhs‰” vÁĽĆxèÚ}Ş÷«:ÇqäÇô˛EÎ|:çóż˙ ŕ۵¶ş +[,MůfáďŘŐZ,ű/ Î:ňY†N˝¬®HŰżĄ@GčŃVčmĂńÉ1ű‡‹ÖTĐ´.¸V°8¦ă3¦ă‰wÍ ňȧgc\B°·]”„Ŕ‰č$PV@ŁPJ')q2` eľ$I‰ăE‚Ş4ůb¬Ś8JOR¬«îĐ®•~꤫,âÂ÷ë{mxŽöčĘÉńqs˘ťł!°­›cŘiGűw®Ntü´GŁŤď¬7»Ymë˛ ;ŃŇvgÝů@ÚË\¦XgVąîň­áaDŐZwsˇ"wu˘áśńűď Ć]‘“„KÜŘŕŕZ省?ć×€:şA˙m™ű_'oiđÓűüoâ~~7·H[%( v¤Öň‘Ő·GĂ_ĆZ†Ăyž5ßyů¨‰´Đ{O›żŃëAAĹ^¨Hiú>~+!bQ‘OPĽQ˘Úµ(˛­4I’ (¬łľbtŢa°»/Qä[ Y–Q™Š(ÖŕZ)ň˘Ŕ±µëH\ëáŕ€8ě·ržś8=<ŔXÓž e^2™ŚDň „˙Šv@_ Ż?xč¬cccÄáÁ~óÝW˝ď«¸×OÜšĎLή§tĂÍotőÍ“o–T/{Ťĺčđcj !Žcćó9˛!ë`ťĽ˝pëpÖ Ö}Źc€Ý2,î¸P˝*’Äë囪ňOqµ÷»ë 5žń4ÂrÎZ"±˙âyăqNÇUÍCôµ’ kFÖzŇĂKä6çĽMžeTUĐ 0¶ÂT^µ/‰7véň©µ& Š~őwě|† łęnô[ŹkŃĎ:WůÖVÉŇŐđwE‰FQV¦ÉgĘʰĎ)óÖƸHiŐ{O ,r纪Čó"ă¶z­Mjy¤4gggśžťx=yńvżyQ4S­ÉP{\—|óüs”öciőyVŃŞµ†î^Ä—öýŰ ß*ZđRŢB+}N›ŕéě÷˝ HJ´âŢrŻx÷7­éÖ Č­xf÷oŠ aø¦ çM}/kŕ*$ať¬··r{ăt\§Óש _׍˝ Y¸8pťśŔ/˝J)$Š ,›äÄż§4®«®a˙tfák” 4eG(¨®8ýśyüë¶€´N®ˇż\[żşĄďg­˛Âiď5Pä%yľ@”&1–Ń^Ů.Ę‘F§C"‘ŕőŢ®ŔÎVŘ  čBpjŃ K=l_óŔ\gRÂáX^)ŤŠ"oä˘J„t´Áp4"JR†ŁQô’(B”PćeCŔTŇ*ĆI ď âÇká iď¶„ŽŞŞ8؉…Uţy¶2XÓí+×YZ*  ¸ôr/ŐÍXűZ+píF¶ąG*ě¶,ÔrîĐábČEľęŠ4ú:±ş“´]5d­eA®Ţ—ť—čk7ô°I1ľZŔ‡oé˛NÖŰ-đż)}ţ^Pîč´;稌}-7ö«}żăwLU‘/ć6o’r5ĚíąUŢěĆ-©şŕ[ßěW˝Î;ŰŃ˝wŤo|ťH´DD˙š&X7;Ę÷é;*uëBśĹă‰pAdesď¶'VeĄđ–Ăĺ|Îl|x¦ aµ´®ő>ď- i-‡E)’tČpgŹt8Dé(đq{"ŕpł‰ťUĺŰ:‰üq Ó" ă¸9µšź †JţşpřsĄDĽRhcĚf3ďܨ|•®´·rÖ‘"Š˘Č»5FQŚÖšHk"ˇĂk´R(%=OŐă{ť©׋kç=Ý ß hí?ŐR˝ÜďuŻsYÚők+Ţh~JĄąh„Ŕ5ÓŽu2Ý?ś;^Żg˝ůˇ’× Ŕz{-Á˙MŘŹöfl{çž(ć{ Ę]M{}7vOűŻY“ëő, VÁJTO˝ÎÇwG™ĺT¶ěyĆ4ŁqŘoŰjľ­q¶©ĚlM{s®=VöüwuÎâl›,=B_#*ĐJ‡ ×~łđź˙łÎU»ű× ţţ/TŐK¦iÉHŁ}ÜĹß÷k|­–§Đ˘lmó_ü7˙}xťś‹Q>Y˛X§ĂŃQš`¬e’¬8‰¤CśsDZc,[ $QDYŚőb>ŞúĘOŕ,y‘)Íh4ÄG”x%Bg ĂŃ»»»(Ňá4 cOöC)Ź’hEkôRÔTç+ÜĐŃŽę]CýöÍQ×­¤«sŽ+˘łĽž ~“)ą,ąhěQú$R%žLŰܿһ/ĺÖî}óC\'ëíµŔýżë ß5ďđSVľ uL¨•uިßĺŤ-çôŮńýXĄI’t4DkOVóŐľÂ9µ[ʲj b‡pűîŽüřZäuË@? ułçÂaűÜ–uŘ_PU¤‰ă­tH¦|%Ç éhD¬Up«×Z·bůö˛zIÇ1âlgć<°úťC‹%ľU ž(W»"*ép–6ĄZgDg.čç-ć3Šl5%Öřk¦˛,ěÜżŻňŐ˝© E–a”Â?‚W•U~Ś©8;;cowŹEž!N0UEU~l2ËL¦$iŠÁkÄiB¤#Tů¤Ey®BŔÚvĎr–îÇ»Ą”ď¸ţ2q?µ@/öŐAY.ŽęrS%ŔWlČ%‰Býwń;ŞÂ˙oó(ŕ:Xoߪâŕţş§mm¨ř­vÖ´?k׺կwßÓŤíš^xUU@Ą5*/¨ÂgÚĽťńP~UUáu¶áÄ 6F°_;v·¤BgMSçkA×ٸV/Ýů4E)E¬˝ĘžŇ^¸žŇ¤ŇŃ\ĹŻţí˙ŤNSŹ Č\t ;VŢÚ7Ď` qaLŮŚűŐÚe‘óĎ˙ŐżF´âßţŻ˙q:l{·A„ÇŘŠůlĚ˙÷ýo¤ĂQ»+­ Á€Ç’gs\™“¦ ¦ňÓ6 ••!Š4ĆZ¬1$CbçuićÓeY!V€(0OŽ(Ę"Č +\H¨Ś±TĆŽDë7ë…Hil@˘Ś±í\xű¶Âuťž¶\ŚŻÔşř ŽJ€7‚ęĺ«ůWů,.*ş°€şúÍę€Čµ÷yí¸ŢÖŰňí÷†A]ŤRžuí"['ˇúł¶ćŘŔţużłLľÖ˛Í|D”ď•…×ö/˝řŹŽŁ´Ř쯂=/ó Ą5Î8΄a3ĄCőěŹ J‡"ż¶»=đÚÓ^D5ÁÇeUQä(A©ĄŻ¦‹Üď§d˘&€ň3ĺ5®î˙×N†Aë 2ĄG\řNJQ â”e•jlŰđ.BKĂĘĹśq^˘"ß&Aé¦ZN)I’z„Gk˛Ĺ-`mŐ<Ďe%~ODQćUNPTU‰±¦Aµę ˇ”âäč8ĽŹř~ľŽ;ĘŤ!şÔMůĄńw× ą˛Ę}ŻW‰ +›čË˙•^]X±+ą˘ °ŞŞľÄ¸Ç-ÄĺnŔ—uá'\>Č ČÝ‘Q?ĘęçÔ„żŹYŔ7y`ť¬·WŞú—ű±\ą×ÁßX〪ŹP3Đ ˝5R“ IDATuîwă(ťĆ®Đ‘·ńŤ˘„Ş Ą4tä«űú{Ďgd‹ ç<‰, Ů»{›tú™ňÉ”éŮwߏ"Ë9Üßo,y777™Mg 7FLÇZ˘Ŕ“ÉĆćÖ'GGL­A-b˘Hű>¶…ĘT”RřńŔ0RçÍ줝&đj+[a+¸6čXlšzŘ»ŁŽ×L=tě~»žĂĂíV9”ÁŁáü)%(„H”‡ÜŁ|nĐq‚Băśó}÷Ú2Aé0R·°ü© Jk˘8f0ŕÉšů|ÎĆć&eUaMĹĆÎ&V9Š<§,Âřf·:t5‡Łféw‚~Wײ˘w— ň®ďXt.:ŻŽî’'î\`ďú&eą´Đ,đÓ'KC7DűÝĄYI}˙H?ÁXn—¬ ű{N‹ZaĐđý˙µŕzűÁţ7EľwUżż†üŤuXc0¦NZBś÷–×bţ±śÜđ 4šňuők­ÁX?ęfM†µcË`]ZWÔ5cß’& •©ŘŢÝáÎýűXçxńÍSć“1[;;¤Ü~çZkówďßăě䀭Ý&ă1ÎY†!Óń„˝;w89:â7żúŁ­MŽö÷ÉŤA› Q#Żč|_Ű9б&Šb?˘×8äµrŦ2łŚE^€±8iżo¦zIXp@l5\cÓë‚°xű?lc×6í«÷lá(Šś(Ž)ŠÂ»jźTĄ4(‡ŁM6T)¬‘Ł:ÉłQО,L&ţ;1†lžł-OŁ5w®ť€¤Ł1 =Müy±‘:d%źŻŻĄß¸,ŘŻ€¶ei2Ŕu+tu®ŇąÎÝqÍéW\..s n&4uNÁ !´Ží˝wéţ˝ć‰€îďo:Apť¬·++ţßuźżţőŤíXăż±–*Ěb{˛_ Mzů]ż(y5˛ďÄČ9ʢ`6¶^¶6›±– ĽĹo'Q¨Ę*ÝólÁ]á,ĽxÉéŃ1Ű;Űllď0>S2¦ď2ÚÜd1›Q•óĹśáËÓ錭í-Ňáťť]÷÷99<¦,JÄ9Ś­u|ď\8Ű•ŁT¤Ńˇď©őtÂQŕPugĂČ– „?i”ý‚Ż!®©k­6pu»Bę–I§ ­Gksdů‚ĘX†é€˘ČĂŘź4^ ,śW”®.€ ®ŽăŁĂ¶Ý NČłśůbŽ-iXć5˝Az0´kjSY]H/ĂůçćţŻě»úżôšşaR:˙S+ků‹Z—Ds%—|§o{ăŻŘˇ- éĂm* 4  \Y·”żn4˛»&¬Ç×Űr{“2Ö–Éî:óîmŐoڎ*M@ú&,ŞY„UgJJn|Łw!Ľo{\ş@Š5†‡µşń­ ŰiěN8TŽ'_|"Da®}:™ŕśczvţM&“Ŕ…0ޢĆúJôěřÄłčk]c1ÎńÍă'Xg›Ü˛,Q‹ ď]ŕ leá ‹|Ül•ÖAŘ?®u®'?NÇ:Žüٱ=zW‹IKPě[(KŹśÔăíŇń¬'@jŁÚ1±?bçľN0\§MăNOŽčŘČ5ţ bŰ6 c_Ą¬Ôé Ë‹üĆŽpą˙I°o@u ŔůDVi¬rtę gÂ+8 ŻĽ-íwť v”É‚,»šŕŞBň§EľUŃ˙¶M¬€őöFÚôşNĬ§ î^ĆXJc¨JĎčö“^¶«ŞˇiUkě7‰Í÷áŐaĚ-–µ\oÝş˛mÝé©Î‡H\ő Îř1¶­;·“”ÝŰ·`r6&Žcň<#ŽSŚ©pÎńŐgźcŚée"&@Ő¶ë‘n|ĺn¨FT•Żöuěą ZëŽŔkH{µŽs •"ŮÜô’­Ş–ŇµŚ¶¶¨Ś'=ćYÖżŇpl¨őŃRMó¤ŃĺבWç+ VŤŚůýóďŐŕ"¸sžh—ŠÁÉř S9DK?i¨™ýôŮú.ôóŰ ż˘sľŇçL4é#QN›¨Ë3çđRׯz{ÔuI@ż<ţ»Z/dJˇú_C-IŇUľzµ ß­ü×n€ëí­ üo˘MŻ8×Ń/©‰~SYĘĘP©‚ČOx˘ę4 ř·YŕĄůůýAxKˇ´X¶géKóý¤žó_’ëm­}CQcĂP`¨ŕŁ("_d”EN‘ÄIÂp8"ŚďsvrŇÇ^‚cű fĂˇŞťG†Ł!‘Ž1ÎôľO­ŢgŚ €×1¨´F†Ň4%Nżýő§”UE¤?ĂXÇł'OŃ‘f02m #Íă/~‹’ĎÂHUhS8Ď#Ť N„G‡€ŁŞ Ů|(áîý{ :3źÍČłŚçŹógďţAP >µ™ÝJŞ‹*×I‘`•oŹXW'Ť~‚"‘εWösŤŚĂˇ•ňŐĽ…ůlFY–h­<ÔFüjs˘VUŇëK4N‚=nť¬†ÎWôdĹő€´Ť®Ç/¸˛^j™´łjŕr”Ŕ­ŢË#vËďÜ˝ˇśí´•\’ÝsŢoËv–ÝŐąőA.č¸ţß:üźúđś3­z…É ‹î˙*Apťü@ýoň…ŮÝOĄŇMŁ­BÝŻŞŠ˘¨(+ŻíŻ”řQ“7QÝ]Kš¶€Üxş7řëJśšj_:‰ŘÜÜDÇ18Č‹ĚO9±¶±čë{ţ®‘4îŔÉN!J‡”eÉý™Ď§â€$ŠĽ"˘VPEĂŃńŮg-‡$!;Ă!˘„gŹź4Ç», ÓJ+śň镪mz-Ô[”‡Č­/Ż©ŐŽ­óßG€ŮtĘ­[·9=Ł/ŕ“-ĚłfjŁĆű%üęj&·wň xŤ*Ňfł9‹ů’4%/ŠÖÍOTçś ŤŕŤZeUq||ÔpňËĐZ–’šé“ńqťëEÉŞi:úôç9V÷]‘ u.$_+u=N…ôsQ˦„×ę\‹(Wíš\ý_5ĘWOţt‚–cY›K˝šŘUN€?´ żN~Ź‚˙›ľŹZë¦R«*ĂŃń1Ç'§dYfĎý‚”Ć1q1"T˘››ľ*çLłłŔF§ť WŠÍŤĂá&qXN®đ_—0ËŐHçqQŠ8MI)eUˇŞÂ;ş¶_é§á\Ďđ§&Š÷ß{Ŕ÷˘$b2s˙áC^<ů†íÝ]ŇaĘ|2ăöÝ» Â|6cgw—/ČłŚť˝[|𓏙śťa­—·ŐÚ[?ýú1®((‹ŠŇÍ_+qëŮđ]‚š¨0§ëhיᅵ†á`Čb6m~YíkheY–Ą•¶˘ÂľŐhîy öϢüô„w˙ Ç<ěżsŁ,'ÇÇ€ î‰őôabĚ4¤Ć:éńGŢb­ęKIG©O±Rś¬îkŐg˛Qş@žöáO–ŞűËŁr·˘_:”¨pO5M¨ úăWt¸– »*¤»ä.réw—KZrŐg-ż×RŔť× Ŕ[ş˝É}~ďʧšŔ˙ěů ŹN(Ę %Š˝Ý]îŢľGǡâuíú×ëó=ázôŻžóŻ [Ö&ÓÓŮ”łqNY–lmîpN#ü;ľąű*pľlöÁŻ *}EYQUeÓ§ôV· §Â\<ĐžýóĆ:^>}†s0ŹŮŘÜâřŕ€ůl†ĹÝwîqz|L¶Xg¦2<ĺk‹ą×»Ĺ_˙ĹŔ”·ßąÇôtŚ« …3h­©”‚ŞňíŢíDÓ ň’\ă¦[WÜ 08먂¤°—nqí̶łu릞ăwm˙:$NJůę˝7IJ˝ź…Ă^¤uôôjmŠ•AŃ-% Wür¸®ťh»Şcü$ť÷] ń_Wqhdq©Ý ®Ý¸"/pçĎ‹»¤Ď¶tşKs¦‹Q’7ąmşNÖŰĘJöM˝`ëŠ˙ë'O9::¦2pďÎŢř~Ç Ć…+Ӹµh†ëĚô»ŕç}ă} Ą•ńíÉí­Mv¶7ńb6y^đůg}›Ďď)©aqiŕńƦ7$DIś¶đ¦łAđČ`ŤAG^eo´±‰Ňľ˛ÍćĺÓoŔiʢ$[d †˛lÎt:ÁV¦á4B( Ó9J+˘8&Ď2ÓéĆg˙Öuś»˛ZîňXÔAşö¶^Vú¦(ÖEAÚ5C$#wE ż.@xjĹŁËë‹öŰŇ|çöüŃąu¸X'oÓÖµ1}żVŠŮbÁo~ű%EVńÎýűüčýCĺíÝăĽÓ]¨ÖęąţNĺ׸ĆudLȸ—Iă{mﮪ ŁŃŕµÉúŢč&‹"E‘˙G¨4e0†€«Â¬ąUU‘ç9¦,@áç[›D‘ÂXÍŢ˝{$IÄp0"Ë2ŚłÜ»wŹý/ĐqDU”eĹîîeYŕp¤é€éxŚ x˙„»ďĽĂŃÁ!ĂŤˇ·˝Mc>ýĺŻ89: VÂ^śPŐ,5şrş˝ý®ÉOSőJcÄ–Ć i2čôá Łx MöšVŇľńłü:đ p¤IŇT„5ňăś#MÓ¦/˘Ň_;hĘŇű ‡ ŻĄ˘U3WM‹ŁE–ü˝•¤†éQ:)WD±öÂGiJGţ|ÇQ”‡ź:ЉbŤŠük7v¶ŮŢŢp¸˝˝ÍU wé´•®»YkŘÚÜb{{§µ<ľ Îu’Üîţ»›żüҬ1llŚŘÚÜBôđŞÍĂ`0ÂŘŠ §A'ı>ďĎđcç’Ľu°Ţ^wđS·8ÖěóĺWOă”Gďľ×Ś{U•éČ­KĂboűş$ĆâH;×_÷u—gű»?ëdâu¬rŻęX•%•1”UŮě—Í26@úŠ8މâ”yAžçž@§y–ń*“ń)Ö:ĘÂż—ŇŠáĆFH6M'ěżd ŘŢŰ#›ŤY¤ Y–“Íç(1źNIŇ„˛(Q‘ö¤CîlŢăóO>!Žł9yóo ˙ŐçĄv׳ť*´qÄ«kcĺ˙jťĄ( ˛Ĺ·D(‹g*¬(˛,#¦{ţş&=^ä'Nü÷®+ůfü.$é Dľ–I/óçG‡‡RťdQÂż»‰BťPK}*‹ś,_ D7j¦ňNEY_»—x“ U@Ŕ‹e6ž€ŇťJÖ±˝˝Íx +HčV%ŮÂ6Lu­TŁ?_ŹžsŔ8‹D“ń¤7Ź ßAmgw—ßž}Š­,ÖZ^<Ç8Ë‹§ĎĽaU"śW¸˘gÇ'¤„b±ŕřđ[–Tˇšvxő@kü4Đçë‹ĆŘĘ÷đEBźY‡p ÝAwÄŞŁ_ĽíŻtĎ =9řśłŢ±6ű±ľÍÓţt[Şć}7ÁI”ćřđ`©ŹĽ˘ýÓ$7aAZň`ýŢÔÂ?a‚NÂéjůçZť ¶›ĽZŰö3”’ýĆL˘ű!mŹ˘>–FškíĽ/ĆsűË$‰î(ćŇ߼hRźTrîi7ýW 8Oř‘úż‹ô:JwD¤u•xťĹ˙}pť¬“€×ş/EQňW?˙%ŁM~üáÇ^.5¸Ă±¤Ďß ÚíďAw=ůřżuá~‡sŞózčkY˘‘wy7éţ]”É«WZ2’kzç‹(K*gÓjÖűŮxŰĘ!o|d*ëcŹR<úđĂf|- °Ćđđ8Úß'ŽcڵdóďĽ÷<Ďůâ“OQJńţŹ?bss‹_ţüçÜ{çŁÍ-ŞŞb{k‡ŃÖ»·osđô*‰'TĆP•9[;»ě?AYü'˙Ůźńóźý•W´ľ• ® žuŐć‚˝pU&Fą® Kͬw˛\8˙m‚ Ť8O3}˛ÂîÝҵĄźťb*{ńŚşt”ü8?Żß;•"ç*ě®ípŠ:„Bi|čŘÓ"*´|”Ë˙rŔo‘–«ĂčŠ@ŮőX~ú^A׆Ďĺb΂ĽB7ŕBŠq…f2CţĆRôešo†ľ­Ł€ë`˝˝¶ŕWźü†ŮĽŕGŹ~ÔôÝŰľ»˘‡ßíń/Ť…5Pl?Ăî˘Ý,żÇXżÖ’óÝ8.a¸}‘’@*“Ąq,O^w˝é뺯w «Ű9Ëp´‰Öší˝=Ž^îSä9Ţ{ŹăĂCŚ±Üąß[źŽ±Ö±±5"JRD+˘(ÂXË`0 N↠$1Ź~ü“Ó3Š,ăÖöyY˛łµ "L&ŇÁÝݲ|ča|ë†> leɳ̷?*ź¸Ô 7k“f¤Ńv*¸&8ş>•O)Eš¤čHcqTeĺ} hm‰ă8ÉŻmH ˛yĆb–5°~/@u«ÄĄŠ}©˙qń5$Ý Ógý_©Ú«2°ôWH^/ŕ_: Ř?†í·SůX–ş¬Ŕ·,+fśzőŰĺÜß\{ŽšDdŐîź'8¶:+S W.ކɀu°ŢľEĐ÷·ćt6ăońk~ôţÜŢ‹{7J7݆ţÝŇxźëhö»ŢČ_?řźĎn϶nÔ¨BčßŘßW&_/޵ˇNEb× +^S‹íČÝZt'JI Ż <űćâ(ńЉźî śŔr¶Ö`ťm`pďÜgČňŚý—/Q˘’ů“§śł˝»ÍŮń ÖÂáË}ĘŞ¤Čr˘(âěô &'§Ěf3˘(â׿ř[l°ţ5."Ň Ł8Žĺűű&6‰ Ł}ť~»· ömĄWK viĆć”RŚ6G Ň1ťÍ˘ŘEŢ(Nbň<$ĎKĘřč#Ž˝­®Jk’4a8ÚEľ‰svv} ˘,K666YĚ3ŻtśtP˛µąA‘g8\z2 Ň­»·oQË|6Ł(Ęž¦ŽOÚeY!J3 ( !$DI‚*çŘŽP™öčEžs|t䨆d(ëެ”ĺ˝ _ń¸,ŐĚŇŻŻŐĘjżkR%m‚pˇź»:ŕwŕńîţ,ŇÓ·Ô.ĄÇ/j'HŻ"[žx˙Ű$âZ­űŞ()"oS›ą’ç´ýý©¬ÁSź4MÉć‹ĐWŻřâ“_sëÎň,ç›/ľ¤,K6·¶uČřä ETUÉŹ˙čđ×ń89:"NbŚ5<{ü5/ž=c8‘$ _˙ć·Ś6·H7†LĎNŮÜŢâłO~Í`4$_,Čó‚<ËŚFŚOÇHĐŢ_,(Ąt8&§gL&â8f0ô={DQ•éhHÁ”%eU‘Ä:č×+Śshńą*Sá¬Ĺ8C¤˝đŚpr|ÜL8c9;>a´µĹćö&‹Ĺ‚4Iů»żţ¶¶·˝ľ@–se…¶Ž*˵:ëłŮ”ᆯÔoßżO‘¤éOź' ĆZŇ$e±#@YVÁÇ/€ÓéĚ %)eaâĘTTeĹćÖf¨đsʢŔ:CUş(q? IDAT–ŁĎgĽűŢűXk™áŚFŚ6FĽÜ§*ކDŞ”f¸1$ŽŠ,§4Ăဪ2ÄqÂĆXă(Ë‚˝[·Y,ćTe…qfEü’ëáüçä{»Ą|{íÖ˘A®ť÷FĎ÷ .©®Ą_ĺ/íŞë˝Mđ{0ľ¸6ŘËeUďc€ŤÖńđ»bµđµvWÝKK(ĹŐƆ„¤E}ňdąl\÷۬ ?T‚ŕ:Xo׺ؕR<yŔW_żäŁ}*4ŐŃ:oÜ2ôľ‡ż úżľÚßůvB_4¨‹ô'ľ„÷*7őąőŞÖ%˘8f4±XĚQÖ0 ë:Ň;щďťEIU–¤ĂŁl!Š4·îÜask‹d0 *K˘8âřđ(Šx÷÷yňĹW8kx`-•1üĂňŹyńô©÷b"ňůŚŹ>`ľˇ•˘Č Ł!É0%›çÄID’(óśŹa¬ĺŢýw°¶"Šfă3ОâđĹ>;·öŘÚÝf:ž˛µ˝‰µŽ$0ťŚŮÜŢb45ŠÄUURe9Ű›”Ö<|ôÖvövqŔ˝wîcŞ ýîž>~‚3ţ”UÉtűä×Ţr×YʢôçUk”xÁ&śĹÝ<”0m ´fck‹$IPZŁuĚ×_ük-g'ÇëˇöÓĂcfłY0ÖńÖÍRĎŮ;Çńá‘˙·ó•ŇŃÁ>·ďÜáčč¸Čyöřkv>ü$+xńô™×'… ,¦3o:č ÎÇ=× k(‹ …Fë8>:b29ón†E‚˛B´j䇭ńÚŠ%ă,i“'¬&śő’Áe=~Đ Lł,[ńö3íaié9Dťó6lúřŤĂáe:+ĆňVYá©«*č‹!€ëvŔ”şÉ=tąüOŁé#p‘—[i=Ü®Ű ŻŢl#ÄĹ[ô× Ŕz»4ëíÎ'źM¦üňÓ§Ľ÷î{g˝í+‚hçŤmťéjdnkd€ö†˝ŽÚź·‡•sĐżôÔŕúžuŇ ŰÔ.ë˙|˘!˝›űűđęŮdŐ(żEQĚĆć:‰Q˘Ă̱—đUJűŻc=:`+’ÁŃƆfJxřčăł1˙ôź˙W<ýú1=â·źüš“ă#>úźňއr´żĎćć&Ďľů†­ťmNŹNŽy‰hĹÉáŰ{; ‡LĎÎH7FÜľ{k,yžł˝»Ăb±ŕţwřňłĎ±Ć§)‡Ď_x‚bX¸uyYb 2+Qĺwč8FG~Ţ_”w l¬ĹĎňGQ„ŇžüW•eËŤkP&Ł("¤DI„ (ň‚Ş,G€'LZĘNRâ8˘Ş g§§Ę\\‹lŃ顫eĺĽĺĘ3ô˙—®3'K˛µÝ«č9DvŁ.´/˛˘Bď&˝ď°˘şŻ©Ş{븕Á˛o—˝:X5ÍX·ĺ”ô“íëWŢr ăşh‚ë' Ţ…űµ˘ßďmť¬·&Ŕö.ç(Š’˙řËĎyôđ}¬­…GĺÄ'ÚßW®Y4;.ca†›kŞýť‡öĄ×Ăo‘µÔčö\—ˇ˙ó“ß‹ż÷…oí§ęoÇ épč+ÓŇ`L‰ fÎ qěEn¬Ş‚ ŽÓ S¦“?xź<ËmlđüëÇÜ~çyž‘eQ“Ä1Źżú’÷~ô#¦gc¶÷¶!1ŤÇcp•âäčŃhÁ`Čî­=f“›;ۤő1†÷~ô#>ýĹß±ł»K:۶Ą“ŇĆy­, ”ÖD!!%(ń^Ö9Ź<8ďĚ7HÂĆh¨Ń % (MĹt2ĹĄďá×|“”­µ”eé$ë8::dkk cmđť°XçĐJˇJC¦”G˛¶#Ó{ö’˝9YR’[RnlÝ;şŤ‘°”Żöř„®ď·i˘´÷Ě…ĘqnŔ-é\é{ßgë9'ç}·Ň^FŃ.Ňë»Áá5& eu’r唬ţÜş8p ęďh-í®5ë1Ŕőö€ű»×Zó—?˙ż˙1Ą±aasS8ڱ®Ijµ®ŕ›™kyÝj®ă@ç÷>zĐÚ ÷“Ź×}ün” Ôü*稪’étJQ•(QďpâpĆ{«kyw9c0¦B)Ĺl:%Ňkóé”çß;c8Q–%˘Ö9ćóY›D"Ťň`cőŰ ´«ÎXHÔEçS伛n‡; KňŔ* cÝ!}Ő)Ő{‚ęA˙\áQőĽ<7¨V{Y‚ŐÝJţÚĄsďŁ/yţMÔxş‰”şFňŕ–QŤ>AP}Gëé÷Ź.®€őö*ţîďQńW?˙K>|˙]ĐTVăś`ĄŐô7ÎK®ú$ +ÚŢi]]€ëŞýőY˙ęĚwU`ď>§ŹĽľ`ó÷”NaŇJÇţ˙ě˝ů“Ç•&ř=÷¸ň¬ @á˘HI”Ô’¦[­ŮÖÚn[ŰÚÚ®ÍßÜcűĂNŻÍlϱ==ęCIqŁ€:ňŚËÝßţŕ‘™… R"Y)ŁÔ‘Uy„ż÷ľ÷Ě)ńLeËđ÷Ĺ—F -$‰ťęÓAŐ5ŞŞ†fŤă;w1Ú›âÖń-|úűŹńáĎţ ˙ĺďţܸéŢâ8ÂĂ?|ŠéÁŞŞÂţÁž?}ę‹úť÷ŢóǏ1Ť1śŚ H¸Řŕ ăý ňĺE^ŕĆńM<{üG·náőÉ ŽnÜB”$xýę&{S!]Ôp…ŞŞ0ÝßÇÉ‹—(ˇ71śŽ‘¦)ňuŽĎ<@GXçŚV ĐuŤÜ´6¬B´E[HgŠl ´Ň¨ĄBą\˘,K¨ş KvdKš|…fŚbçLÚÚ÷R0ö‰‚Ă\x›bjźШ9hł¦¶€•Űós)ý˘xIŃßj ĽđÓ=V—5 ýĘÜz @ŘôĺqwşÚ]1űZ× Ż“Ż€ëŰeĚváÓĎ>µň,BÚ AëĘX4~őd?.;á«6¬¦G滪Ű“€7fŘP l*řĘő›‚o3´tNMnźc)c+ąKHH”u ]+) é ‡v_®j…l0Ŕ°ŞĹ6rWĹ dTqpăČ%ĺ>üéOŔĆ“‰• ¦ Ţűŕ0ëŐÇwî /süů˙ôK¬–+,g3D‘Ä/~ő+<~đnß˝‡Ďžáţ÷ßÇ`8Âůé)ŽďÝĹją !¤ ŠcßÂáÍ# FCdYŠ˝}śĽ8Áí»wńęĹK †$Iڞ,P•5„8<:ÂËú%´2"űGqŚ$MÝ\Ě`ĂHłRJG<Ś‘$)ŚŞ(¬U˛Ń(Š5$â4C”$¨Šy^twNŻÔ›Ţió:á°đN}´Í Ř7VšŠFťę ¸]“mő ńĄEź{Svkwţ^MDvŔ˝1(‹űÝ 6ůˇűcÇzW[\ˇř®Bl$‚"Śę6äoq&|Ű’Ż€ďřÔżíkÖĹgĎq÷ö]GXłM±‹­%@ł#­ąÝ¨f öc˘™r=ĐÉIĐŐ ˙Ë2şQÂaŇ`sŘő׼S:ôU›zĐ–ôC+…b˝†Ş¬[ťVĘ2é‰P˘MĘş®«‘X.žEφaX|ôŻ˙Šńd U˙«ŐşÖb‰×/O ĄÄÇżů­•ĐĺQ” V˘(q;óŹ0šL‘¤1–‹¤XśĎ,3˙ôä´Ö¨Ę Q$P×5†Ł1^źĽÂÓÇŹPŞ˛ÄţÁ˘$Ć‹çĎ`jŤ(‰læĎć(ËŻžź@Há(ł†D‘Ŕ`8B’d±]…°}lUQŮź'Čűú(Ťş®°Ż ąŐ!ŠŘfhň´Ăt‡˝JĄőí‹4wxzĺ-Dž]@?§.(EÝ@_‹¸+WcşbŃo?Ůů}(DÁ¶Aâňm˙ľ|Üßn©­ŽEo3Á_Řٰl<Ö-+€­ŹçňŰ·1 đşřţţžŰ-ŽbüĂďţĽwß’µ|oZŔ0¤°żV6aąX¸53ŚŰ÷:% mĄx*|ÚŠá·OŢľ70Á×R[GĂ`‡^‰@oň 6óëĹf‘ď#oYô/÷Ęď|Ţ6)ď€ęwşóV€·¬č +±łĎđm›÷hčZű÷žÝŕącÚânH|]$®€ď.Üß˙zĂŻ_?Ăý{÷íaęIM-¤Iî •BC8¨_ Ťpë€Fŕ « ĹʢXŇúĹ÷ż]Ž€Ük ¸—ô·ú·v§ţŻ.xLJ6ČZFk›§Y«^­´C#4€ČîÂŮXS ­ˇŤöľl ddÝ÷B‚ˇ5Ę1 a[Ů]ËFhĎEŃ[ďÚ˘%ăŘ’ “Č?×B¸waZŁŞ ”E !-11 c6EhüZµµ5ÎCŚĆ•»/HJHiŃŹáx€(N˝™1`†1RJDq IäëĆhDI Uئ§}Láč,:\ľĆ‡˘ťWą•ů…ŻTçL ’ü6S˙óĘ™·¨&ř~@ôĺC¶xCŃżR oş˝K˘‰·ÉěÂIžh®ź+!W>ŐĐ'#Ň%u~đ°ľLŔŰśżýa㺸ľ}-·«ŔýáMJ‰_˙ëłĹ­ä=—?‹ 4ű|‚ôćšĂ ˛>ÜrśDS¸›Ń_tŁ|»FAŰ3Ú„ÁÍ ľŐpúWŔo?´Ĺ%Ýîöu­QV%ČMŢŞ¶‡¸6 XT˛†Şm0F#K3¬V+ZŰ Ţśž¬ ŁČ’3µIi2cóÚ5ŇI礴…Jim)mĽÜNFVb×ÚŘ˝nLÖqϰÖ 8đ«'H)¬OA"!D­ ´Ş!Ŕ0Ćľî2Š ` |ěškŚ$#é vaý$„ŚG1ćő2Ž˝#śqQ»Ć3ýí'üű‹)X©PG.×ÎŚ{ÚLÝňÝ•ú‰Ąě]w8Źť…?X„ę™í“ľŘ^P; @·—¦ m+öá¤Ýö¦ăękDĂőŮąnß×{i÷Ük:¶=ôŤűî‡26ĐâŻĆč]ä‡\7×·/6|^îďżaó|ĺ}üŃő‚‹˝9ÜąH[¶oŁ XÄÖ…´@9–5ßp‡‰@™˘ÄíäY|0m‰yô…/ćmÁ>#řJ`@ăhčžMG ‡Â†ČHa'g»ż'ďĹČÁâI–!Ë2čHŁ,K€l¨OG2‚VĘ7Ý®”uÔlP—%ęşF– 0šŚ% ”VČW6^¸®k€ş®Qä9”RŢÝÎż‚P׌[M˛† |ۤ€× Ŕ·hę˙"Ýëjµ‚D ¸âĎöm*7…ů>ÍôÝ[ǸghH˛?ÂXżm„ă؉D/‚Ă}ŠZ ý7ź ăT u÷Ł­|?N8 ÚuˇżéÂţ˛µIś Š"ÄI)#D‘„#/Ö•ôĎFH’4nĎOBBT•őSÔe­¤´Žn†ŤuŐSR·‡ť}Č ź@+űxâ((ŠşVÚ·ż  ép€XĆűűČC»ŠqżťŃ ’ÂJ Wkéx$Ž]v ŇiJ¬ hĄP×Ę[O¦@0"¤€Ş*$Y I{{q@Ł ¤ )‘ç9dQ˘*k¨Zc8 MSDq‚ÇĆúĺ[4Ŕ†I!q~~†÷>ř>ž>zŘ2˙µÝď[wFíf?—dć&ł™e"3DĘ †ÁČh[đ˘Ú´p¸Ňl4¤´ÇEž€Ö(ęĘ6B8Ű^× ae§Fk(m|Ó'ŁggâB¨ŞFą. „Ä«—'bkôcLĐDhŤÓÓ×PJŁvĹ¶Ş§3Ň,Ńëĺóٲj€˘(] ť…Ą„{SH˛DŐĆYĐű jS=SĐ5 Íç]8 0_,Ih"čşFU×Čó±Ö )-ą1ŠĹ1´ŃĐĆ ŠŘ† űz˝xţ“|ÝN˘ĚXçkĚ/ć›äĽŤ:]ľtÚâŮoŚĆh8Ŕł§Ź!…ĽÂt˙–¦WĚŘ›N1›Ďí{+1 věíŻţ3´ŇȲź=xŕ¸"W@”ĆÉĎ­µăŃq”`µZn8Śn{<×i€×·ou ”Ż*`ꊂ€#01‚m„c•»}°'ä„ëăĎ1iĘTC3í´îîťÍ‰>ôß֮0p›<&ě„&ed˝áăD˛gEĽął˙ş:ů–!ŢđV¸ŁTrcř#=\Ű ŇĆA´Ö¤§yÜB$i 6ě¦öжqšw[řáŁd˝lJ´:xôśá„çW˙{ I–סkTĄF6ăišX¨Ţ˛ZjXű ĹĆO҆6ö=ÂÚ@ (‚†V5€2ů:‡L´…ŞýÁË899q*v÷x űAŻ( °ü8Ć`0˛ja×ÍűB+ )% uU{yµB‹  żĎoĐ×4ůƀРjá´feBA0Ö$$ B¶M˝Ľ$„]ĄÁVçľNß‘ Úń:¸zýßšFM8„Ăß˝ť)Nۇt D$!ťŤuÇúđ]ďK;°His'®ż1HŘŘkIpś% " żŰ·ëŕ»Ű=ŕɇ¸qpPlĹý’;ŤÁ´ń¨dlä)Â,§›fŰę7NH‹#ˇLcŘ9RK2lö ŤMŕđ§TĄj? ¶ŃÁÍn_řN])Ąj”ĄÝŰ"•úĂŻUÂń;SĽőşeËßZąZŰÔ4űTÂéřza\!'ŕâěq’@+eÇä—ľÁQ –!íŔ˙8áKRw„5›é@²ń“Ůp`wěڮؔH’ŮpÔhë¶×¬ŻÝ÷7rRQÚPž(Žl¤±1R  0QS˙üëşFIQن‡µŞÁĚ8}őĘ’ť4„ý/ŽH!%–$Y×5„Ś0`t ĂŚ$ŽŔBřUHŨuŤ…ZŘŐŠ/RÔqăő¶={ßđ˛áž±TëůďW6Wäk`óTÓŚŢ{_xŮ^_ČF›E_„>ňE_tŇóţBî{®Xť·űVIŃËM?FW˝(6 ł·®<6©4|ŮEü Lë}+ńëŕúö§óÂK‰ŮÉ&·nµq†*Âţ)ŰFŔN­.U-Ý_„Zś MÜF3ßH× ŇP$ˇ™ AĆűšť=5đ4|L»§­á@ÔËh••»Ź¦h‹˙»ą¨űĘ€KáXtÖť—«=„˝m=;.@XpwĘ·¦Ŕ˝ďÝÇrq€˝˝=689y‰“§Ďńăź˙U•c~1łë&dĂ EQ@ ‰ńt‚bťc1źc0‚\6@Çť]ŕÖÝ;8=9ńJ)#Wü­a1uY€–L‹AŰý*0ÚB§;ń37LŃ".î1ŰČ^ÓJćÜ“Ać‹ęZA’đ?‡„mT]A“@UÚb$ťd°ČK˙ÜÖµö6É B%JTUĺPŃÓď‡üráx0}ŹŢ`˛‡“z‡€ę_báš]tXçŢĎ.[~ęłÝ©'h˘Ą›–eWŃGGŇ ÚŇP\VđĹŤ‚¶_,í]†×j§˙÷ľő®şŇF·Ę E÷gs¨ÚhŢ]Qľ A𺸾ýÉÜgŻN1ĚFŠ––’gŘs¬žÜÚúB˛­ýd5Ú@­P*°V!n˙EĆÂn‚ µ¶ ‚ÚâŐö˘wh¤6ĺ:ď°ůĂFŢÚŰ}sČ2nČ=Ć0¤ ¤Y̨kŰdŮŔeÓóľ¸űý[uőÔ—Ny9' l‹_çç"´#µŻQś$(ŠG‡¸q|ŚŐbőj…3a0âĆńM †§`ň|ŤźţĹ/đéďp|÷.?|ţäǨµÂĹëSüő˙ńżăŁßüëĹ Iš˘ŞJĚçëx‡N?śöüĆ>3řEżi\Á§-«„]źĹ6«kF(ˇlPÓRíŢZ|‰ĺÚĺ ßü´†aW^w\ńLř¦Ż€ďŕMgOźâřčĐď—»"äiäŠ Ř@¸F 9,˙Ż™BL«íof·.pŃ7’!Q m$ Š­›`]VPŞ˛+€ĐŐŽq»Ý~?¸Ťöd5Ąî2ď ‰‘çkDQŚ8ž|!ďÝšzPkËÚθđ_đ›¨`ß Xż,J,Î/°¸¸ŔŁO?CYäŘżq„ád„gʎĚsDI‚ŮĹ “É˙áo˙ĂáËů?}Ąj<ú{űű¸qëţŰüO6p§®‘ç6śH)Ť¨ÖBB%˛ÁŔĘ•AžŻQ*4ŽE‘—eI'×#"°f/aRXą›ĺ“$‘•÷™8†Ś-Lźd ڄ֏X­0=ŘĐBKDn§Ĺ‘C!ZU0c4`4™˘® ”u c4”V¨ËÚŮ‘#ć5ćJIšX˘˘Ň­s\ŢçkiPü=›µS@Čs=Z˝»Ź'?±îJÖŰaß»eÚoT-ťŢçő‹>ŢĘÇ#§NŠí.ö­˛?P@ ‰ř ʺ¢lÓA‹»˙]aĹąyĎď.üۢ¸nľ7)%ŠU3maÔîŐŽFĆA˛F€¤“ĄI¶Tă'Nvúó$BçŚfHx’ @m­#f,óÄ6Öq l¬ĺ ŢTF˝kÜväQ!ŽckNSUNóL®±^ç;CŢĄ.;ÜĽĹ,9Ű\éŕ~‹pč>7ĆŻ8ŘhUăĺóç ˛áuUc1»Ŕb6Çr±€Ń­ĂŢŮé) ¬—K †cĚÎĎť‡a~1ĂăĎZő1ś<{îL~Ř‘íţß3ç…ply÷ś ëŕ×@úRË0 lëô˙˘YŘďŹd„(‰Q×mŢ€‚NÎN!ăq” I3_hdd `I’"Ëlc ęya_÷áh„Ńh€2–•BľÎí:HÖŢi8Đ AČóZiŚ&cäëZç-ŠLÝ”)lĂo±b.ŔżGD»[˝Ě uťoůÂ/{ŘÜ=n tůţťú;©Žwţ ľ[Y—ŘžqŃÎT@±ń €íWY?]ňóŢ|MoCţ®ÓŻoßřŰrµD'özíţťĽ÷x{°9g@ÂkŔ­X¸f슾süńPBSřâŕďDĐBcµ®Q+n'a0ŚČŇÄĄv}Đű]ź#68ÁJ)yî9JŐÖŔď¶ŁßM2µ0żű’(Ž1Ť ăŘîĘťGBYU¨ŠŇ1ŐᑌvCŕvě$°wtńxŚád6@‘çL÷0š q~~a—V0LXś]`~qnĺ… @i:Ŕ» hő˙†Q—%–óĘ󞻨€‡ůą[pąń{ŇďFš&ˇńíľÔrwGÁňA®T|;&=˘ĹŢĽÍÚ-Śmť ·ľ†;ÜBŻe€×·oÝŤxůě%|8 7Ś|wXAP;—°;Ů9™ç`BÚf`áÖµç9 “]W0„„fšńŘNÄ˝B’˙Âa ÉčG7źŹ˘ٱÄjµĂ´ÎoŹ=ěvűB Ç !7ór…Ş(»…ˇ™ŻŘ‘ÔśSľZA€P×5öʰZ­púęöʰ^®‘ 2¬—kŚ'\\śĂ“öŔ6/­+ˇuL%ë*EPZŁV5ôB»‹aW1ŕ«"ýďĽŕďBŻ€ëŰý&¤€*kĆiŻŃäs?vWá@äµéÚőS‘-ţäPHvRBwHK¶E‹Z˘PU–F–ů=leţŰAŽč zŽEQĐŔ7áZ A¦Ó V«ő§#§Ţ´¸ ž(’vŞt×ĆEůÂů.F\ŮYáč‡HG#LĆ”U…˛Čqpóóó’,Ăěő)fó9 łós|řÓ?C]ÖHóŇ4E’&VB·Î1žN°^®p˙÷ńôŃc¨şĆŹţ3|üŰßa0AŔ`4Ŕó'O‘¦„S«(ó5„ĺ|‰éŢu­`ŚÁtoj ­[+d IjCŤT]áÖŤ=Ě+@ZOÓLľŤż_%¸ŔbIȲ!â4ńŻ{YÔh0BHi }d 3PUŤ(ŽQ%ŚÖŽGd„2/Q© i’"N’ŽTNŤ4nVQ¶!ŹÇ¨Š2ŽĽ?$N0Ź@.eQic=ńÝnžüëěDűov5(QźÔ×ů/™öů˛ßpnB‹.ő·üťć9´cbčcGażb=wM_±¨SĐtí;ľăćŕ›HĽnľc·˛(G±źđą)ţ"¸Řť pcnŇÂÄäaAď/fB8A:h„eěÚľÁ€„@Ą €ťä‹ Y˛gťÉĽŽ×ÎҦŤ¶™Mc"ĄuZ+ËÜ_tĂáČ‘©¶(Ŕt:~gPŢŰ7Ü= ĂZ;÷=8„…[¸Ýkčű;gűÜ•uŤďÝą|˝Ćx:Ćh2F™3öööpöę5ŠŐ l &“)Ş˘B±Î±Z®đţżU×PZc˛·‡W/_b˙đ‹‹9ň<Ç`8„Ö g§§"‰,Ëpňâ"yĂń{{űX,Č×k˘vůÇwď`˝\"Ž" Ż Âh<ĆbąÄ­›· Ę1›Íp||DŚł‹ąO˙k=ůŰ)3<@U­QVŚÍ JŞŞF]iÔşF$$"0ňµvx– P×5 đláß×€µJ.ŞĘŁMä „*Qy™ź b8Âj˝¶QĘnĘ·.‰ň˘B”0"–¶9 Pîăp¤Ď.Ôß{}i[ňő¦ý¦  l:úďÓ yçÂ]°>‡ĹţŞpyŹČ˝BO|©1_i3Ŕ[o^xZ’ˇÎ®źßAMţ¦'^7ßÁŰěbŽŃxÄň®pčÉťÂx× Płűł§ÝQű{Đ 2¦E¤ľKĺ&#!3DńČíçv±.(ĺr !ÓéÝ7 ËÚŘßŐj ­5¦Ó=waRgU@$IňýK÷˙®.ě†`ÉhS‹Čy–@“»ĐČaě稫¶^Ďřç˙ţʶqp“/1Ak…§ź?¶®|‚P%ę˛Âjő‰‡Â_>{!î˝˙=|ň»ŹK‰“§Ď±XĚđůOÝ×Bé™xţä)@„ŃhčUŹ>ňş÷pČ%im…Ed!öŐý%NN^ ,JD‘ÄÓGŹńËé[”ą=ཀྵµklroÔČ™;%Iâ?!EŔG%"¶Đż Ä‘A$ě´^T6™ŮXĎŔ—HąÄXęe´áAĚŚ˘(QĄE4\Ö€M4¨ęĘš)gWëW;ě™˙ @Ć4[wü´cJ żŘ Ü!´“= á3 ¶Çú„Ë~ŃôßP˛˝VR¸Ćťú9ĆţwŰšÜ ĆöµFĐ5[32â+@ÄÇĎ /rÍ~;“Ż€ďŘŤ™qqqńxŇ“`Ş÷đ? ş^ ,yÝĄÍŢô¤U¶7:`e›mjk,­|0R¸×·Ud±a:ťz&x ďSđo{ŤF`&\\śc:Ýď…ý± Ŕüb†“ç/üYš¤)T]ŮŔ ‘D’ĄxýňIš‚ đ“ź˙RHÄIŚú˙ţ몆QşýYä\ţŁ(",KŰđI‡^8h5ńJ hc`L‰ŐbŽĹ|)%ĘşÄóÇOđăőÚEçšŰ÷ś_9W·ş.Q–1=+„QŤ˛.1 !”Ş]N‚†ŚbÔ°«ĄTëÁ˝8xjß·׾Ć<¦{řŔ¦v"íAäţľ)@śŃwárj;gěĚ» ?ď@‚iź âöqz[ŃďĂço*ř»'{ŢRč7ň CŢĂ®ËKôî´±(WĽöŐEř´w›Ť«]ŰßĆ$Ŕëŕ;v“R`µ.q0>°.ÔúűÂMÔ‘Mí2iuĐÜzŹtiÓ~âµeABWŇÓB&.Ń®»#%",sěďď»}żeű+ĄđňĺKÍPZµÁÝű÷0 ]9pppłł3˘%ţ)@xáéĂŰáNłÜš5)Ťîcť}:ÝÇĎů ,f3¬×9F“)N^ĽŔáÍŤÇX-¸uç´VXŻrěěáѧ@Râý;÷îáâôI–ÁŤÄĂO Ö•-°M”®7&2Mš ¤ľč[É:ą0›&žČľ1 \7^ööúä•k*L‹v×Z>{}>¬˛#MSK.Ś#ńR‘b4a>›ˇŞJ †CH»ĆPşÍ‘oŚ}DqŁ#‘ŁžĽ”ĽIwś›·!˛ Ą€ťŽŁ÷ď"Âm+ü[dt¬.š˝ţĺ7q…"ę~/–Őß1Ú>Ů·®"ˇäQlţŢâË\Foˇ ŘŞ[RčjCÁ·QxÝ|çn¶ 0 1·’-ř7z„$!ävH.¸™Ú¸µľ @J6†ł Ťd°×®ÜfM„ëőÓéÔ#Bž?0ářÖívĘ„§OžáÁ§đłź˙MŘĎáá..ÎqppĐ™˘› :´ňý*‹~čň'Bi`ű±¶‘ňű[Čű– Ć«“—řű˙đwŢuďÁGŤ-ŞGťźăŃgíă •„„2říď!ŁăÉăÉi6DU׸qçŠuŽőjŤ(‰'±ă#0´V¨+eCy’Äúđ†RµsÚł®ŤM´1P×ÖË•óóxýúÔłí›Z!„[…;)‡EżHŰiŢ}^Úźe´A¨Ş 2Š`´6Ą )rĎš”±Íš ő[ž‰¤ăcčŽaDÓĐŞź´Î@ËÔ4ÇáĐ6×÷”s[Ś€®Tř[Ž5iťŔŽ˝~0ąÓ ýţ”/·@ůÔ˘Xbâď9Š·ąR.©ĘžŕŘSđîŔf3Đ&cŇ[L˙ßćŰuđącE‘łÇ…g{˘Rç‰ěL§Ř„ÔíuéöĹD]7pjŁ[•Ń~O äpd=帕átÜRxذĹ˙ččŚŃÎzÖţîĆÇ·oá˝ďÝÇ?˙úźńoţâç–  Ë2Ôµ-JŰĚ‚ľ®Ž><ŽM3QpłvŹł?XIĘRđrĺ¶ĆŻ]4 Löö°Z.!AUUb2ťb6»@ľ^Ł®m*kűÓImP3c4#Š#¬VKÔ•MÓ‹ă“ý©µ–ÚhČ(B–¦ ÁÔ5”VU Ň4EĹ>Ö7NdŇ^‚Ŕz-Q”%HHĚçsTUéß{¨-‡YňDîşz"¤Ť#f Š"oÖB1 `¤°…Ü…J+FĂ1 FY7@EPuí$„ʢŔ`8DIäEaن90šjV5ť7AO[v=oBčgŃGÖúi€—ţćďä:‡°@[05]ˇč6,ý» mvu~GŃýţK‹ü­ żÁßź¶öK ¦ÎŠÁňloµü«ÖGtťx}űŁ~kš"A(ÓhŠ­a‹đĆ.Âďá¶?BXăběť[§5B6 @€ÇYK/$F#“%A(ÖkL&S˙ýv’?‚1şăüJ•Şń‹_ţ~ó/żĹ/~ůçĐZc8áüüűűűxWšź~”đU/lÚâ:ÇŇÁŇI•VP pW+ĐtĽZYZ`MŰLžB Ü8Â~ô!2çzXWîĽwĎ?A]ŐÓůz…›·oĂhŤ˘(0Źpq:CUĺ$0 ppt„˛¬0ŹQ×Ă!ţĺ˙ęŞFYU¨ËĘ&ńiŰ Ł˝¬Ż˘ÚhhĄˇTí˘y˛čŤŞQW%łąC hnî§ëyTmc ”Fž—‚ •n‰‚ĆĆ{+dŘCă˘Ëş„Đ.HĘtUˇ®j’#ÍŚŞ*a8¶> Î4I[Ô´ÖÝ&­!™†Á7. <‡†@.LkÇň§µCŕ ?o­’ˇź6‹ĺ.xżWôwMů!śß±ظĽ¶{ÂÖ ¤ţţŕ ¨~͸ő ;O#µ”„ŻDŘ?Ţm~Čup}ű…ßĂÝh‚fŕYýLí|Ňd®s0čř¸šNL)¸‘6Šţ†Q Á&6¶®qâ×Ö›ŢIŔ [Ă5´Vžm'`!Č“˙Â7Ą4ŢűŢ{xůâG7ŽĐpšďű"â.SŹ>#řňŃeóěĄĆĄp4‚LPA ‡¨÷¦ČĎÎ-ź:ŽťÝˇ%Ř™ţ/Ć0^żx‰‹WgNFĐÚŕýᅬĎ>ů/žµ;|ß ‡!ADŰ (qŻ‹^cłc%piă°¸B×ŔŽ6—w_đĂ3÷›PřŻ€oů-ŚÍm‹ŘćTJ[&w€÷ |3‘1Y»Đęw—Q퍄КňČ8ö ›Ć”Ä Š„/Ľł™U„ľřm>@÷ďĚŚéŢź?|Ś›·n‚Ů Ë2TU‰8NŢY'˙…‰2 è”Âz˝FĚŃô&ŞHBÄ Ň[·`¦c¨ç/@ĂDľ„®‚ťr@,3Zc™çXŻ–ç§Żf¬WK,ć ,f Ôu…Őz Öëő„l8Äb1G‘ 3|ţŕ„”ř»˙ˇŞ*$I‚Ľ,ČŘ® ȱů…;ÄoÜĽW/O mÔź}ŻhC­  AuHĽzůÇ·ď´=dŰaD<×€övµľpĆ@† ¤Ćh'4¨ëUUş|+=„1ő¸Í9jĄ<ÁŃh­‚ÔŇÉÍ Ś!(e˝`–9Ś?©¦ÖŮš9ľm1Ëi`z6[Ţ7ĽFuiáçK¦}ŢŽ.poŇ‹>uě„iGĂâw›ňEË 4]ˇ oaě1ÓűěŤ5 ůíă–VăÍîW‘ !ľquâşřŢv©ĆXÇîĎy‹Ăą ŰýÝ"€9[;·{N a7wpÓ aAź"gŤ|ŘG”[(U+…HĆţ1hŐîű[=?ő¦˙ö€4†EöľŤ!gŁ‘$´Ű í'îÂş¤Q %j­ÇO0üĹ/Üs* ă8>FüŢ{Č?ůř|fIuC^pűŢ]¤!Ş˘ÄŢŃ>ňŐĂŃq٬*śż>Ĺd:ÁţŃ!fgçřäwżĂp4ÁÝ÷îa˙č˙řź˙ nßÂp4BQ–¸qă&–Ë9FÓ©%•‘Ŕ|v0A)…ýĂ<{ňeľĆÝď}EQŕâüÂSٸřčćQ:_ů‹ósÔµ Ć?ZʝƆ:«#¦$Č+(Ś16@ÉÉXÂhظŕ(B]× Řoź'HCkU+Tukţ7˝×uĺUű3‹˘°Ć@¦ ëé"cO L 謹8”rXw§S6nś[ hSřecƵeš3C…N´€oŢPô±EŞČŚŤÚ5Ő¶ÂŤń°=´Ż'@脾Ęç`ôo–5Ł é˛~âŰ|Ý|Ç ˙ćAQ =ő0Ż%ó1Ľ‚¸“z(µ§['/ĽůO¸ë]řŠŘÂŔí™Ň¬#¬vÝ’ýúpľß…‹p3Á>L¦y>ŚáK‹˙Wzaň ż—nŠčĺt|”ĺÓgHďß çsĂŔd?ü–żţ'1ĄpŮş0‚°Z®' ´®±Z,±ÍUU#_ŻA\śźcą\˘Xç0ĆFčVU…óׯ‘ X.–ȆCÔUŤ˘Ěqq~8NP…•VH´Ö ĐZcµX!Š%VË%ĽŚKśłÍy·ÂĽ,°/üÜOhuŻ€/ÖrÚAíÔ%Q6D<)D«˘pĆGM-j„¬ű4!´Ň.,Ŕž<ÇN ŰşĆ1ŘMąl“’ćÖđ2€slHĐ©ŔýüŚfx5ŹĄ™ü›»6hĚ‚¸őěߍ7S¸áíčyÇ:Ř)_šuM€6ř¬ÁPžĘ[T Űô‡ÔÂZ Ó6Âm‡Â:źćmęŘî—˛Ërâ÷†wănĚáSDž·"Ő7#ň:_Ż€ëŰ­đ_ö&mÍÂźţľ¶˝ËľŘ6ýć×…ÓAˇQ @4“…+ ­‡{Ç;»+eH!¬[›;„ ·h˙÷hˇ˙¶9 "DR8Ą€%n%IÔ1~a毰“ß~E‰Ý7ljD$"Äq„ G3ȇHnąÍĄŹö-€ŽbŚ>üőĹ q6@š¦Î^Y`~vŐbáS‰łł —ŕ좛‰ ¤%đ A(Šźú)íNś™ńčÓ`"ĚÎN§)^<Avמeʢ@‘řř·żGľ^#NRüöźţiš!Jëáďř`†Ö 팧Fă F6`8[Ż"$q„(Š „Ŕh4DśdíÝy¸ a‘'˙?APJC+ă˝ČÁďçŐą•ş7hžÝׂ”˙{šeţ{ÉYűzźüFšŘ  ÄiŠl8pćCö÷‰"‹:$i‚HĆÖő„Śś# „tČDEö÷“űűűO§µéĚŚýýÝ5‰®Č’ŰäWÂhÉhŚý˝=Ha™`{áľÜÎ`ĂŘŰŰwę€Ík‚ß*Żű•ZkŚGCL§{$7îźű¬ň(I3ë5âVG‰Ś¬2ŻëĆuđ-*ţW)b~.éÎÖh§]´ß~¬ ćáNÚž‡Ń›CÚ;«ą8X—ęÖ8♦0ą¦ŮŤ )Qçk hOĆX.—‡[ްIi®ycĂmc®Ş*L&“ŻQ¸ý~U]9–ľ"[Ä´a@|vŽä÷A™-†<»k’Čú'´Ş`ÖlYö )q˙ĂěÄ_–^«xóN_˝‚pn}Ó˝=Łqóř^ľx,ËđŮGźŕ'żř7ČW9’,ĹŁĎ>Ă{ĽŹbťc4™@J‰şŞqóřň˘€ @Dž?y†Ł›7ü®Sc9iŠó×§X,ćřŐßX"á˛XáĹó§îµ¶Š˛(Ż×¶ ëĘI×ë‰×J˘5·ńĹ;hEöBsކČWklC`„í× ę4”ť4<j˙ŤŔ܇™QWŠ˘đ™DÎ XiÔU Ä2!$dă7áGPÇŕgÍĐÜB L„ý˝=Ěfł-ď"z»}÷–wĄÖËŐ łŮ2’WÓ›&íÖÉbŻůý{ńĘ»űă«_‡Úh¬ňćÎIňňo·?H+ŤŞÎˇ•ő¤`ĂĐ‘U«ŕkćűVâ× Ŕőík‡űű—EG‡Ü)ä.#žÚT=kčď¦Öşł…á"!bĐý·/Öµ‘-0ő‰ IDATݡ†Z$5¸h÷ńűß~‚ţčďô6ˇÓźŔl6ÇŃŃ‘ĎĐźwwQżő}R«°hV+q# !‰(J‘† !#ŚG(ž>C4=†1 ń IŽ0Ě2Ś3¨Z!MŚ'SdĂŞŞqxĂţtáG?ű3Ě/fŘ?¬P9&Ó)nŢÄzµ‚ĂéuUcşż’ĂŃŁń{Ó=DiŠ8ŽˇŞ ű7Ž0©k,KÄqŚ»÷îÚ˝qY4IłUh÷>ăáOĹ ˛Á'/O,×ĂeŃéÖ@šc‚Ŕ›ĆîW4aTľ Ű/‰¤@ĹPZ‡^}®ÁAĂéLw{;ŮŁtn:k.‚đ ™ÂQă&ňrÁ&;€\Ux €‚u@G&vGŤÖWŁ•ôńvľĎĐďý­5·»ĆEó»ułB–\÷źÝ÷?‰nv·J;2 ú?w ±Ei˘tFKojÂńćL3ťáaCJH_ţL¸Ś xÝ\ßţčM€%Ú Ą‘łµńż!’° úçžżďÍżąhţ-ĄôZjKëHűeY6@YHÓ Z+|đ÷đđÁc|˙‡ß6:Č č’ôVËĆ“±ßů×uŐĆ`s­ů.:ú/ÔŮ»łZFŮ`€(‰Ažťapt%¨Y#»s˘V (j.K ¤0çQŚ×/_@H[lN^Ľ@%8?=2l4´6„Ŕ`<ÂĂ?üeYŘ8[áůă'q„$J R<ýü1†ăYfý –Ë%˘8IBu^b˝\ˇ*+$iŚ8Íśô.±X,0 đŻ˙ř?PV5â8Ćh4F^0Z[6~¨*ńĹ—}1kHs˘SôZ‰ŞäŕÜÖ5Ŕ˘gľăů!„.?µą…Ţôű4ą¶!i]2ŰŚöľ»őÂŤ'ŃĎ;öä· ‚iŻMnÁô{ůágDÓN°őöđ$}¦Íű ˙†ßGXôE·ďpA#@ExËţ?\Ľ‹]đ@…h†€@Ăü¦QdĹŤź@_řŘ&ţjÖŠ× ŔőíÝŤŻÎµ)ޢǬďƆ†®sMow!q0$ăő«¦`GQ„ş®ü÷XÇ? © «ĺž/ćHłĚî]ă÷Ţ»Ź÷üđĂď#J„7jT ''Żpx¸ŹŘ»ţćó9nܸáť÷ľLÁ˙“˙é06‘TµF‘çµ}˘A†âł‡A ş¨ôXJpľ‚ÖŚTJ«%”Ň`c Xc:™BHőj9‰a´†ańx„×/_cpx€“ç/0™LG1ŐqĹÉCŐ BčÚşäĄ qc˙čĐ”Ď?­ăcĽ|ţZkĄ ¤„ˇÚ«:â$ ±^Ż1žLAb‰şVPĆřă})G CŔ˘o t(Qm řćýé‹8… ‚˝˘ŽV˛Úńäk¤¬Ä[ů3aţ@7$«?ÉĚůP!ŇÍ› íÔĎxďÍeA>†ĽéPżÜm/ü;üáB^„Ó>oÚťŮA a輷mşßZěw(v®h÷·żéäwu„~»× ŔwčfĐ*šIVřľôÔť´ęPçk·Żşź·Ĺž=É«Şé9Ţ…ŚÉx‚ůlćĂ€Ň4Áź˙ĺĎńůgʎj B¤Q„ű÷ďz¸ź¸¸8ÇŢŢ^‹r·Ä„đľĚŢź=¬ň‘-˘ab<†YĐ‚°^,ş†!B=_Ŕ4évZ! ,± €6 wîßC”$ŤFř`ú!ʲÄĹůĆă „ dŮĐłż‡Ł!˛á/źżŔŃńMXĚćxďĂŕüőkI’`z°Ź2·ŃąUY˘.k°Q_̉ăéO=F’¦ÖGزŁj­jśśś‚CkFUU.Ę8,­ż>®öÍޝĹ0ž;vÔLmĐi.¨[ěŰÉ˝ĺ·ôł.¨“?@™ü‚ÂpĆFÖ×w•ořBŇb8dżnîhÔz°)ü˛-fW*üť˘.¶ ýiżťšąíqˇmÉ…ĽýMď×—vo(řŐ›DŔţc+rzN6đ[üń»NĽľ}lA)ĺ­7ˇ˙ŕ<ÝÉú×ŕc—Ł @§ÎpĹBôAÚ™aZ¤Ź1ŽpqqaYĹdm^ďľwRH7ů7étÚuăöt¸¸8Ç`0đD-ű¸m¤íÂłzn–2Ž0‘Ą)ÂŇT ŚĆĐË%TžC—µuŢc†vž÷FkkµËŔ“ĎáÖíc ˛>úío1ŤP9Nž=G’ĄHł +G˘|öř1ö0Ť°^­ANOĎđâĹ Ś'€(Žńřá#LöA(×ŚŃ ¨UŤ§Ož@kKěKK¬ŞTŤ"ĎńâůsÔU&A†a` ·rńNbű€6“ózS<!ŠbX3tťö„ťä› WťZJČAłB ŃŰłűŐz Z vú^¨ÚC((Šíş›ü÷Ăíö»ń?ŚNtí®2° űđĆ mĽóöiżY§ř¨Ţ,úÚ€sđéP|ľ|ŠÁďÔ×éq Żxsâť,ĂŽY7ĘÄaáçnÂřy{‚đ÷¦]“ř–D!Đ–şŰ}Mąy·÷~ϰő蜎đą5˝ÂcŢŃĘຸľýIÜö÷đńb2uuÍ®żýű -čšX÷k¨×l˘ ÍaŢŘ®VU…8Ž;…Ľ_÷ööQ–fóRH ™•‘ÁÂĚE‘C)…$IqóćM_ŘŰLöŠÝÉ„˙ú»yP­5ʢ„RvuˇŞšĽXzÝľźD‚Cľe­ Ľ˙âÁÇźŕűw˙'NOO1ťNQ%Ş˛ÂŢá!ŽďŢÁüb†$MPW˛l€Ĺ|Ž(I°^.!ŁggŤ'ŽÇXÍćŚG¸ű˝ű(ÝŞa<ťâôŐ nÝą‹gOž JS$iŠ×/O Ą„aB^”_\X©§îyj$s‚!ŁČů9žh§j!EđďćqÚF˘ÖÚMăÂ1ńÇĆÔßÉ}<ĽŹP‘b­†-˘!zr@d˝0¨­ŽMŞśŘÝí58Žóˇµ=jç]6Ro»p?ípÝk üŔś«3ů‡ënŻaa‘u¦-¨€«ť VY EŻDÓŽ‚Ďť,q_ěß}“*Đĺ°o¤Śo w!ďq^0.kşŹ6ĽÉđ ü]čâup}űŁß†Ă U]ş.›¨_ô Ń›ÄBřźI {önBaó=„,˰Z-ý”V9†ĂQ·Sb…ÁŚ$Ée03T]Ł,K‡@ŚF#)íŔdZŹöps ‰“/ě×~Ýť˝'Q‘GJă$F6@F1”R¨Ş F+kcÂĆ«97»ˇLĚO}Ž?űó?ÇËç/°^-đúĹ ěîc˝^a1»Ŕë—%ęŞBžç8şyĂ"JygÂĺbm HDxýę5Š5łňŐ $ʲBUVxňčN^ľÄ­ă[6Hhe¶ϟۀť4i€]á·…Á¦ĂَwňÓqŤXJ0 “Ä1ʕ֑ dw „ßp(€Ţ‰$©}ź‰`ŐŕFŰ!íď(¤kfÝž×ýl)„[/Ů(掞?@8¸@dŘ„4ďarŚą`˝Đ¬.'˛o›úÝ; ‘íŠ~ĎĐŁnÝń·•Ď#h˘ů‘ßÁť@±ÂááîÜľ‡ýý)Fdl-—ëşĆ|6ĂĎBkÝEî{{wî5GÝbO›#yÓK`:™ŕđđ·ŹoŰ×ÇĄŠHŘЦ$Aś¦(Š~ťŹĐŞü+śöżIÁëŕ;v3Ć ’Rë“~©äťF ”†É|v=ĐB˙Ö45˛źmŠ˘ôdĢ(eYŰ=skŐÉŤ+Űzś¦H) ¦LŢ#rzSüĄÄ«ç'Pµ~ëFAđmq˙.śÉ~ŇŚ˘BJ[”Ű1Çyׇ˛§~¶Vąö€.‹żůőŻmľ˝îŕüüsmđůĎPU•'µ-fsÍ­Ő.‘sHňu)Ć(,+čZů¦Şqícf(c0Ź±Í‘ 2@HĚgL'ŕŃŘ™÷ŮUF±/(‚l ôÁᔪ?Æ ŤÇChĂŹÇH3«>€3˙‰ă8Č®0˘oU!¤źrŤÖHâQlýZÓŃmb…°<é‚üíŞ®á`ĂPJˇ(+(­@š»¸*čćb„žáj#¬pfŰÔI[őü"t čűîo…ű·5"@Ćú…żżŰG+…ŔŻţňŻp°ŕŃ(rĆN¶iK0™LđţŕĺË—ř˙óß#±W;Ŕ“%·@÷áu±ˇ"jR5~őWżÂűᅬ4IíőÍěăž eß˙őă˙şYp·6Jďvř¦Ż€ďŘMńx€ZŐv ÂÂ@ -™ź-ôŹÎß[—At¬z›C3I(esĺí¬‘ç9Á†ÜŽŘŘÂçHcÔHvu Ť8T&ą&ĺŐó×(ňŇ%Č}qďm/ěMŻqö`U+¬— @HŁ`4‡qű'ď”îI›ç‹N ‚†dÂű?úVëţçżůwřĂďŹücüß˙ţoqtóŽŽxüŕ3ÜşsĆ0˛A†‹Ós0RJÜľ{gŻ^#JbÜĽq Ĺ:‡L" CyŞ*°ż€O>ţű‡‡xňůcüŕñx€§Źž`˙đpŻŻVëuŽ[Ç·đčá#¬V |ř“źŕţűďc˙póó9>úÝďqóčg ÄiŚ8I‘ R÷ľHł‚„ ˙a@ĂŽc #é ˝„qëEĐF!NbD2‚‘gᇆ@qdď_mŚ•5:“A’¶•E…J)®„ˇE˘5K=ßď¬nŢalHóýÔżîoj<őüö»;~_ř±­đŁ»Ű‡}ýÍ˙ň×HŇĚp·ÎÍúĄAi<˙ţł~˙ŃÇ’6…!ÂHŰ‹ý¶8ä;wnc0ŘHçf…c ą@31áłĎBă8 ˝ĽďűíĚľj•Đup}űÚnŕřÖ-<{~‚ă›7í|Řń¶Đľč©Ţdúě¨;¨÷ľÇŢĎh4ÄjµjˇVٱZ­0 ;hC´á%ntŘl0¨3 µ{ŕůÓkÓĘŚ71}ľzŹ\3ŔT•Sĺhđ¦uDh`JžV6OÉÁÔ.™®Č׸{˙>^>}ŠńdŚóóSÜşsBĚ.ÎńŢţ>nß»ç&ö)T­°wp śż>Ĺěâ7Žoáĺó0¬1;żŔôđ“éŻ^ľB’Úb;›ĎP•ęRáüě wîÝ…ŃÓ}+»Ľqó&ž=y‚éŢ ÎÎNQŐ%–‹%N_żöEp˝Xc6»€ŇeY˘\`v‘ĂnzĎóÜ…âÝ[@H« ăQ$P+Ťş¬ ĄDY•¨kŤČyoŔĎĄ´9$lsŃŘ&Ŕ^µ˛fJť÷;5’A‚ 7Ćęş>Ťßq?'Ü QŹ$ř6»ţ^ý$Ţ(ęÜěř7:SÚܸëH)űË‹l0ô!K˘É]Ô>·D^•CDřËżřNNN0źÍľ†{ŃŔâMmłżTkĄđÓźţÔŻ’š&ÄÁlBŮZRţč±#7Ę ü¤›u'Ó”Ż4ᓯ€ďčmo:ÁÇx€»·o{&x·Řoţ»!óő 9ő4Öíj€Ľóŕ&A\0ÂjµjĄb`,—K$I‚,KÝ›˙ź˝7‹±äJĎÄľ˙ś7îÍ­˛–¬˝Čb±¸oÍnuS­­g$Ť–‘4’mÂcx ŔŁáŃóć0úÁo~ö lĎČŁ™öH°F¶g4’Z­n‘­V7ŮÜ‹¬˝*+«2łrży—8‹Î'nŢ$YĹ*6ÉÎ ¬Üî˙˙˙·ůTś<Ö`ůşćŔć h0ÎŃÝěbmm+ěűL ™ŹÂŰ-˛Ü 3FPÚ˝FżŁÔ´Ă=ŐŚH˘|Qaî 7иy}7o,‰ qŇA26!qaţFsĆňú6m‚‡K»ŐÝő $­ këëwQ…»o…«W/Ăso˝ĽĽď>#ídŹÚŞ*QI‰kW®ŕ捛‚CiF·–Wlzáp©>‚Gp&Öň{zƸ-ňÜÂŃJ)dY†˘(A¬¬{¸·ëeŔXD@k¸•…'Žůýüđ?Őä¶xŤA˙ţ<14¦č™&˝©q†đHl\ŤŠŕţĆĎ›ŤA`ő»ŤĂ=ţÂď™sűföáČá9»zqh …&€‚2@ŚAÁŕç~ögńýáżE–Ąo1ń}<ą;)ÂÔĚĎ͡?€ű Hk?M˘ŻľöZP˙ě<M8˙i·ő}š€»6ŰkönźÄ›”™“yI©#·ż8˘B>úljaý7hÜçč: Óé`{{JigdĂmĽD0KÓh5GÓLóʱÝícksŰ?Şb¶áPZ‡ –űŰŃďfpN!ÖT"Z_0·âĐŃűç•čĚ`wäSűf°˛Ľ i4 5 wÎ5Rë;yŚÚé.Ap‘$"q»V OËSŽÍÍ.Čň<Ż'2›Ó Ű*%!%ł Á  ĽRŢ`d#{ą„Öb*ň `uqŤČ}ĤdÁ Ň.+@‚iÍ\qĐuÓ˛´-ň–¤¨÷ëłęÇG¤‹«ĺ~~%ÖHŐDŤ$4¦ÝĐ; j!ö”b‘•đHq•á5¦ţŮ?Ę=‰&ďÝ żűOi…łg¶\EΧ Jîřţ}„3űŕBaŞŐÂC§Ď`ţĆüôŞyŇFűşFv¸ý%Ą4žzâ hm ¸ç,pR1(R``XZZĆúúŹ< i\Lň^ŕ^°w1GŹĆňíŰŘ?{ ś 9ţHˇż3čtť0J(´MĎöît: ĂÂvëîz˝8gHÓś‹Cn/¬¤”(†%†Ă"b|—®!¸ŤkŐń”ő±wôľa±M‰VŠ©P4ôOMöżOV´¤±ČŁRJLNNaui9ÚqĆ®u°gě˘Xín9ëłŇ}Á.ËÄ*.AĆ ’•UQiíŤMȲ˛D=Â! ÚAi+Ăr$C)%¤”PJY¤GšFi+‰3äVc®ÓŃÔJQřŚ­ľÚ6 ‘&Ýł˝kä§f}‡xj_ şäáůŕ,űF8ż‚ş Łč|aŤÉ?ŠC€ČÄĹŢDę6Ú‘ÁŕM0Î˙?Ş‘»Ný#?Đîp˙.!Ś19rÄr#śÍ3çišbuuU%Ńn·p`˙Ah­˛Â‡ĐD„/żđţĹ˙yÉĆWŹýF“´«-"8ç8{ć¬s”4ŕŚC¸$IM:¬w^{ă „GÍ­3¶éôćH>i<ďáŢ__cŃ^ŕŢíw;x`WŻßŔˇ‡ăśĆBűMÉß8‰ ŤHcčT)Đ,Ľ±\/MÁŃď9Đ„ż7Ć`8Bigˇkt]˘˝ż•oąÉÚ%f­śśâÁ|Ü'vÍľ”0Şq}ăŕU8Ćs»í@x"°¶˛ęśŃt(Q­qDÁ ‰jĄČúŐhĄ„Ů2†–…ďÔRV(«˝^?\„Ť6¨¸„ŕ qä1‚ÖUU˘Ş\ö€Ň0F‡őMśjĘLýś9ۤ`¦3bVŐŔUXíîç.ô&J뫉x®Ń2>!Đż€|Eś"ćȧћJő¦™0X7±#¦Fg׬AĚ7±1ŤüiĚĎ›Sŕîŕ4˝Ć$¸pnnÎ_ś1ŽDĽőö[xçÜ9§°Ç"<űěłřÜsĎAU ‚shn€©é'ŽÇŇҲ#búĎ›Ť4ă{em4žyúi§(ávĹÄ9xbŤł´Ň AxýÍ7¬[%c»¬ŕ\ăč<BóöA«şŹpŤîž8Ľ×ěÝîëäď/ J*´Ű9´ŇnźL͵÷)ä;Ýţv‡ţĂćc«şxű‹Y§ÓFU)”E­Ë`LäEć ¤'öhSŁÚ5IŇç< ĆµŐ˝'ö݆Ő@ă/ď#4í wo3"ëŁQö˙O€!Ú h­qŕŔţ°ďO“ßú«oaůöíš`57Żţđ‡¸|ĺ*ţÓßüM‘¸Ő›ýů3O?Ť˙˙ÉĆe´ńp\÷Zd)ńÜ3ĎÚ3ČX©«`<¨ý>Ţ}ď˝Fęç‡Câčž^SÇ źÎŰ+‹?>7ŠŇ €‡zWçŻs¶ ôO»¸ý5'›8;ąŤűÚ~ż˙ö˙ö»n­έÝěÄÄ$˛Ě9˙vޓ܌˙€`i–˘ÓiŁĺvÓÚDp7™;>±ĂcDN^w}b;ňźŻľLpđ4qZę I–"M„ýš" ’4<¸ßŮ„µ Č>7‚%ű‘o´M–í L͢‡EP´QĐ0¶`;Mµ†VZIHĄ‚ő0#›±@ś»,&’4CÖĘŃĘs¤Y‘&Öc‚s×đ(ĺîŰĐtřŮÝ4í÷›~d•!AŃES\äŁęFQöę b..b˛_Dä´ǢçkbŔb"¤Ăkđź ’ Ž?‚Ůeůďh ĐăĂŘ©Śo@ě†gâXŢ:đfjr‚[¸}~~KËËuüń„Î9ÇÖÖ&ţđ˙ţ#¤Yj˙NpĆńř㏑_o ęustdđ äłgFž· 8łÜwě ž€3ŽVÖÂKßý.Ň$Ů™ő=Őüšę5ÄG(ôţş˙ÓHÜC~ڦţŃwLhĆ(ę|4·?Ś(Făc}˝ŮůoÄČ€=Y!ŔGć/ZC)GŁó4gÇ0Ćv_ \b|Óđ>ďĎ=Ńř҇ű‘MŢëLN€qníA(•²©Ą„66QŻ !9GÖĘĐÎŰŕÂéŰ}îśgŻ3j"Éť'Ź5v©g@–¦(Ę"şŇ4E«“ŁżÝÇ‘ŁÇć;žî™˙JJKŔóN}i 31…,•0ZAjŤN§ŤN»c‘ŁÝçfť¤T`\E!U ĆTuÁfl„7WďÜkľ]ÄĐŹ,ý÷Ť{­abo|ľT[bǸ 0#LP3j¸±^·ťz÷†§`ýąqQxďůÓŕ@Ú9ŢĹ\ń÷hô ¶ĄŃÚrr¸‹…ţᯠľűÁěőő |˙•Wđągž káńÇĹą÷Ţ­ ľ˘)ßc\Ł(PYřâľ ëýaU&ľąĽvýVÖV­*`LłŤČJ:~Źé#ţźE)ŕ^đ/üڱ]wŐZkĚľîޞغŐúç9{ŕ¦g¦‘f)’$ ş~.„cČ+¨JbĐ루 (©p`v?  /Q3iŔ¨©đ;Pg¨D&šNQ›ľY˘%w:o,ĎŔ8G{b“S“Đd×JĘŕg\íRRÚ&@ho7¬í'DÜľ¶‡˘ÓîX67#epôčq'đźř˘u4Ú9ĽYÔÂOYR[MľÖ J;”B»%ĄPiUąźyXźqhűaVל">ü1SľN ¤†©Ź!j1‹şXµÉbĄÁĂźv¸÷Ť®FwEŘ%x ä?F÷ß ůß`=ć®&Ăî[ívLt»[N–›í‚¤»ýŠ!ăřÁ+Żŕ‰ÇC»•eĹcŹ=Š7ß~ "I‚\”Ôť÷{đŔ;z ĂáĐ6„Ú®)ąŕŕNúůť—_Ţ]ö7îm3ŃŠć.PŔ݆¨˝`ďö‰źřw;p‰í<Ç`8çÜNÖa"¦ĐSňCü) ; ‚~Źß(đ&V4Ł<ëÝż—Ĺéú>Č›äÚ(ň0äĂ?Lhŕ/ä0?âNŢ>kĺ«”BÉ%§F!·ŃżeU@»řC˙MNOa8,`ŚvŢő5ŮŔ1 ©†Xí…×Ű*1fš`Ä”ç㉠IDATJ«ŞD+ĎÁybÉ™ÚE3–b6ÄHkh'«ó±Ĺa§®Mŕ hcŔچVΊX+CĐJB$) €ŁŇĂBş`-MEýa’O˛Ĺp©íšŁR•VčžCʤҲ‚¬”Ş \ą`"Î`Ä\¨qĽë'‚&‚LôB/ŁĆ " 1¬iďŰŹ-ţŔ ťÚţ±ŁÁ·ü-ü>¦:˘¦Ŕ •&BŕęŐë;'ěFágPaĄ^úîwń«żôËö#ŕ±Gµ\"Š#Ĺ?˛ď”Jâ…/˝`ĺş‚´ó—PV¤ ţúĺ—GĄ± ‰ĂĆ©±Ű*âÇ÷¶×|ĆnwÚ©*ĄpćÁS¸>'ŽkěüwJţĆĹ×ÓSý7Ł&A¨ŮůጫŮÄXďŘčŽ&z;;kOä3Tsü߸ůZÇfA®a0qy4?t׸žkc+‹ťĂ™q)€öŮ[—:¸ÉX5ŕpĆʵ·‰„1ÍçŮ“‰Č“!‰n¤·:MnscÝf4€QiŁ+­”“f%łSK Ą•#\FćÄöD.†Ô¬wT'ÜGĆ}¶ůŁ‘ĆďAFÖ>3†s$ ‡`„Ś1ôňÎ0yô8¸'’ý1çS`©ĘŇĘK%QU¤”¨¤„[“ ăöáĚAçˇmŤů ± ˛röĄw4Öyg°cß±üi™Ťvůb‡[ EE" Ŕ@sçĎ#Ë2ĽńÖ›u‘ÝQřÇěщđĂ×^ĂoýĆo ¬*0"pĆńČŮł¸rőjóĽ‹=»Ł ăź{öY7ý´[ë%භ?čăő7Ţ@–fŘ‘<)ôŚŕSÝ@np‡hŔÝcÍáfŻŘ»Ýçâ73ŃicXŕć÷ÁnëöWŁŁĐ?"ăí.xşFFN}/.ôA5@./= u€Ž1¦†üŁű3úŢśÔwö>GĘr˙z8§yŢAÖnÁ0fg1#ť>‡6˛,ŃďŮpîvó˝î6D’‚Q=mŰúˇ]ł`‚Ăź‘Ę)!LP s¦F‰±ÍUUU ÎĐÝX1 ý4 ŠŁxĆk»ÝĐr[ś÷&=,ČîőŮ-„;ľŚĐÝ8mÔN;)ż×U‰°żcň@-€84s•’3 ;L÷ú¨˛Ązy ’1dJâP·Cš¦¶9ŕľűŘbËš¨¤D»“c˛Ý†R •ă<ôűNĂŚa&=…™!Ę0»cÔ»’ýh €EĹctýc€…čxlö őßq.đć[oŰß ÝƸ¿S>č›Ó /áĚC…>ţčc¸xé„Oâ Eź9/r˝±Á—ľřEh­­ŃhFĐŠAČZ9ţôĎţi–5aŻ‘ĆÇ4ľéĐ­Źčő!Ż ďÇ#ÚkönKáż›NiŤ'9‹·Ţ=ŹGÎ<Ś8´ćNÝţvÂęMčż ďS]¨]—ŕwřÍî9şŹĆ>ßÔиź:Ă×ń…@;_|¤®?~NöbbüóŐu ‘ŃľőąVEx_´6Á]ÍhŤJJô¶·­–^)hCŘŘ\Ă#‡ź@Q pŕŕ!h­±|k ×çńř3Oakł‹á``c·ű˛˛ţţʲţÉç DO?ńge UU ßďŁ×ëą :Źŕx‹F07Šúű‰ó(ş{›XkYl_ĺíĺ%0!¬UŻŃôŔĂĆć&’¬˘„-ÁЦV2Ć\ÂŔ…€˝ŮhÎÁ48\”űf ''`8) ^)Ą°-8Ňč ‡Č‡¸›ĆYWő¦ RnŇ'› &)&;ťĐÜ2nÍŚ¦§fk@ Ą-rĄ‚…°-ü:XZ;Ă%© üšÄ!WÚŐÍs˝–iŠXhGď0ć‹ĆŻj­ĂĘE«ŃźŹoLÜÓ« ŚŢíč_ŚŐăáÍ·ŢÄăŹ>f_ 9{Ă?"o·›Ó˙/ˇ?ŕ§ňË6ÝĚYYó —˝>×oĚŁĺ‰Ţď¤#ŔóZĂ( eŕ|7t >Ü!ŕÓĽ×|‹˙G9ŕüßNLä Č[Y÷t·ż]˙#j€XóŹÚ» Úpż ý;Ž@ýSÔ_7‹^hÜąđî'űüÁĐÎsäy†V޶»I‚Ş*1rdFŚY^€Ź/6Ć]sÚťŽĄ:J…ÉÉ”®Đét0;;‹v§Ťőµ5=qFkdY 'NÍ`0ŘX]c‹ożŰ ;Ů`Io"â—#żĄYŠáP (KĚěŰgwěŢŠ—±Úö•E¦;öćĽáöóĆďě 0==)« 0R"M30"äí,Ik }dřŁa •„RöoP%hUHPLuP&)’$ÁŕÔIhÎB¬Ż!ÚżÓ˝.:·WÁÓ¸ČŔ}N‚?fYÓđ*x :v:ËZRY¦!¨ ś‰H0—çą ŚąĆŢź6•2Č˙ä× ›˝VÖ×±ąµƬ˙ţÄÔ8ą÷ŘŤÚö'°]~FZăرă †v§ZŹ0ö¨Ţá_0¦hFDR­5&''ŃívŃë °˙~ĺd‡çŽŕé§ź~ßsČÇćpüčQešl»V˛Źűť—_ÂăŹ>†¤AţŁZ^Űče¬•đáĂsPR9TLC“ťN­Ĺ`¸«kÂgE°×ěÝÂíˇŔ~ř:ž}ę©Ő{·nő´\ĂóvŻßD“ľ­ÜQÓ`"î@±ĹÁ»6÷÷¦i˝ë‰t—ŢÝťŕ%5ú‘"ô‘ČJU@šŮâă|ń 3ŽŰ 1, TU‰Dd­@ EUa8`scŻýŕűÖÁXŻvĺ>«•Ű+női/śD6˙ ?č;çćî™Á+:ČÁô ó7ćmś{›ó€çNŽÍ8§®Lś;xŽ:#‡ÎAŇý#(YY™!cÖ"¸*±8ĂV· &’P,íűÍÁ‘ŽŚ[/p$ PČ4X!@ZŁjçÖÓ ’öw”ŞÝŤFź86§§‘]Ľ^”F“·ąuţNĂ^{ 4]ö¶ąpżZ+·(ÜgŮLĚÓä‡{Ď­ŮŇßů‰/!mĄŕŽś¸x{ ›˝>®\»ŽĺµU,Ţ^Áâíe ‹Âůŕó 4áďÚř©”B'ĎqůĘĺ÷—ő…oł÷;¬w´ ĆhLOOcsseYâÂĄ‹.m” ˇ!„Ŕ;çÎír*Uá'ž˙¶ş][ô Äž‡ţÍob«»… .Z#Ş÷{ÍîÜUZa鱳PŇrS´¶ĎŁŰëáýNçqčžÉŮKÜ»}˘ ˙{q“RâńGĎâ˝ qöĚiwĐ߹۟n; 4F ěśÖÇóúw"Ň1ýG\€¸‰pŢş?„çvČ>D& $Ś…PĆ ŚÍ6¨$ńđ^s‡×pie`”D’¦ŕśajjRĚ>„ţ ŔúĘ2´6H’<čLtŔ9GUČň­vŽőµu0"´Űű˝"‚>qüâ% +é~G:B¤őŠdŚ N,Úîç­/ŕ{ĽA.‹gf uv+žĘŐű÷íĂ‘ĂGpúÄńđśqt··qcq ‹‹¸ąĽŚ…Ĺ%Ü\^BUIg¸ăň10˘ jHíŚ1¶‰pQČă€Ř/`'¬n¨ö•ńă)ΑµZ¸pé"N;Ä8O=ńŢ9wÎ~Ćq:RtžüÄ>" •V`Ú*V†ßţëżĆç?÷Ľ“ŠĆÓÝń"Ô‘1Ă4ڱŹË\SűA×ŐŃußž pďöcŃPdiŠÉÉ6·¶0595ÇÓ.Đ?špż‰;ęřëH˘C˙^ÂIţŚ·.h®šŤC|S ęčjńŁ‚đ|Ł« ý~‰¬Ü®ś[Ʋ6f¶E˘,KSвrXČpŹĚář‰PFŁ»±ĂÇŽâÖÂňS'ŃĘZŘŢîbfvIš˘×íbv˙,–n-ˇ, śc‡Hí<,á1î­‡Q“ë´#"N¶G2:2  ¦Ý‰¬‚)¨@XŁÜÖ~±+"E’EkmP@±#`”hȢť?1Ö(RÚí˙Sm°ÝßF’ĺPÚXż{I*MßÜHĽŚr#ýşÂF5*HXČţ™ĚÎLăsOú§Fs0Îíoúo¸ýč?BŚiz 2 ¦A–­ćů»~˙˝ąŤŃŽŘç§_đA’Űź3faŃ <óÜçđę÷żŹ$I°µŐĹöö6´Ń¶(ŔiÁy°.J;E–’ ¸ăÖ·]*i×îs"ë+%a”5 śĂzŐá^ű>>ĆĽ‘»éz«‹Ö±ŁhePVVßľ˝ płoČůIéşhi h¶p ˛Ű…p–Éś3§`Vé+!Śy/±mÓʶ†žĂďQüu: -¦ ˝c'ĎČ„tĹŠő}9ëäAQ„‚·n%I@»Çl9°Ç‘&(Ëg¨JënŘÎs” *»đˇ© }ÁQ>xĘ68[]đµ ű'Ý.¤Ŕľ@$€”¨±˛ŠÁÁý@–úČ×7AJ´‹|Áđjt—ďľLŘuăŽ*`\ ˛BQ•€¤@bŚ Á„EĽAëu˛48s~ &ů€uDűlréŽ,ÜLô|-JfwlĂWŰvW˛‚R•®ě @VČŇÔŽf'‹ FăüMiU”€N?އŽĂŻüôOCiŕĘÂ<.9„`ł×CYUČ’äś%ĎťĎ=óLhÜ:ý n,,:íľđüóŘÜÚrŹ(ç ţ×ßű]äyŢ(řŤÎ‚ŃxĎDÍS\ôŠłW{ö€Ńíß0xńĹşŘü›ß˙cÎ&&Îcţ3mżn”ţB%Ś6Ćźńś3Á©•·Đi·059V+#ă|­ů}+üăň¦¦&Á7ß~O?ů„“ëÄa<ć>¸ýŤŰ˝™“rá+ŃcçG04®¸~¬ž‰ćş(%Ź!K30aÓô„+,JyN€••‘eţ ĽÝĆÄÄD’ I¤Y†ŰKK(‹kktŞ€\´°µ± ­7ŔáÖü ĚŘŹŐ•ô{=lmn9›Ak»VXć i’˘?@+ Ă›?| ž&"pÜëÓ“41€R–h3ŕ-i‘/l­TdY†4MÁ™uIY+Ż*$iΧÄc7br‡°:› ˝r$,j`©Ö¨zŰ`Ă căĐű÷AĂôŤE0َ:mTs‡@R![Yőł¸ó ¨Ő$u1ˇ€'S@ašRN#0ç„ ‚qFYRkhUÇižă_˙˙'ŹǡŮY݇Ůéi´Ň,\¸/ ¦g( LŠ×KÔ”÷yď$„V«…ÉÉ TUe­vµ†–n}ŔŚE–âstç…ˇÁçVÖÂčřá#8yä~ţ'ż„4IđÖů‹¸pí:Î_˝ŠíŐŢy÷]|ńůĎ#Ż3§Ď`~~˙—˙ОwrQbŔ·˙ú%,,ܲkc‚ř"ä…ň>"lÄ›´›\Ě@tgĐ˙Gđî$7dŻřĚýoŕĹ_Ľř"áô§)‘řĽ!üçZ©_••<ídlĆĂBpJ<ĎĐé´19ŃA’Zç±Á`•ĺ ¬¬mâç~úyÜŹăęŻÚ­NťzäRÎpčŔšÝ‡ýłł803,Ma`-cjwĚF."çż ŐŤvZۡ­,kÔżJJ”.pĘY»ŕ‘âeę<ϰ¤DUÚż{đŘQ±ď W J,,AÖüG»Ď•<µS,3,DDzÍǰ(°rű6ŘĘ 3h©í®ź ¬®¬"ŮÚBYT(†CTE‰Ş(±¸Ľh ŠIu~átý*רŠŇ‘üęLĄ4Ş˛DŻŰ·Đ~<‡1ůŔş\Ž'˛yEŔpX`°ÝK8ă0ĐČö A%×ÎZšŮâ¦tĂqĐ6ĽÔäśDφ +éÜ„ís0`ŕ7o˘4c•3źńÄ.wNUvwo  ¤÷»0 Í?i—J@µy˙~X°ÚÂ5dňÔpn¸şű3ÚX"Ą“ QóXZ]ĂâĘ Ş7,1‘3†łł8|`‡Ä‘5H„€4JŮŐ퇍ăĹş¬ßşŠ†Tdeł'ňV†Z˘Q”ĄEG´3îsŹ98Śx]Šr˘Z’#6ßř“˙ŔäOh-˙±.ń[ƨäBö˘ÉŔ‰(I·Ďď o·@Ć`0čcińÖ76±±µ…Á €¬”cóďa†±ŹÔżľßž˙N›€ÇŽ˘ßŕŐ×ßŔĂťvYÝ‘f˙ÜţFˇ˙±nŢ šîcčäŹĆş°Űŕţ%îöŢ;R8ăČÚm»G×6MŤĽ˝¬©‹Ą”PŽ@—ĺ– ×í"Ë[HY‘pTE‰©}Óvşć‹7QUÖio@Cll¬NĎ&Źf+G3z§;,ó~Ú@© dę0‚źvmŰ\ĘJI@(ś¬¬°Óî »˝Bi´Včô‡`ô¶{`®Hx/í>) Ǩ7žRď'sCŃż J×l!5ľ aŢI0Şv>w€"HßĘY Ü ťÉżçx˘ťv×´ĚŽžĆ+Ů,a’ŐőEŃĘîőů?&ŕör-D}śv=l]ëáť+W-Q웚ÄŃCqěđŽšĂÜţYł2L0»ę°Ç …óÍDy&Hz)ÔVĆ;Żí7¤’(KiU!ábl·k` ˇ[ëëŘwđ`‘rh Ě? Ť4IĐÎ[ř›żú&ľüěsx÷Ęlm÷‘& 3Î0¨ąćOŚĆ@±5ŔňŕGńţ˙,J÷€;Ľýîďţ.ľúŐŻţů˙ř÷qŕ…˙~N–Ăd´ůmiĘ']°‰ń#F\tÚ&§&0ŮÎaŚAŻżŤ…·±±±…őÍ- úHĄl‡îeDÁ™ÜN…š1˙zżöüwzËóž}ęI\ľrE)ńČ™ÓPf4čÇěô3ę0:}F ĐH´+¬Q*!Đ|¨}Ýý8±wîíDěĄWvä`\G{˛Ç„6 (wÁ-mş‚6he-ěź;„Ĺ…$i†É©IĹĐyŘw§ßŰáB±msěTç Vś1(ĆÎ˙ź3Ž4I·rKZŚöŕÄ(4cΩeQB 4”ެÓ0ĘNĄJJ+ťÓv˛”.@J 㬣ɛ\s¤ 2đ´#Ţ!Zë|§•4‘®ŮđÄ «â÷Ó 1€´k*üąę!şfS-¤ČÄ'ČßCXAFŁÇRXRĹ ŤłŞôĹźb¸€šGa$dČÂ÷‰eöK­pőć-\šżJJk5;#âóĎ<¦ÎÎ@»Đ!í=H×EßlăsĐ#l p&ĐĘť91(ŞR* HĄ‘Žb„Ťő5Ě8čZ…ÓŹ>nWRĂÁĘň2LYâňüÚW~Ë«kxçŇeĽqţnŻŻ["ăŽŰ‡ŕŹĆř•îĄîÝđŐŻ~˙ń›ßη·ŐŻjŁ˙ëŞü˘;sŽV–˘ÓÉ1=5Bo°Ťůůy¬¬­c}cýţŔÚu:™ź—Y’á–É ÷Í9 1(7wÝŻ=˙Ý4J)ś:yRJĽńÎ9웞ĆńcG!ŤtĐ˙înáĚ}LŁ@Źřř‚nF‚˘FŁůXµľŮk†óqwň”É5ň^–%zÝ-Te ‚éöí>zÖăB\lă¤P TeF …˘Ď»čw·Q)h »ą b ýŢÚůě÷{v˛6‘)Š#ň×ö˛Ú†srÚq75BCÉ UQ`(“9řW8dÝhe*¨Ş„¬TŘk'™“Ň*Č.Ý­‹ŞŞ”\“ĽěĘË;$Ú'ŻQaíCy `«˘``aň·§¤ «ë\¨ý`ÍęćŰý>…bćIŤľ9÷‘Č ă8‰6‰‚…v†ëˇö:Çw+ ^#2MÓí¬%3‹ ¦ö‡ś[•†7Üé Ľ{ĺ*$1Ľ}î’4ĹÜţ}81w'ŹÁ‰ą9pÁ-ďĂ˝Ć@4tE_G‘iíB*ű_f‰ťCż. ‚3lą`&m LUáôŮGˇ‘‹o˝ú}pÁ­ëá`‰NŽ/=ó~ćůĎa­»…7Ď_ÄkçŢEQV ‡Ă—ŻŚg*R˝Ť/¦»ßě5?.·ßůťßÁ׾ö5Ŕß|ë¶Řď>k”ţ'Ű]ů"ČLňf1n :ÚyÓÓHŽAżŹ[7obem ««kŘŢî;cYó¬eĆmŃçÂ}Í`¸°y猸ýO©ť–{˝çżŰçĎ<ů8¶¶şxóíw03=ŤcGŽŘ‹ËąýE«&Z 43Ć@˙ńĎsFC ţ#ęä¬_řőßţm)‘$˘.&ľ0 v36~l€$MP…+,:ŔČ^IĚî·ĎHű^ĂÂ…ĚP臓ęďĐh\qV I’Ř "gă‹5Ś&€Á6¨–´í %1Đ.ń=śÁŹßą·Ú- äďáď¤= ŕĚ#Řçfla÷y őTNŇ>rÎo®p {ĆWuÇů2Ě˝ó:R¦řU‹V`Ţz9Ŕ}!& M3+‹`Ŕă×6JIđ$`\5{ٶ>”‚âśűš\Peâ ™1†đZ¤YЉvŚslvűX߼€Ľó”6Ř?=Ť‡çBC0‘çÚ+"ěgl?k]KpëľÜGŽ„ŘĘŇĺ**ôş[ö8¨Ş0”çcríŇyˇ˝F>­ şD«ŐÂź~ _~ît:řy o_ąŚŰk¨Ł—-ßĂ7'“!Ă5%6{úHŕŔńöd€źŇŰ׾ö5|ó/ľ×Ůčő˙‹›[˙ €ç8#€S$é&đ„ŁŐĘ0=9‰‰e1Äęęm,ßľŤ••5lmu-ÜëŢČj—á%KÜĆšç0ś»€Ăb"m!mç¸rĺ"ľőÍ?Ç?ýÍźEŐ|¨‰˙ăÜYů ˇN§Ťgź~›[xëÜ»čt:8qěH˝ô>& î0˙ń„Ç‘ŇA×ßČ 0cxq3aîÍI}GďŁs·őâ7őĽô2Ň4AžçHł4 0†l40<ĂÜ"iLNNakkÓCÂÔ̤Mć+ 0.¤ ˛,ÁÂő›ŘŢÚ‚ÔI"¦™µ±uÁäyî=SŇît[­'¤‰ŐŁWÚ5–‘']̲V0"G`+ËÚç@!IŹ1+”•Ääô676Á^pމö˝éŻ.Z(›ŕ&QËNç.čÇ …ăÚÇ'»EŐ+nwN›ç Žq‰rn*ä>u°ţťŕ75Ś´ë‹\1ômd@>¸HŃžšDŃݶ°ëŃčÝFŁJ ®@c5d…ţbžŽ‰tÔh+ckśQ}Ý Ř×â_3çĚ%KEUâüµëxűŇ%TJcŞÓĆńą9ś<2‡ss™ś˛RFYP R8su#‹Ŕ;IY:t;V€çßzÓ‘5=u# ˙6 Ëł3 ľřě“řŮ/|ëÝmĽyá"~xî=lno#Â5şŢIѸµ vš{\ů? ApŻř„ßâqmxßýÖĺÇJ©ľ¶Ůďý#ΩCÄM”7O‚s$I‚v'Çľ© 3ŘÜÜÂąsW±|{««ÎTEÁŤ´ź„5/q“=„°MO¬üK$Hóš^ő{xýŐŕŤW˙PTHD`đ±Ăýw¶ĐčtđÜÓO ?ŕňŐ«(Ë safzÚBŔ±öߌwúšpěö7ŞhĘŁńÄéŁ#ăv¦Ă§č†ÝőĹR«`kĽ>«}ν˝r–d(úC{o X_­přČlnlAÉm´ň˝ĂÖv˛**Ł .ž Fo×¶±RJĘĆx»_Ď™ó“>śŰ‰°ë ©5„F' ‚¸md©O+Ë+ŕĚš1në8ăŕÜÂíIšBîL¤$4iëlÇpf *ČÂđĚyőűiŰCďĺň9vaĎnM:Ľ—E÷z c[‹Yd˛ RńkĺŠ\ň`\ĺUş*ę meV.%QŽÖ~[tÍźhVęš›rqM@€L„.Ôyq\qýe˝&÷ľ®é`ČpőďúĆ@–űĚŻÝş…K7PUň¬…ŽĆÇŽáÔŃ#hg)J‡Őęrx‰%Ő8ýöÖZ­<¨óc8˙ÖëáŘâĚ9_:FŁ•ń|!X‰âĐTČÓ _|ňIüĚsĎáćíeĽúî{xóÂ%hh$i ÖÁć>üO+AđÇľřËżĽ‚Ż|ĺAŢxĺbviáÚoýŐźť˙o ô“‚@Ě8 ÁZy†©É:ťĂÁ 7o`qqKË·±µŐEQ–îBÉ܉ĺöřÜŮş‚n§{#O!v:(Ę Ż|˙»xőo_Ćĺ7´ÚhµŰśšˇ»ľ÷sú¸ŕţÝhkňŘ#gÁĂÂŇÎ_ľ­4f¦§q`˙~ 3+]‡üD;jŤĎ€nfÄíŻ¶öäCĆ8ŠaqGť˙nRŔ»]ÄOMVŇAÚJY2b´M÷R«‹ŻP–e`î3"\żv Fjgń[ ’%Ým'bPĘCă.c ¸ÚYbśĺÓqűŢ3ĺ ["k\ć"źŤKô# %%ŞŞ 0®1Úń $Ů@‹©đsK30JĂAUĘ=ž-ĚeY@*TJŐü I,\dŠ&™{]µ}ŻPĘh§\pű|ćšEcuÄŻN4Śa d#pu°™ MŹçh Ňĺh//u|Ür0D«Ó†ěv:óŃீ ©‡ń§Mu˘?XĽNÚ!‡Ç’€ "@Öú8Γđ˝1óçÍóç•˝Ö ´—ŕÚâ.ŢX@YUťšÂ©Ł‡ńŔŃc81wČ­†PUá…zEa»ŰEÚj´M'”ý!V151Ą†e ŔzpFA¦šl=‚l¸sbPŘ?=…_|áKř•źú2Ţ˝z Ż˝{ççÁ‰…Ýťń€Ź¬ ú4ü˝`äö•Ż<—ľűéĺ•î?ą|kţźŠ„Ď1b&"I#áÜůff&!8Ăúú:._ľ€ĹĄe¬®¬Ł×ď‡6~ÎmÁw{|¶ŕ $‰$R´:mt··ńę÷^«ß{ ď˝69…¬•cňđQć¶#Eó„¦?‰¤ż€Ď8€Łss`Äp{u×ćQ8Żń‰Î¦&'µr;µićCb&¸ŔšÁeşS¬âöŇFkl÷şŘÜęBĘ y§…ŁGćÜžrü{wż¤€FSĂ‘0ď´S:b§×“J8ť¸چ’ĘM¶*źśśtvÁ)Ęa~ż­tŘYźzđ\ľx Džç¸ą°€ąĂs0¸˝ĽŚă'O`c}RJ¬­®AiU3Řá›ü$I6B×ű9Xć›C_´ćtüFk;qĂ6l5żŔ˘CPZIheQ‚'‰łf4ŇôiŰdh]Ođ±R€Ŕ S»Şđß÷ŤO¬··ź%ëo@aúw+ß(Ť<(!PI—Î裎ÝĎĘ^ŮäŔŚ”ˇ ŹëĂ5˘ÔŔú„ M FŠU]řĆäײć ÜlýÍůéZĹŤýC ěÁ=žŽxhJđ`Ą«yĆŃĘ2”R⽫óxëâeH­0·oŹť>ŤĂűg1·Ö™iG’ú[›Ř·˙€Eh8Ç…wŢňPYwBG&.ĘĘXdAµ«öĎ f„ëře›łŽÁ™“ÇQUŻ_¸)«šhŮ]şłN`4?d/ đÓů˙3?{úoNőűĂ˙numűg)Ď<ÎäĂ%91Ěęö÷ÍLAV%—náĆŤÜşµ„őÍMëś2ą˘Ďܔτń”HŔE¤)ZízýţöĄoáo_ţ6Ö毂ON#me¶¬ľ‡o¤đ$żOjá%"zž€†Ćľ™iĚî› ?ŰŘŘÄúĆnŻ® ’ŇÚÁşĆA¸=·oڱ1•’¨*é T¬«Yž·0»Źř[FiLLt095ŁúčAâĐLĂP#÷É|Ô°ýď­K—ńę{ç‘$>‚ŽÁÉĂs "TeiMy<ާ%D–FŹiď<Âfd0+,+ ©¤ŤĐ­VÚ4ŞÂčk±ML–fxáégpky ©66YjÔĄb”K1ľŕďÉ?c·Ű—_Łż9żůüËoý4Ŕ?Ȭ/ş«†,Ć‘Ą &&;žč ×ŰĆů÷ŢĹÂÍEÜZ\ÂÖV•”V‹ě&}p;é3!Ŕ¸ľč °$KR¤í¤6xĺű/ăű/·Îż 65ŤVžaňđ±úbÄꩦ6)© R8ăŽfŔ?Áĺ8¸“Č8:`‡&''ěűĘj©”P”%†Ă˘.Ö°>őI"ĐJSńš¨[·dYĘ]üÇá‘őI·©q¶I©•˝IcŔ´±xľ y&|ŚĂNÜRş€ă Üľ˝bgűŰ}”–÷Rµ•ĺ««+`śaiq Đ&Hę ´Mí3&컹¨Ę˛~?˘&ŔN¨€R‰sů#«ą‡ťö•TNf©Áś•«6n÷ě\ădYˇ( çĚ(ŞŇz”eᵉLşâĚ ™*;­—Ueeîąhĺ “ Ě"©'ô°Fg,xř›—G°z„ľPpöČbŐ5#€–Úˇ&’äŐMB±ÝE>5ee—Jõ+Öëő¬ĄrT€&&;ŘŢŢE‰í(čÔ@@»,µ‰ŔG8ŻJ+ ôz=pĆ‚'ćî-…ýüőháŹx fäűťvĄ¬PŢ»zo^¸©4ćöÍŕżü‡˙•¬Ŕ ”ʲŽńćĂ#¤,që-‰^€4I˘$C4“GŁ÷DŽaQŔ8Ke­4¤[G}đY{ď®{ Ŕ'ŕváâźŃ»çÓźyůÜú˙Äű©Ľ•Ć!2Äá¶ŇSS´Ű96ÖVńęmá_Z^Ćövß«ŢçÜš·$„ô-ĽĎ’—' ¨đ†R`» ‹¶¸ˇÚ;-†¦´QrF|çýçĺCś"ozżę÷\7Ł5Š~Ůä†ëMGżŃŐ’—˙†ď{{Ŕ›”ë!•5öBŚFQ˘‘"Ť¦(ĐŔć30O~ôë Š)ňîąBÓo(vÚ1µ©©ë·=ç1“p0‘Řăś ś›ĂĘęgČó ĄŇČł–Eů”ŞĄÁAiˇ>i– •ešśDQV€RAµ ű Ä›’ŘĐÉ~^ŇC•>ęµoş¸×ünç_1˙?{olŮuť‡}kźáŽďŢ÷^O H€ÔŠ’LKER’ K5™˘m’*ÉrĹÖ`%ŞD•X–WR±*–ír\«ĄD‰’E1'pa"€‰ŤąŃ@@7zî~ópď=gŻüŘÓÚçś÷úőn‰~Ó˝gŘgݵľő­ďŁ˝Gďů{ĎîŐżź&ôV–3sÜăM’y–b0čŁŰiăřÉcxę©=8pŕŽ?ŐµuhÖV©ÍÍăS“PáŰ źçHZmtCĽş˙EÜwýíxúÁűv­Ný]Ű ?T÷$EA˘Żífŕ H|˙I˝á«ţ7#\vîÝ€ŞA’ÓEĐÎ;.˛6… Ů$5•PlzŘy«…©a ë«+¸řŇ‹qâŘq0kĚn›Ĺ®‹/ÂÂÜ<–—W1 1)&8uüŢő˝ßŤ˘ Ď[Řľs;V–W·r<˙ôsرk'–––íT ?DŮɉöÉL’(dIfl…­÷|1)L« Mýů98<Í2äynÖŻ"$ äY Í0Łb·í?.Ę@É%”ÁÄŚ•pšúÍÝŤó%IŠ˘,`HzÚ·˛˛˛AJ…¤IĘáű€áPť§Šđ”g”íĄĽč’°)‚WT•Ö$)Ď„ňĘ@!"Ż-mŰ"Eč'°ľľ&‹D¬Żăî'žÄŻâęËwăť»wcçěŚq$Ôf­ł—­¶ź­Ý8'Đnµl˛Xb<™ ( cV¤µµaćşń&úů­öż“‚oÚ€™éĆ[ďůŕsGîúwYŞŢ×JóČKÖŤţ´ňAťN GŹÁcŹż„Ż´ä{v†Čg!ţ,E’ćPyŽÄţV yo “ÉÜ/î»ë6¬/-"ď÷Ńß±+@ű˘"RŢźš|‚|•®ŔVüÉżĎ˙&ZGŤŁ~gtŽ~˘‹ĂýŽô H$¶x–BFĚžĽčfϵfĚź:e$t“‡Ffűé‹ó ` ¬®­`}ue©Ńíö°ľ¶†}ĎíE’&h·;Xśź‡R ň¶±‡]^ZeÎË$>€GmXŚrş•˝P»É<Ń­®ˇ5b}~®fT†+ €÷ĽWˇxć¦AJȨč%1V3ä…‚‘_—|‡ý`sxDĂ^ďĂ€ę9‘ĎĄfggńΫ®Âh4 )¦§¦p(Mđâ×đĚK/Ł•e¸j÷exçĺ—açĚ FEaúöVE4v%6Ü’$Qh«:­ÖĆc+kT ÍésTÔs­Ćçsř˛óVü¤oÂŔŹżľőž˝áĆ»ţS’§?ÜÍs·3‘K1b'9†>:í>„‡Ú‡WĽ†ăÇN`}´n˛~• ±Aź’‰…ő“<ĘŰP­˛VÝÁOďy=pľýÔ¨©Úí6¦¶í}Tx QŚ\U˝č)’›_uć"vŽ]ŢpňŤ>°Ő™ý­Ď®ú—4Ŕ´$GĆ(xľŮKdXńÎÝU™u0węYšˇ( ł1–%ćçć0Ź13;ÉhŚőµe¬°Á[YZ‚˘şŻ1. ŚGë†FMěEüLş«ţD cű>“Éş(@ă@¶s‹‚ăɉµu›lŢî`ue *1k[kŤ´oFfWÖ׬‹`bޞâvľNâ§ś IDATDPÚŚŕ•–ç ˙—$FÎ6ăłAˇ,Ë€*ř&şĽAäEcayŠ&TP™¸‚ć0ž§Ö0łű2ŚjäŐ(gWDě †ĘťĽj"ş5L¨°Â(’ I“CÝű…"#¬ĂŕÚ) ˛ZJĹúűö‚›D.hĺüŃÁÚZ¬WÂŁŐnC©‰‚#bĆKŻĆłű_AŢJđŽË.Ăwíľł3CcMly*‰™ ‚ÖäŵÚyäŔdR›m­‘úä$$hJ˘(çôß N€oŠŕţűŕýďß €qŰĽëúďúżł,ý™V/w22d$ ÍͲ ý^Sý.Ž=Ś|ß~ĺŽ;Ž5Ëč7ň©©ń-·đ~’ĺHZ9’Ľ…´ŐFŢíA3đŔ˝wâž;o…. ´:}ń[+RÉÜ—a‘Ü'T@}…FśLĄb˙ŽßXć=ă•ČÄéÔ áĹIRĽ>é”çŘ›ˇ±µ·…±a´>BŻ×Ƕť;0»m‡Ä΋/ÂÜÉS8zř0ZyŽé™ §§‘e™©îÁ§±´°Ľ“ăŕ+°^jY ÉKq6¸°rĂÄĐŢ+Ţ×vëˇ(-‰^n<c9n’fčw;öqňÔqÜsďŁŘż˙Ű8tř(ÖÖ×ÍOLŻPef\Ëôô[HZ-$y Y»Ťîp‡Ŕ=7|{ŞŰC»Ó5Ě+ăĄ|OL¸Ż©*ąOEß<ě§ĹÂU!‹UVGť˙ć*}‡O l$ôsAĎKÚĽŞę(Z@ÎŚ†ěś•¶cˇ Ś´îúú:Ň<.K:xé!ć籲ĽŚ$I±´´Ś#‡Ž`03ĸc4#KSĚÍ͡(tiĽloÖČMřu©T´n•#’)­ ߪ «Ď śa/9Ý~+iL ˛¦C‰¶ćA¶©ËZA— J‚Ľ3ů¶A€ŰŁ,:Ą"(icoţBqa2~ÇĘJ´ó#I^k°c@yŁ!ů{2YwŃß)<*"p’`enÓ—\‚őů…š)‰`#D˘Źĺ“ЉQë{ TěnÂń±í%¸ýÉŤOÂ[SŰóöúCŽÝ|)Čz °@DAĐqÂč¤1’úŔűŢgz˙’DáŔkŻá˛K/EY–VĹŃbačŘ+dY‚,MÁĚxj˙Ëxđ™gđ#?üCH‹WíľÔ8K–%4ëpý!Ó®ÉN«tޤ˝a“Uşb_8w°·€óţşćškđü G:{÷íýť…ą•˙­×ëäÖ.ÄňgĚ O’ťvŽŮŮi,..ŕîÇ‹ű_ĆÁ‡°Ľ˛bzIib‚–AeŇĽ…¤•#ÍÚČÚm$í.şS<ńŘ·pďť_ÇüŃŁČô¶ď23µJ‰jDôí%Ů*îéG›ISfbaɨ¸r|«Ďżud"ÚhŁ1Á×7Łć)ě‰qDv’,Ô÷ŕ]ôĘč@[} …ĺ…e3ň6ářŃcH˛ ‹ Kp¤ą,ĎP”%VWW1­ŰЉ}ĺ–$†Ţév-!Ď̉§Y^] žk_ŮJŤ”pćc'žăúöĘo¬Jˇ6Éâds)<Í> I~x9dŠ{Ë•g&Ěč ĺĽ ˇ6â(ňß1Ţ/ňęŠđ¦:äq¤á E¸»ÄéĹt“Ą%pY˘=śÂŘ©F1*ÖľöGT™ôŁZ ’ÖWQ`“×ÉŹ‹C÷Ţi°NľMŕ‚<+aQ`Ţ„”Qĺ2×Ó\çá` oŰ}9Fă1“RăŰŻľ‚‹wíň¤DĎýđz VÚ[…sQD^[bu4ÁÓĎ>‹űž| W^r ŢuĹn\4;‹Ńdl%‰#-L> -[áüýí±üŽJ®»î:|ôŁ5}ţ[îůČľ—öýqŻŰľH)#×kš…ęĘ[¦‡SŹ=ö(^Řű^9p ‹Ë`;Żl}’,CŇj›ŕßn!kuu{ČÚmcő}D±á˛`ý#ţňgoőůĎ™ř3ép¶ď¶B5Ěu…$%ŻYRˇÖs˛±v“ŐĘ$ł«+«Ö2Xa0č#ow°ë’]8rđ5ĚlŰŽµŐ@ʨ¶Ű3o­ g`zvĄŇe‰™mŰ0?7‡ÁpÇOŕ•—żmx˘_JÉRv˝jÖ~ľß<¶ ®$ÚP6éáÄř`J[×\˛Ł­*ô«)~^|BˇŹ(‚î•ĺĚČă•S}˛L‚Ń‚!w‹äB…ű·ëT¤čG),ź8‰Ţöm-,‚Š1hgBľد‹ EťyPÔc• îw*Î B™o}|r¤*o*[ě”M Už!ÎÁUţĚ`(ĂK±÷]kĆ»żç{ ˛j«űgž{ÝNĄ®x$8%FO6¤ĐV˛ľŢX*Qh·ŚőáSsxůČatóľ÷íoĂ»®¸ÜL~Ąŕ/ÄY˝Nˇ˝Ę#zË đ_˙řÇqíµ×âŁý(n˙棗_ăÝźě´óźÎóĚLô˛ťŇµüť4MĐëv1ôđňţ—°çɧđâKűqâä)č˛(EšŰ oüiŢBÖî ítŃęőŔ¤pďť·áˇ{oe-´;$imnJ5ŚîI_öIŽ Ař’?sŮgősĚ$­ťÍřë» ľáţ ý`ź1îOηţ;g>CzU.‚ܱ˙\&L&cłî¬ ”ÂŽ۱˛¸Ś;w!łf4J%ĆÁŻ(‘f)@Ś•ĺ5¨4ÁÉ'qée—ayqŮČţŞK‹K€cGŽ"M0'ˇőĽ•°^}ĄnÇ'áŞç¸ ćwĚą(($Ę»­ň)żĎ–ď)‹$‚G#ąr‰2ŽL”‡v›˘Z!đxH"b¦mĂAQÜÂńp>×Ůţ -, ż}˛^ĹúZTě+źô‰÷#Á™ *ýý¨Ő¨Q‚h†!‘Ô¦DůV„­ô#[moIÍ~*‚…€ç¤0"McRde»WżăV–hež~î9üťďt©ʢž>Y!?^H¬•©íü=W ©bôÓ.=/îÇ#ĎíĹŰ/ąßóö+1ÝďyŢÁâsçeŹhâ Ľ•śĂëÚkŻŻqöµ;îţťŃdý˙{‰ó )‘(“!ÎnbţÔI|ă¶űđÂľ—đÚˇĂXŤ ”B’fP© üiŰú˛vY§‹V Łń·Ţxžyř$˝>şĂ_ť8†®w!U©PŃ•hĐ7. ¸’C6ŕ{.@°‡…Y@˙ä-Pßęóż~Č„|°Ďę38Úb‘Z!•$FÔŁ v'ň$ňq16"9YbŘňD(FĽúĘ+Č[-ĚĎ/`2™ÍÔyR€˝?]¤i†ăGŹ™yióV¶v~nižyŮŐ¸5˘ˇśl0¬qEI.Ś›‰if›¸$~ ˘®Č8üˇˇÚŹŹ*üš€:( S3ŠB[˘ŠÂQte»BTń‰¦ü Ç’č¤J%Y@ÖëL„ŐS§Đš XYĄ*ŚÜEHB(X‰B;‚Ł2]Vőb¨Ť*c‰VĚ2¬ąŃcßw˘"#‚|­"ĹD‘Ţ™¸D‚pő;Ţn,ťmEväŘ1¬¬,#ĎZ(X›É wď}ÓÄ­%kâeďŹëÝ»+­$yÚŽ#¶ňyžăĐÉ9Ľxř0fű}|ĎŰ®ŔU—]ŠD©F%Ĺú×tNűB]”{DYľ%tćU˙żk?ń Ŕ-·=đţîĽçÓ˝~çęT%ĚRśĂo’<Á ßCž%xäá‡đĚłĎâŰ/ż‚…ĺĂMlżŐB’µ¶ŰČ;díZSS(Ë7ßđe<˙čCH§čnŰ!ú´ˇrPU…>˙0ŰMÁ=Ž*TŠśm­«öIl}|%*oenŚüĎÂ,yĽčŞ˙=U˙ů|ż …Llô0žîa=Óű¬ą Ťâr*1/Q (UNĆŠ´„ ™•™c­­Łßë#KsĎrź™ť)BQ”hµsK‹Kčöş(&Ąń¦'B»Ý†R ŁŃ`26Ó.ŁŃ`Âôěý©!Ž9Š˘0B:žá.”ÔäF_«ĆŁž?˘ę;,c2ĘöŮ ń,¨DE„ĂUPyUŁ«lăŕnűĐN8ËM`ýw*ž‹G$˝ ˙\Cđ”ŕB‘řřľ9`}aťéi$ťôdR 8q‹ âswš aÁ‡D€˛á—ZÄ2Śv-&ÁđN‰ÚúđnhŇ'5^zaR đl‚Ľű˛Ëm"IPPŘ÷â>¤i†V+‡¶ßO&Ášš%Źź"Z…C5´łOvS ~‘}‚IYŠAÖǨÔxčą˝¸ë‰§đS?ô(Ć9sDÚŔ`<{Xż©ť¸ŃŢŔ¬qíuwüŁŹýü5_%"ľé¦}ř™źąú­`ÓŞ˙źŔ±ů"ŕľűţ˝"őŰĂAßpă#ÝjĺŘ6;#‡â[>˝{÷áč±ă”ĄĺKs¤y iË0ůÓvy·‡öÔŔ7nůžyř¤ýşŰëżŢŚ!ăH$Ľ§]6 ¨ ˝©äFŞ|y]Ę,W ßo6’© 1ÔíŞŇó¬ß¨żzŠřś«ýł,‹‚;ťÖ—?űĹżt˙ž}żţţ÷\=˙pš~Ě­w<řîoÝ˙—¦˝w&”03“Ď:íâĎ’ý~ťvŠĽ{ö<…ý/żŚĺ•UŔJʦąěďwĐęöĐęOAĄ)ľůŤ[ńÔ÷"é÷ѝݪĎPu™p5đ«hV_Y¸•íĆŁ|OPŮ oOęa}ˇ~ćڔ̡*·ČI…C‹±§s%›4e·oôŞ˙lŽłŞÉýzHwbµQĎnNSý+‹řYw!]JŔhuJ’ÄŽ©¦ą/D—–MaÉĚ=›Ń<Ťb2FYE@€±´´•$X[_7F0ÚŞ8O‰ůSóČ[-c4”$H)$śÍ]ć$7ŔWŐÁﮎ5fň!ü˝±NTj a¤Űý ~L5 ٶ¬üó)“XgC&đĎi4v+9î9î‚R`.^.P„ŃÂ"ZS—@ĄÎ*8N8ü“îZţ¸¨‰JR—ŕXĎ?Tç’H1ßÂs(r$ „ÂŔüS¤˘čiËL^;Ŕ­É‹w]„˛(l˛­päȰU\ÍóĚţëăuQŕ°_7̲g¶úlő°Â±‡‘H„±D ,ćęsLgUőź'7@ęv{Ȳôc÷ďżćÚëľţO®úůÝúD~śýo}đŔxßîÝ`fuýMßü]Öí˙03śbÍ–"błD%Ě!fg‡8qü(ľ~Ë=xö…}8zäŠR#ÉR¤inŘüíňvY·‹Vo ˝á÷Ý};úćm vťŮí¶2 pŁ÷TSĹŹJźQôűBA¤ě~ÇňçJ°ńZ[VdĹ«”ű;ă«îś×ä&w¦¦:đź inŁă8AŮŮ ˙MŠzxŮ–$őJ$~L-lŘEQ@ł¶öş I’ Mm`“X–ZCF"WëKK¸nł+2¸Đ€Őȧę±(3˘7ŤXĺK’ÝaĹľW6S"I”Ł(ŕ‡ţ±ëŢj{ľ*LŢJ•mĹ6UM6â ^Âô®§¬ę’Ú•vE ó#jÉIŽ9Ł˝¨'*â†ú’Yc´´„´ÝĆdy íť.ëÚú›-â(ˇ ­qěv·ô"Ç·é¨%ÜEj˛Ş~^EL|ž1z`Žaff“˘´Ł®ŔáŁG‘ŞŰfg1ŹŤô3kLF…ą÷¦"qłU˝“ĘV^ Ĺ=CJ ¬6Ď-’ăźá»ŤÉůëó2S33łłłËKË·<űĹ˙řŐ#§ţĺĺÍ®Ţwß‹řŔ®úŰťĽo÷nÜy˙_ÓÝ× ¦¦~(KSÖ®űĆ,ż ÝV Ăé)<öŘĂxřáGđâ‹ű±´şB‚´e«ţV­nüS۶ăů§÷ŕëźü*íá4Ň4«¨ö‰‡PT#$F÷Puá#Ź"Ěťš˝5ŔRUAš4 hď+1WMÄ1—€c! ÔŞóî§« ĺç6ýţVct~ľ·ĚĽ·z~›%2Îrřő řbł YP©‚˘ÄĚä'ăa*0'ëc$i꿦$Ą”Řş NBżTjÔ°H(Ry“›w„UI‚Ş}ÄCP őˇ/*bŘZgSfŃZe+<ű>žhK]ű*Tßüí˘Jh^á€bä€HÂÝT9ç:˙€8îpżô  P ÂdiŮÎQ\(˙^*šD“Ć:ąD0öE»€—ȰňÍB- ˇÖ‡Z“ŽŔŃrŁz!9”rŃĚŚ~·gm{;ż°a×Îť(&%4™Dpem5$0ÎpĎŻăF9ÄGkź ™bČŚ°r2ĚB$‰Č¸Qő.0*Ť•sj luoŚĽ4SżßçN§ó÷Ý÷ĐO]wÓ]?˙\µço=pË7üŕĘŇň×¶ÍLO#Püť0‡f¨LaŞßE–n˝ĺF<ńä“xőŐ×0) CđËLŹ?ëv‘[VozNž<Ž/ýŃĆ©“Č:]äyKdŕ1łź"ö°Š˛qUńgÄ©jEá—ťýSqőďfŞ]˛ŕÍ`”ňĘ\RLúvŐEżhĂvŇj –MAń\Ú .ą8[+LźtUÚç‚$ś”ăÜPöŇ´‰č{»C°é×VGH’Ě÷bY[@Ąay WĚRT‰Ô^ĺś»€Š]Ź—¬ —˘–F/˛÷[ő0’Ä‚3Ťa’Lšöhźř6H.Ńł&ł$ "ţ)‚â:90B(6˝‰H„‚lčuDŮ!q,ňýx˘¶0B¦ËĹÚ*’N×?ű‘pS»Bű$»ďő«Y™;’"ËHŐË`Qd™˙0ď'JÜdKłW…kÝ^eYDĐšP”%ŔŚK/ľ%éh­5VVV‚c$‰Éo5ěžR>Éj°ň#Šá6ŲÉî騥TçŃp3‚ ËR€l ť$Řľ}ŰĺK‹‹Ź}ń+·ţóŹ˙Ăźü áă˙"®˝öoţŕŹ™ńf§nąç·E˙©ß2sieP łÓ»¬•avf€'Žâ·Ý†gž{ÇOśC!ÍsŁĎßî ďö÷účLM#ë¶qó ×âĺçžBÚ ;6ü<ąÄ)Rąq,f?ň$5¸Ť}«˘=‰PYŐ+ÜYŔüBâ4hŔł[É«ÁŐ=?µăłVµ*ł)@©ŠřřéŘŮö˝ÎÖ«©ep¶ŐzÓßUĎ˙\2ú3 ţnZĹ‹ś0Ě8Ůŕź$aĘD%X__7#qRŰMi$*Aš'Čł@Ŕd<=Ĺľí•j?XĹÚŐ1Úí[¨4ĘU÷·(8FU2‡Ţ5PŻŇŁV‚ŃçŢöÔť&€˛|ިÚE6Řő–@đ{7ŮR M˙˝@ĄďßŔ/°É>K/E1Ę]‘«M• PE¬¬ˇ5=Ü€'L÷¨_{ćřß¶íB„„ĺ`uTµ˝~וÉK%„ ü×íB¨Ěɦ†d "L&Ś«ßţv¤Yjí¬Í§ž:u*xs¨zđgDhF¬é`'eś*a0GbCÖtm†@{ÜZç¸}rţćmĹ@Ň&‘´±fš °şşöź˝öĆ÷Ď­ňoÍti|ë­{đáżç͛ܺg>L„žě]ăÝ9ô?šg93Ś˝“#Ęąš7ĎSĚÎńÔ“Źăž{îĂ űöaqy*M‘YŤţĽŰC«ŰC{j©í;đüÓOŕö›®‡J3t¦·Ůůă Ë«<‹ŘJś’A O­%ޑ׽677©÷ IVľ*~řĂ8Q<H•±Ŕ kę~f2yM ÓZ[-í('°rÁóL!ţs ľ[yďs Đ[IHÎ–Ź µ>«ă k)¶üĄÄ&ŽO&ˇ,t ô/, *M¤)Ă)hf,-®@ë$c…ü–Žv'˝•«ĐËO’A7Ç­{Â4é ¸ş†¤U¬}?˛â-©ŚńĐ%%…” `ApŁ„‚$AŚó)ŠúTC,8Öbß6'v;!ň‰S}ÄNÂóŐîÓSŁ‹ ĘńŞ×vĆŃ#HnΙPyEľŕ‘ŚxĚŻa]Rőřjtb!>ĆsV>! 2ÉB¤Ě­fg d6­ ż¦†mżiĎÓ8zü¸WÂdgÉlů,ŞfďÝč[°ĘŻMĺÚN$Čɨű¤ ÓTÎó˛—śŹn·ĹĄ¬ClSD`ÍÔít¸•gżqóŤ7˙Ý;îyôüý}ϡŰď?ţţďó%Ź<˛ď}Ď»p÷}Oě~ö©gďÚ¶múJ˘ÄNzšŞWYfŞ‘óͱmf€»ľyřÖxéĺoc<.´2d­¶ú{}´¦¦ĐĚ@kĆç?ýIśq10S˘R.+?Geâ&Čy„ä/‚A-Ŕ’™˘«x}4GÜM{ĚĐŁ0 QJLű8$EyW)j„ ĽżÁ×Mč‚9UÚ7&ř+ˇ/˘jçDŽT@˛ěÔ“‹)'…őőU¤iř ĚŃ‘$ áĐ‘#–ŻÜ'=°ŠlŘÄ LÓ(»§ş.€J‚Öť>-?Łg÷l‘Mˇ×kAë««kĐZ(ú–@ŠíŰwüŕÉ“'ź»îć»>ôăď˙ţ‡Ţ”Ŕ{ßű.ÜvűĂď^Z^˝{vvfH–ÁtÇŞHá• KLĄ ’NĆC@I«aŠNŢʡćŮRÖ=3p9\ÄĂ3§i÷ťË`«ŐĆ_üů§đËżüß"Q –VVŚ$2Wź[ĆôĚĚÔŇÂâý_ůëŰ?˛w%ąé_˙Âß\ Ŕ-·?üÁ’‹[gfk&v,PaO©Đí¶ŃÎľôĄ/âŃÇžŔá#Gd-3Ëź÷úhOMˇ;e >űç„…S§†Č˛ĚŽUű””ë­Ťd_0¨<{ßÍŰz¶¶¨ţÝq%¨ŞýyEU[•ęß]"#1#MR\vń.|đç?†Nž¬QL h]ZűUŢ Ý4b|ć°¶íű¶šcSÔł¦j4ü>‹]ü ˛Âü•ŕx2ÁoýĘ/c4żîŁ€rŤĺ­>˙_ţý~”¤H“'OǤx©YTDv4k\yŐŐxe˙KH’4v JBuÉ»şž.…@ FĐŮŻ˝v§‹ŃúŞý|mLŐ [ĺ( 4ŐMÍ|­™qĺ•oÇË/żěĺYµ.qŮ;ß R„Ď=e| Dă! ˙Ah l~F»ŰĂÚÚZĺ˘W„•¤pŐŕ¦uť"Í IDATň|D˛ľ\âĘ+ß—ż˝‰”â®!,´yanŻ[»Ó©ŰKĤÂôĄlÁë¨$ÂęŘu.YJ!ű{%$§ĺő@ěm@â{RY€+SD„…ĹEěÝ÷ŢyŐU`8\ŠććđęÁ†ßâö4WÜ(Ł |,PAܸ"LĺP’đ}Ł^ČPlĺÖÝ bTZ@x=g˙Ś;g–âŽ;îÂd<Á/ţŇ?ÁpŞŹĹĹekŚKSłfšÔňŇŇŤW&ëżÂĚ~!÷¦ôőĽ7~ýľO(â/ô§Ě6ÂJ†«év: .đWźýžŘó4Nž:R Y»kúüý:¦¶ďÂK/<‹;oúT+GgjĘC«ňî|˛ęŻÍ;•>Kh‘,t) ů}Ąj>´”‡|˝Z űlř6TŃĆí˙ÚöŚ;­.»hÝ®M&`Ë )îĆ“ÉŐxĽ.3mŇ*N˘Q ß”#E[ü<>g8ŹŤ‹ kŇŃpYk@3­p“ÖkdąAqTް˛˛!kµˇ ŹĆ=lÍy޲“DjsJÉ'„1:ŤŁĘ‹rŠrĆ y+‡†^ő,¸gžĎĎý«Jđ#(hĘ͡AëY«…V»e[1Z—Hó B«Ű6­Źţ‡»Ąwó ¦B×hµZ(-A7 ęQܤ†„S¨Ű§ ń/i­‘·Zhµ:˘•D yśĆ BuŽž)R˙t(¨f@é¦(ëp´ě⯼’^塓hĽÄ H[÷?Şűĺ‘6(‹˙t °ŠŹm‹Ę˝ććđđăO`Űô ’ÔO--Ż`euĹ\Wí(´™´ih™Ř:îŠ>šMď_˘¶]lŻíUŃlŻŽö?óm¸×]$=†űżő-¬­­â—~éźb0bqqĹ$Ń"3*85ĹD+˙ős_ľů.řßSzaŕ^·ŕ†[îýµN»ó©~ż®[‰Jv5A§“#Iźýěçđřž§077Js´:]äý:ýşĂt§‡¸ĺúkqđĺ‘öúhĺy0şPRÂ×öÜF§#ŢÚn)d7DňÁXôů!L~|¶ĎžfTűß}®đáÁTQGY ÉqŽ <'wšeZ­şť™ůöŇŽŰhŻĺ2®@Ť•˝Ő ·^ŽK;5=ąrCÜ8Ó„’ćµaĽçúQŐ ;űu»(Î+×ŕ´Ţ`´Ú ¦gĐíu1L!ÍsôzSŘŁbYj#25Řţ¶ňVҞ𠣰mǬ­­Y;`Cő’ź'Lq¬äWí‘’ŃIoĺ-ŚGë†cP鵥KŚý±*}włĆK.1;3‹µŐU$v^_s‰éé! Ęť»lbŔţůkö´ŻWŢ š5ÚízŁőM»<@‚źĂj1Ym´•OV¦‡Óرc‡=~‹R >›!ÝňšÓY˛}ôv§ŤîÚ:)ëĹőf>Ş$@!sĂĐ aMhÖ±}űv¤¶ ńçoŰ(¬mBsüx%öµ»ÚŠHŮ˙ÓĆzş×íŘ+l‚nYh01z˝.şÝžQIőy ůBf› ěg„›Ć(´Ćô`;vr5lŕw}2 Íč´Ű ¶Z—Ŕ„‘dÚíö ţMíDä9NśśÇC?О,ńĎţůŻ ?5…ĺ%“°mµ9Â)i¦^ŻËJĄż˙ůŻÜ4ÍĚżKŔöuInşíţ_jĺíOu»mü]¶ +ĄťvŽ,UřËżü ü)ś\Cš·Đę¸^˙ÝŮm(‹źţäľč`hp¶ÂWŰ*K8’ä˙oćH¸Ť "®0ť¨U^ ĺ«&”%ĽČ1¦%aŠD?ËaŽ•µöNgJ%Pi‚ĚZ§‰BY–`í¤ëh»ÜhP!=ŐéćE5#–0n‚Ý•ŕĎŤĹRsD#Ľ~㤦2›jE7ť(JU*g’ŃWýą&F#1?ż€$Łh‚oCDa&m‚@(čŠV… ŕáZ“ć@đSáÉtżŻŁě°ů‡ĎnnĄ> U9Lź$h1jhgĘe/Zg®“ź ±ł,´H„b8©÷ˇbAşô źŽĘÁÝ j.MTYÚ1rÂÄ‘ĎA"×8G„řř¨¬ô­¶äĹD$8ţxL…I Ä©›*„ŽŐű—rúŠlő nGbPç›ŕ„ŻÍh2„L˛= 4TbŞyFĽĘ­9{­6p„=ŁżîŹá’&żć8hkE„”…¤ĄĘy/6%˛Fg0,,-ăŃÇóźáWĺ×Ńďw±´ĽjÄ“Ş"Zu;-&5üWźűŇÍ«ĚüoÎ7ryÁ€›oűÖGł<ý«^Żc`i™! Zíyžŕ3źů <±çIśźG–µĚx_ß0ü‡;wŕŔ+űqÇŤ×CµLŚ äGÝś!ĹýÔ ŐgˇvE‘!…ň*pż˛D§śĹ±J`´‰U1Źë 92"BŞę€žĄ«ĚřX’!Ë3´:mäijżń ę §­ ć’­[‡N~{HőÄbÓŕ&Íóf–m‰‡eľY2CoÁ1đtÁ39ôŃú:ççP#ăÉže(Çcś8~Ż<`pÖÇk´'Ę÷Áë˝Ô%:íŽ:„$K*âSŮőĘw‡,E·F8×IńťN»ŤµőQ`ÚW’sć:ŹŰ誡P7FŻŰñăG [ź­éÔ …cÇŹÇȆH¬«Ř?Un¸űg»ŰÁúÚz…ś wAĽoŚOŤ<“„÷űS8uęd=¤F> Óé6őłŰéCă:‹6Ćj›AĚLMářÉ“HIĹnHŻ)Čěę ž3Í‘"şťV×VĹx!‘ĽHŘă`ÝüëDŹĘRc80Çź( ëĐXWB2î™ĚŔâĘ2––.Áh} (ĄÖH…Ńhýśţ™†±fôg¶CŻ-–VđŘă{€˙ú)üÚŻ˙÷čuŰXY]3Ç-´BÜÄe§Őbî÷ţŹĎĺ¦fţżÎgpA§m|ëíţ¤JÔWű˝ž5óˇĘ&k˛ý4ÍĐë¶ńéO˙{âIśš3•Ţďˇ=5@o8‹éťáţ{ľç÷<ФÓGË2rÝŘ’Š6Â$¸î9–«íY(2ą JÁü"ÚX#±«ú©B, °UPO“ a“ă•äÄŔuB «GČŤ'&H…4Í·Zhgą}Kk\!ö$®ěQq{‘{žqůgŁúÚ÷ý%ßśâmjŁĹĘő¨M[Ú(7)‘ĄHCI­ysŽä…0®oĘß˙„yžŁť&öfŚ °JC[[h%zşÔŘ5;ŤŃĘ;:ǢR’ ÜÚÍĆÇŐłcZ‡~¸©<5í¬…ŃddŰd±m*‰1èʤş¬Şp±ößÓZczŞ‹íáç°.1Őí©ÜÁŔ$·•ĘľJŇ«ÇíŔškµZei}lŐĚŤI V˝nŞÓ°Ű1Zµ(Ľ1¶y ­ţ˝V»ŤÜ{(  Î }ŚŠ÷`5÷lűű3úífş=¤Vۤʱ…¬+íÁH\Čß*”Ěh·Űh'rŢžă$J’ ĽŁX,K¶mtYbş×ĹÎáŔ°«Ś@?ÁĐLč¤ ­4Ĺ šĘŠo™Uřç˛'h.1رăĄÜŻ©…Ąe<úř ?ý$ţ»ßü-´[-¬­Ź·RŠ‚©Űî23ýÇĎůćUfţĂó•ś÷`ßľ}¸úę«pëmżÄ·¦¦,áOKä’$ĹěĚ_ľö xrĎÓ89w iÖFŢëˇ=˘7ł S3łřĘ?ŤůS'÷Č˛Ô §gó»yÉj:G)ö‘f»©ŇŻâ;ŢÍŹ=4çô©ëIEÄB€ň©RŤů~-Ăűh;…Ŕ*ŚDÂŚ#±{‘™ϲ ižGÁ}nRóD Uýi‚pÍŤ¬^űl¸ĺmŘx‚—°µużzˇ€rUČĽnÂ;»ZAŽŘ¬…é©>Ţó]ďÂömŰe)« ÄlxPĂ#?–5śžĆÂü÷Ud¤g| ŰoŽŞH vó7‰JQę2â}HşµÚĘőÁĹ˙pĹ«Ţ0|­ˇŰĚťyűŦMniŚnqô«i’Ł('›0LD«©oB´a}­5cffs»/­éîő€ćǧyl6‘¤Jë¸ĺ—Úä>kůOĆěpS—ě éV7n(ýą©÷ÄHÓ“rěyÄ›$G›©&Ru1#ŁłĂ!NíľŘ«GÖ.µ«Îí"ť_ZÁüň"V×ÖÁş–Î`C:Słx×QČ:}´[¤ÎÂâŇ2ö<ůţň3Ž_ýőßDY2Ć“Q8o×± ś^·ĂĚĺ˙óĺëľ~ŔľrßüŁś›bŕyO®ľúj<öÔKŰŹ>vë¶áŚţîÉ˨”Âôp w~óřÖăČÉHŇZý>:6řw§†řâ_ţ)ÖÖÖĐîôˇŇÔtüťK# zŇ‘p‡@ČŹHAy%¶ąťI{ѸęGÍ1KNÔ&*:ŐŽ?_ ň=•W"#G¨jÚŕ›ců›ă śQóÚäAˇŞí-5&´…ř±ůümý˝âr\Ú v޹ŎvÓ^§‹é~ß}Ő;Đďő‘g)Ň,…"ĺ+ËZbD»ÝĹ+%{NŻ”Řo©Ó¶Hč,?5ŁÝé`[żÎM3–Ű=€ý©¶ žÉgČ‚Ě|ő†É,Wdŕië'ČŚv·‹Ůvű´ć?Íámó„Śa|ěK«Ăp&aĂ\\ćšŃëv0č´­&ĘV°Ú8LWŤ­™”.Ę-Żź8©ÓLu;_G~g±˘Ďú•ĺ9ľ~í_ŕ#˙ôW1Ü®ŕ9pšqrnŹ>ú(f·}˙řcżcÇO˘,…ş§×F2˛ůý~ź—?űµ›îyţ#xĎSp_ýĆI9˝ţ¦{nľř˘ťł©*ÜĄE°ëőÚŘ÷Âłřú׿‡Tj`˙Á˝ŮmČÚ|ţ3‚˘,ŃîtŮOĚđ;˘ťQCpŃăJżż˘ĹĚ• ŻDőA•©ŚlRiTýr Ęq-Ő-©T©A´* ‘ „wąË”ĹŚ6|‹#,nŢúä:©Ź(ŞăVŤ'ŞĎČ*Mr¸©Y1‘>ô§+N“ÔŃ\›I”çżXţ—I’"O.˝hT˘Pçě‹„”Ö†łŇ”03˛ĽÄd2i¨Ý8TÄ´jˇDAç" : ť$`ë(„Ř7.bĹb‡1ša‚\kLʸÓE &`b dńŤ·<ŮŁi*Qv¬ęĽŕ6µWR–•%Pn\ěSô4śîâä0I#™{ş®×–4<ęĘžă"Çd2‰§FĘ€űf)UŁë^zg˙‰6Óurq3¨ČĐfᔢ8-%‰0eYbR”ď*ž\ŚűóJ»fg°6#Q‰1)z^U‘K;ľví_ág?úq věňç´¶ qčČqÜs×]صë"üÝţĚĎ-DÂî센śŔÜ©S·<ňÄľď˝úę«O˝afĆu7ŢýG»vîxo|”°ô5ßĚł“ŃľđĹ/âŐW $…vż‡Î`ýŮm $ÁţżO”B§Óµ˛©&đJďGN|}ő8ř“dܢľŃFU?PS’p_,ć#M,„ ‘¦$ŃžpcD)•E‚UsÜş‘?É¸Źź…úÔ˝(ިęheävŘT&’Dđ'Ú$&×˙U›+hüró ”N›!źw?۬˙ě ŔpôJ—Ř6=Ťéáş(Q¨T&Č’% Ş$h%Éva,&EY4Ő» Â$…#MŔMę=áŢČń˙ť†–A§ ¤  LPLĘĺ5IĚî?¶×aŁVOŁ4uĺ› ”+v=ăaCn‡Ý0#`Ą»ńx\96Ş!)§[µµ´Á!Z[c‹ČĘčj0€l<Á¸("ŇrÓ/6./–fR±{•Ú*IZ÷ÁxŘ6Ů8J*‚a|'5—>Ajňżp7K ¤yf0ŔŁÇŃëv1^Xx]‚żA\´hĺPi‚żňüýźţ;.˛ş ŚŐ…9Ľ|ŕ5\ýWqĹoĂÔpÖÖFÂń“„°Ą‘¦śžžąhßľľĘĚ?NDĹßhpčĐ!\rÉ%řë›ďűgł3ÓżfÜź¬ą‡2 ÄdşĂAźúÔ'ńíW_èÔčL Đ™˘73 &…Ż|öĎ$E»ÝőšéŢ<Äň(řW¦«N”póâ%Ę;őŐ‚µ‡‰‚ż„¬$€ëíŻlĺ>Ď*ݱDţ­uµď/ČŠÚb ý#m˛Ał¸˘Mž]@®aňAÇ[Ë“ąqűÉRś*ËJĂ×z,Ym6•M>Ž4ÖŃćÍ*sÍŰ€¸ŮGů,즱ŔÓ˝Šb‚n§‹‹wě™J¸pë·„VF”ČyźW¶HĘvÂV@äÂ@7HÜĵ–硒ş,«»ëé+ćęµ x\Ôš&9c,{ôĚ(mŔžŚ'Â0is˝‰joÚŁimŻ‚Abt˙¨Ć=e>M«^ü^^‹ă÷—říßţ×LĚł^Ý>A033űcź˙ŇM˙™çlÍó’\rÉ%¸˙‘§/_^ZűT·×eÖ4 X:p™hŮéäxčÁűńÔ3Ď`iuy·kŘţ3ŰdľüąOIŠN§‚ż’•żs‹őü«Áż©żk{)˘ADŇS*†ńݸžţžĎĐÄ :,ĹWXşú  řÍx Ĺü±ŔŤňźÉ)’eĺ)ěž-“‡ŠÄÜ^íĺ‹Ý*H_•ŃŞş˘WÚZ´"Řf˛:ĄFu˛Í«ľpőxiý­»ľ¶:KÎňÁŢ:W i t:ĚĚ 05čŁ( ;ňVřÍÖ%ł>Á%)—2EˇQE“`ä•őÂUµ*Žk›»|ĹfEĄőPÓšˇ”ëŰoŤëăÚ~y1Áx< ×…5&©ŐĹźL"Í żP‰öb¸gË%ĽI’M3Ú|ąqp…EŇKÔô«a˝ł=žqšb´>¶­¸jP*<Ä[ęůW—M’¤(ul¤¬ą @ý2‰ c4GëM×—ęČ_E!o…ú¤:MQ”e$ICS˝îŹóU1—Š˙Ć­Tíť!ě¶ĺ˝UdČ›):v˝v+këÁŞłő«˙´{Ýóó<ÇŔ7ż~#>ôs˙ýí;PęşÔX]^Ŕ /ěĂ-7 úđĎannĄfÁH‰RJąÓéţ«ŻŢpÇ îľóÎ;qÍ5׼ţ 3㆛ďýüĹ—^”˛ćnŁX›9ËLĆ#|őúëpěÄ)¤y íţ˝éäťľôůż”2Á?Q&řSö·A±–Tů5ôß©2‚H5źq–=c–¬}Řym'ő+‰~*&‚ë$.']ŞŞ$?ß“j˘ A1~ 53ŚĘ¬SéŇ޶µę B‚Q"·PÚ`ŢŘW,C:7ČóV@±ř¶ß\ść3G}Ót•/Ż#oÝęÎ#âip@!„ĄhŕD¸ĘRź˙»5ńJ{v=&Š0ě÷±cvŠLźş,KCú˛˝¦„µ]G®%¤ăçMµ(ŠX׼–°pŢFUˇ¨'K 3ŠRË[ç+|ż 1˘¶QµÓ]o˙ůŐ‰­ IW‘ô’#ö;ĹçC•@ĺ¦4GŐpR¦(-Ç€Ůęq”gިŹzĽ•cTŚ6 ·±Wě˘ÄSőđÇ`¤‰FQN˘ůŚ­©­ŮzgůkŁq$·ČâüĹď'€/ śbş|F}­ÎŚÂ!ďpIUŰ#%[Ź$즵¸VÁŃ]»’5 ÍC€a3™Ř=Ek `v8ŔŃS§¨ÇD§éťŻQ@ŁNk+óĚ$·Ýx~úç?†©ŮĐe‰ROp|n·ŢöuĽűű~Á ÖGă ö)ΑúS}ž››űÜŢ—Źżó]WîXy]·y~í–{e۶Ů÷ń9îm~ ęOáĎţë'qčČ1” t§čMĎ 3â+_řŚť'íXáťD0ŢĄˇO˛ i­[)Ë)%®Ô‚?dđG ăSEő/L Äzć^K;_Ůë§ZŔ‰ů>íÍ€¨ĎoT˙ 5J­…ň— ľ![Ô"7Ă–Mf&ĽÉC5•´¨|r='njŢRčDH*ˇ%ÚLŞđ¶˙@%Ťú,“:mżîŚějËBĚó'd䥻ť.¦ú}LőMő?)[ń+/ÉŞU"mÝćĘš=”%&ôĘą%JBqµŽ"\™Ř1@ńĚĘ÷á†(ĎŽxŔ±±łÔ 7ÇÖšL0žLdޞ0@2™)ŤJťĄ" G–Š˘ůăÜ G"ĐŽ=ĐĐpeG˘ ¨Héë@,˛,ÇÚÚ(Ú 6Ç‚(~Ńß `Zš1@˘ÓQęz´95ٰŃ×GŁ E‡"¤& Š˘YŕŰŠ˘•™ó(K“Ř:í —ČH= Ů9 Ij_“©h¶Jm†/R–O&Auu3·6n‚ÚzqL÷ű8|ü8zť¶ßŁŁi†ž€,Îy<8˛ 7kiĚŚ›żöeüôGţ1úłŰPN&Xš8|ôţęŻţ˙Ë˙úżc|bŢŁr‚JŹ`š—<ţŘ#˙Ŕż|]"Âţ Ăö>˙_Úí–ćČWţäőči–b˙ţ}xbĎ“XŹŃęMˇ;b°}'nşîó(&ňvŰŞű)ĎUbÎŢÍë{gżjĺ_…ŽhŁĘ“_ž“yĺ{čÄ’=Ż ™W`®”Ş ¦P“O©Ź%6ë€MBPhŤLsĐÂ’‰Em#`Oä©·%÷ °Ş«ńřY’v,\AďĄkíF ,sĄÁŐ€€şŤš6l~‡ZŠą‹z1sö–±ç}‚g|š(dyĐď÷°m88ř6”e‰‚Š ¬ŁĚ3˘UY·†SÔĐĹDmŐĄ+ÉZĄtd_ŇÉ~ E OP˘,JÖČđ*~HÂâź‘0”‹ ©5&EÉd­Áą©ü‹¨5dqÜŕČ2ÇRÍEjZÝÜX{łçΠˇä*]…ŮĐń("ŃUiič8‘Ł&„& YQ`R–uýŁŤ*ýŠźŽŰ†„·bĺ™ GŃŕÇ ]NC HmKҵAA±GE\l…`¨¤Ż…˝9č]”¶P`RŚí¤—@~#î‹Ýk`2ŇßÚ.Ôéţ–×Ö@ŇÄŠÇą‘r;™uˇ^~lÝ&%DŚ,ËQLƸý–đÓůĘŃĺd‚ŐĹ9Ľ¸?zčA|Ďw˙7X]×ŃóUE^“$áN§ý?ßxë}úłţŔłŻKđČ#‡đŢ÷^‚'÷ěů·—^zqĎzf Ó0ŕ||ĐďăO>őUĚ/.#ÉZčL 0ؾݑć9Ň4 ¦>Ţ˙Ůe!RµSËsŐW‚܆ÁżAß“Ą b˙óŽŻÎŰS|c‚¶ú7Őµóä—4’¨ 1khmYQÖ<¦RKäŤÄüÚZěŇf„6<Ç:y¨ařĚچĽž|“$u!iˇJŻÖr4Đ8"G‚‡ĐDć——‘fň4Cć’Bä®yľ^M‚D–ÍuH0) Ü{×7đ#?öLÖ1Ź1·¸„ë®ű2ŢűŢĆúxâɡJRĽĽHhŞ×Çń“'ţ33řLö·łNŢűŢKđŔ#{/[YYţ•R -ş‚ŢĄŃK!IĽřâ Ř÷âKhŤÎôÝém8tđěßű ’VyÖŠPĘ/† Ç+ý˛#XF°ůÝŕOkÁŁĘź"«SɢwU†ŞTĺR%P4|b2 ęľŇË»F© 1`ŽÓŮ˙KéŠű”ć(Fdťľ*»KD.!ŞWj$¶A3*ű}D}ëŞöy]qÝpľ™˛·ýH® MĺĚ}ĂNkĎť·˛ źHŢ7•$&ČR´Ę“ńóGŹ`ďÚ2˛‰H}’ŕä U«V®Çâ…ä~N°Wť0‚ĽčTýoPAXA‘Őî·ńFż:{î5Ă’É´đç ‰JŞţŽ€}ÁGŐn ĺDoŮŔ¨ÄőcjćCĄ,˘ą‡d†kżIľňŹ.®Vů"CHÎ-řű ĄałP¤(…,MŃĘr¬Ż­c´´—÷ż„4QH’i–Ńź” @%Vţ×rdŞÂ˛l%”¨°ŻË°¨€ëígm]s^ő©ąĘ”b9Đtű«Ţ´ÚË •+˙ˇŤĺ‡t\ŃW~Ôś5DVĹĽ)râމ#KÚ]jvaŚyů•«A§k싌vŁźUľ¬‹ ť^Ó ™ϡ ©d‘€¨ŐŮd¬äÍ )îíÇ‚_1' d5\PŞÄü:ÚZsrŻ}Ąýůąâ…›ákŻ˝†”5ZiŽ$q\€­÷ř·bVsĹ´6ó̆Č[–Ąź˛""$iŠçö<Ží;.Bo8ńú*–W×pÓ-7â‡~řýŹçBKIˇĆÉfýn'VOü>3˙ŘVĎ嬀k®ĽO={`ű‘cGUÉ~±ŘŘÍ 9HIaiqŹ?ů$ Rčöűlß…›®˙¤hµÚ6č«JʉĽ{™‰óő*™+nhÍųŹŃă ‚ż>*Ş˘ŠĆtü7ŐsAŚĐŠ Š }Čo*Z´ĚeőNµÍ™*D:öىvŠ€ę0ľfS…PN…%fiuZĺ#A~ż–ÇqÔ&ą"F|ś4ᦑľ6ŢbŔŻ>ô›đ|@6h·ZXË3üÁţ!Ž?ńx„ń¤@Q–`¶$N®†˛­<´tvEĺ&mä°ýźMăăüKs=ë79§_­«\n@łŘB’¶áGÓ™ňąXj6Ľă¦Ł¤ :8ż…ű]“Tmš·ŕ­~ů˘Ň$ć ň4ÇŻýĘ?GQ”hőSdIbrÚš®řه™“ÉŘ{=HÓ27Á¤ň÷Ýs~ćücŚÖV±8ăŕkŻa˙Kű°műNL´®$M.‘&ż/¶;í˝ţ¦oţŹ^ŕ÷~ď÷đ{ż÷{Ř»ďĄßĽňm»I» Ď¶’uśŁ#ÉÜóÍ»1)Y§‹îp{ź{+KKHňÜĚD+ v¨~ŢDčú“śonPČ“ă*Ő·`ŐWç˙]ĺS©2 g{UÎő ¶DÁ Qĺ¨Jäp˝˛ę¬lŐq®`hÖV2Rö°b•"Ż JŃüÓ]cúĚ_łDV„p “ýzŠĆńuĄ2b§}ŔfMpä¶°Đca<´IPŐ›NTÂ|¶¶üÍÁ&Ji ť–řľw&Ĺ+««ŚÇŤ ”eá·Óu|7ČŤüŹy“ ót›ďi7ľć÷TŐú‹6?„ŤßŽ*oşÉčjÉG›ň¶p_ ÚBÁ~féŚÂ(m-ŘĘßQóť;›΄łJé\>v ÉĎFwŔýRĄĄ Y–aŞÓEQ–XŠ«®únŚ×V1Z[Ć}÷ߏ}ěQĄt ®<ľfĎď÷8qâřďř…ń'7ŕOţĹ?8˙ 3«›ođ_$Iš5I±˛s˙ 7úEčµ»xŕÁoAˇÝťBšĺxňá ôźµlżź*Đ•mÚ /[‘´t}`™ŔŠD%(’§Śú’"yť}nnřRVU{÷±\0ŮlĂ#ŤČ@eꉂ$ݸód«¦˝jśřTóĄ,S4˝m,Ƕ%€ű¦Ä"ž Í|’EQŃ ň /' ) Z51Ż´#ŞséDö<*źx6ŢiżÝl’ĸQö¦¦pĹe—ammë“ÂČŕ–%´ÖfŚS7Á-Čsş­oŽg˛ÓróhE#'jŁăŁ­ţf¦Â9T¸§)c+Đ1Îů­©ˇć§óÍ;·ăŢŇK57Nč\„łýhÚÂŇĄMĂ>5Ü7/±®Śúk’(dI‚ôTk¬r…# ŘÜ@­«|ľf˙«‰€‹›ďxű•HÓťnyY˘ÔÚ7ŮKbźF}ţ˙üu˙zĎĽ5˝±nĘř¨×ń¸ĎëÇÇQŃM6)Ű p<ť„€·]q˝vđ×hfŰł¬šE”–ĐżŠô˙ëĘdLĎaćT’úHT®n<%$ Rđ¬kS@íĆS(m…e1"{K&D’ĂNń0pŕ•Őt©Q&Ątp7ń*śn:F;9 "S—(5YuÄ}-ňě}©ÓĂqť+Ç Ö‘ň E–ŞŽyĆFLŤÉn.Í0u7E6Ídß"B·ÓĹŽ;0™L "`5Şx[g"Ľőßđ^˙ߤ׏ŢPMŕą4–ń¦Ő¬@¸ěŇKpřđ!;Ypzß‹­üz;QWČăÇ!¦Xˇ›ŁŃľŠ©îÖ&c<űüł¸ô’ËŚPWĄâ x“%çyţ‰Źýâ>ůĄĎÝÇç5xěľg’ckË?GVŐTţĘĎóšjTůŤ8ËR<÷üó@šˇ?Áťwܤ)˛,ŹTü‚ĆľťůŻhöKVĽ§©RóŤfssě"I•qÁĄ…*구ć)î‰Ĺ‡‚*`śý‰d©ć]€HdH ŔÖúR˛fŤŇ˝r ¬đ ©„§TF•É}!ČSM/kâB•zŢ «}Špp4„ =—AíŹë­i:Ô ĂÄ@m$¨‘őşżpđ¦éëi\ń¶·Y `+FĄAńÖk#8÷ômŹ3|ţ‚Ň[;|äwĚĺ©ö~ůîËqđŔ+P*9ŐÜN”˛óMJ°M<™řĄá™§źŔ‡>ôłŻ.áą˝{ńł?ősFIłA‚%BLÁ”¨ôďýO˙Ă˙;üŇçľţ|&tdyá˛N·s©˙X_¤H±0ó°’‡iŠ—_}iŢĆÜü ,ÍĎŇ IšFÖľ586˛÷eÄň˝ˇúŹl~Y*íy`RŞÖß1d>öŐ5¬Ę`D d©Śe>PN#tjA­lŇ Źm7¨"&ü‘ô»Ś‚°k]Ŕ[I:€ź,°ÖłűY^S>‹ă9)áěQ„ŠĆv4p$„w$‘Ą–€ČhŁ–‰Gěě¶OţXđ:¸Ě#ŹHš&{VFĐśHÎl ĎýoäŘęt°}۬×ěot\{ëőúł·.ý[ݦ¤Ŕţ÷ŇK.ĆÁÎŢßś ȵ‘r™ŔîUf,0$eQâСčµ:xé•WgYLĺH¸Q›ŹjwÚôĘÁW>ŕĆóŠ,,,ţÄ®‹v™Q&Ä9ě*4a"“d>„éť—âéÇż¨iš…ŤQ¨Ką‘Ł[î~9ëÜHö7Ňř ăw1M5Ř`Ç)ɨ`ĆCgf#AůÁ!!ĐS•6Ůś;H P•‰otž«:Ú~ţÖqěőĐl2ÍRkk0$÷»I¨IŞ%Ë÷‡m D*yRŔ3V+\l`|$I“6h“•!T\ý¤oFˇ ŔË“÷F6ÉDEq1’&fXÉääŚ~=Ło~i­ńö+ŢfU»bŮç·^o˝Ţz˝QňĚđ|EÝ»/ÇÁŻn©-xö†aÍBoĚŇËA’űL\Ü»÷YüčŹ|GćNŕÔÜ\Ě)ŁŠz¬Ř÷Z­6”R?ŕ¦Í°°3Iµ:ť÷fYîőŚÁd™ňşő}zóy‹ó (-:püŔ« vËT˙rŢßUŘl‰€ń-U«2ćyŹuëw˛ú7•l‚HűŰ˙­ ¤Ä*&Ů1Á}+sSÁ!Đü¨­Q““-©¦çű˙ĄF’5@Ş@óRa«‹WýŔąáçŐëQU ¬VşńńÄ}€Ş.m„+J‹ăÚůU I–„…¨ âß·< p®y޶ŮcňVŐ˙Öë­×<0Ďč%_„^˝ {Bőó8u®´`PZŁëbbČhuKËËHňNś<ť;v‚팴Żú9v &ŠŔi–˙Bß·qçŰj‰âµtó<ű~Ń ˇńĚ$ nvŁV 'çN!ÉrĽüň~ Ď˝˝/*:MJ}ń쥄O¸ˇj«Ă2.xrSö…Â÷Ł>ű ío¬‚ +J\·6×!ČěRĄ…A‘ń „óÁ_ Ć÷3g6šň¬ŮLX˛™¶­ÍN.Řü®ç hű7ĐĄi%pô÷Z—BlČ˝ż­ó=ĆÝ×î8µ5ä`͵cőh†xŻřÜtô»áXÂ粆?n§Ż#ĎťCͧ^~–=îŤa<ś¶úß˝{÷˙ĎŢ›GŰvVu˘żů­µ›Óß{so’›IH$¤!Đä } ŠŘKŮ[˘˘––ŽŇ÷t –ĽÂ§U–ÍÖZUZV9`迤´$ ˇOGŇß&÷ŢÜćô{ݵľůţřşů}ë[űěs›„{2NÎąűě˝úµćoţćoţ¦ĎţĎ~ťý:űőĚř2,Ŕs·dOm`˘cKŔD\YKQŕ±ÇFo0ŔŃcGŁ©°ŚŞhđň†üĄR/ř©ń“}L(„m‹¸ňĘ+{ý~˙Bb ;cn;HiƨŞĐ ńŘcź3F)Eg‡Ň§ŰiłTID©ÚŁÜh`ä?çE‰Âv7>ąU,bKŕÄÁ(:qn0"ÁaśÉ“ äă}'=ňđY´Š.wKç7Z›9ňöŢÚO"DěöĂ ]q"Ă„´MŹ,ŞFdäf'CáMţ*{=,--Nĺxöëě×ŮŻ§××ŢóĎÇăŹ?~Ć$Âq—tK\ň‘>Ë\RyŕŔ><˙âK±ľ9Šgr˛7ZŠŚniďŢ‹/ťP j”· ü łŻýúoŘk kőë{· Š´M]C7ÖŽúCĎP„ab™Ż×j'A úc"îsÖ~„öĂÝč" ʋٜňßę´h ł‚ĚI0w€! ‹)|f"Űe 2 t˘?Ö?$vĂŠH{ÂÚ57>㎠]ígŁyľZ‚o+îÍ>k˛ŔÂůU§uÇŘPGĽłÇÚšéžÜ ©™“_Š·)bÓç'âR§: 8/7ŐđÔż»vť­µoű; Î~ťýzf|13š¦Á{÷âСC§ey‘Ž(ęňŠź?iŔüŤC€şŞ°Ľ|ăj”µ'—„‹ueŮ™ąťN@Ž9 €¨Ĺ™…ĄŠ2fş»±żŢ§Îlüp0ćE/ń[fźDE¬E,”ňÓŽŐšĆ%ĹhMÍsTů©”ćíě-q]ŁÄ·^ywżŽěĐŽ$ŽgáæfQzÂmQXËŘŮ ޸Ž¦Ă±˝p6†@$ĎCšůS4˛­507„Ő4ůÂC@4 ׉ěg°„;+† },Ř9Ň“÷ ”P:3Ť˘m 矣)‰§ëĆ–7¬R Ăá <Ď~ťý:űőt˙rYřŽ;pđ‰'ZʶűŚ0]G eęĂ [í·…eňÉqäčĚgZ„ĆĺWEQ`TŤöxń0žČ1çĺĆćhXĘ?č]ßľrÔ0‘Ą®á‚ósóxňč퉖ÇŹV±.[–{k'9žc-YÂ=yp]‹ łp< ×:óe003ŤĎ– řJľâ` ‚HŮ•‹ŽRĐBčŞ9|¨}k4Ť3"j×—OÍ:÷ ~ttâŰOběŻFŇE;÷9_ű¨íĐ©ţĄ ,q-»xA¤¶˝P ýڎą óŁ8a¤ŞÖÎ*Đ'Ńą±˝őŻ˝Ö†Ă4Ť™ňőL~5Ż˙™žĹ~5Ż˙t|ŤÇc,ĚĎc}}}ęš˙ô­€a`O®­¸5¨N|†8zô(;Cr#AP…BŁëÖ'mżOŞ «ëk}—é:÷˘3Co6ą‚1–±ş˛,č8&š#JŢ|Ţ<Ü•PĎ+Ę’Ň’µĎŰ{¶d€‹[WŇv–ô’{E‡ťŻowT©;ž1br†Bh_”™#gĆâr”F‡Yä®ÝʵĄ­´¶9ęÇŹJ,6űż bP#Ňj›u«´ě"ŮŠM†äoÍr(GSXŤÍż,pĉ€FZË#iZ°ńČâŕâÚ~é¤hą[)eô,Vg˛ąąiFYw<4N%¸M5č ŰSݧiŢw&öń©"Oeŕ›f][˝gÚíťôľÓ±Ś3˝î“ůlUU^ Ţ+K”eŮMëăôé¤fMłöĚ4‹dysĺfgf mKuŽŤŚ őLĽŹÇł6Î76Ž7Ű>ř(:¨š¦1±]z›9.Ű6,.,˘:ô°s§p˝ă÷c,sŔ>X†öi—źTiĚ·ŃůĐĺ¦-1Ç `†ţOłn×ö' ęhÚä€i×K6ëWÂΖ" ”ËôEY"Ac7t¶nŘÔę]ÍźEű  ő,D{Ě"SĚůĽMBťÇŁ||±A´ä‡É€äG"'e©IULâ'̉D AÔúĄ0Pš řCř·P,6Zo]Ż›ňĆ&"”e‰˘(P× € kkk‘ őVeŇc«ĎOZV*4Í˝Ż«\‘[GNĽşťmŰęµiŽË´ŻťŽă˝ť Ó›ŰńŮÜë'¬Ó×&ý;÷·IŰË™çŤ|M Đ&e˘Űů·î¸'§Ý§“Yg×˝ďXĽ˛(P—ĄônO©0*Mcrź#)GcŁ/˛–âŃőÚšĽ[VN,“Ťóµ ţ‘ĹjąEđ—  cžT_!š˙ÎńYÂíJČžCK˘4 á ¶'DŮ«-ÜÎćٶHZŁ R’“(k˙rä…±‹ş®ÍŻŃÂOܬTˇ–·„™˘k‹¬ëT¸0eFn×çü˝N®ÔC,ĘÁŹ_’ěő ¬KĚ6ÄZfÚ`Ă(¸†d@Pű9j.Ť,€ c  őşíf¬UU™±±±¦i&ę¶ H§ňďíŘIźťfÓ2Ó.w»@aŇr'ŐFO7ăp˛Ů¶¬OË>m÷o'H»Ţźţěúű4ËîúĚ´ű–ľîJr-cť->çęţňK)3.XÖéÓöŕ“f•¶Čţ·ü*Î;g–×V˘R¸Ś3q5Ü´?;q z0ť*-lĹ(üôîľë XßذáZÉAlP¬¬xÁ=¨Ť0m\U¸úŠă–O| ĚM–Q YĎE ŞP(ČR EQOu`(ÉÔSŰÚčħÔ~*›Ž–1~µÂ(qç 6b´¦=I#»(łĂ8b, |DIBöż7 Ź9V:4 ˝;ŁľďKŘxůžD˝oQLľNO˘5Os{8tö3O|áj9m0Sj`á8Ś \ R(<⛋¬ŕÔL=Ü5Ń4 Ćăqô€q€íŇ”§#ťj6|:J§Ł|˕̶=@«›F~:ďËé¨?űňTmďÉ\ŁÓlË´çbŇőó•ÖSäJ§rOObŰ̸ţęk°9Ţ4ŽcKŽţ€ŤŤulłŐFd[öa®Âx]0űÚW˝ď~ׯ ‹­úŃ4¸o3´03ŁćŞV‘M®¦C@ˇ Ă ¨Â” Ą (EPŞ´Ś ‡d©svµkćlŕ%Żţ尿,„V_pűć¬#MŇKĘ ~FŁ–”¸ńUŚÉh/LT‚’ý¤ Źx}ľNjö^TŃů~RŹŠ~@`ű$ČsŻBÖüČtCB[¦w - Śh‰ ć$njÇH&ëL>ĽžiÁë鲮łÇíěů9ëÚ ÜLŁ#:ĄŻŞÂ ×\‡ĘuĺÓd{ *pâÄ :ň  ˘ x@â»p%˝ú ćÂ. :ß fŮÍŚ+Żx†»÷`s´éűáó'$O̧Ę]'(dÝÖb¶nŔŞ›Jt3€e•ÝEYaFEa˛~>ÚćU`J¸=Z—ítúhpM(ť_üXQźj홢&ş@ŇĄOµ&I…ÇşÇV§D°V@c©†µÇ˝_‹}Ňű(xŠ'÷y0 UâčŘ`™ŹX; ü Ă M8ů‡,!L;(h»Y÷iLx ž©őäę˛OĹ>ť‰u<•çç©Z׳éülu}ź©uťŠŽ(Ë 'ďc3ő ŻzŮK1UÁdM T#Ńm&Ďé‘#‡±±ľŃK€¨­n«€’%ý`\ŤĐ+ű6Đ…,’™lť[řß°şş†oýć7á/ţň=€»,7Ö·"´ÚmřOÉyß}K/33¸©ˇŞ›ČźÄ^Ľź*”ś^Áţ$ë ”±Ůvš#' +9áĐ\M†MˇŘŮP©`łdĽřŇx °‡óc`˛[»×ť…3E2ŠHĆ‘^°îh©ľ·] p-x˘ €YÔ§/Â?qbç+’vç'Óú˘\•¬±Q¬ đ6éĽiz|Oǵy:ŽśL09]÷×4“OwŰęü|ĄňO÷ká™~~žĘë;Ý'­őÄ®źIËđmÉ3‰E"ćÎë^z+únáÁ.…řZkąĎ´{,d…<ťŐL"*ĘR®k°ŠŞůľŐN–,Ě_BA…-;e`Kä»"”"°e«`5,úćIv4ÚďŠR-qBrÄ6ŔŇkşĺ«@n4łě(ČłÖá@l§Yž’ĎL ^Áo''XŠ íR”,DĄ&öçwŕÉ’­ků6ŔŻôCD®ű™ř¶3}~¦ÍľźI ćŮ2§aGNuÜ·;ÎX‘ňîŚxŁ1ö˝Şiěßęh’!Eôy@–J)ŠŇëÁÜhčşAY€Ć/ÁüĄP¸¶C‚čűöĢţď™/Ż'ëÉö/ę~tÚůń ;v@ĹÖżč8´{?9-R ˇ‰KA·‘nźÇ”FóÓî!r&×SđĎd|6ťźłěČW1;Âť˙čx/ůřT †¸ńe/ÇÚĆZđŁmMĘEQŕđáĂX^]3Ob˛€&”ú`ŕî»î«^őJ!nZ™Ëă5‰â‡fťŚŰ<ű:S¬gŮ‘ŻŽóóL¬ăo{_(6›“Ś´ŁüÝ3Ęti ©ńmoxtÓD\Ż‘“Ďo—t10n6ńđ#›ů3¬K‘ýiV:­@`X][ĹťwŢ…›^{”jĽXÁMÉ ¶·±@pemżńŻ˙ň~ÎtdĆä—Ç­nojă@řüĐz!űKÔMů#vék†I'<aoI@8§?ś‚—5ĹŤf0k+Âł˝ńJÇ#~…á ůČÔŠU$"ńćC"ß&¶S‰ˇťß@Ł\@"ťL2ühr`Îśä[4ìkňÓ$ý¬ @Ć9+JAd gĚűĆUăËg)đgĹúfGž ć©Ó4Ť5RŇZŁaŁu˙ÖŤ6s´FcýŚ•°i3a»,÷»™3`†ů¶źg»l-–-×e/\·]nšÝöz«aĂQ¸vŃäš AĐd;l=¬ńűŰ nj4MŤşnĐÔ5ŞşFUUć{\a<c<c´9Âx4ÂhcŁŤMlnV§HR{Đ3ń—ë‘ë8ŕ˘ËňôL®Ó˝OÓžźÓŮ­‘îÓ™X׳ĺü|%Ż…3u~râ˝®óCD8ľĽlĘ©¬3 ݤ˙Ýr5ОŔwľńÍhÖŁŕŕţs&z6.Ü˙ýöŘ2–™Z(”Ë|÷Ýđ¨÷SÚ‚[›×x aum˙é÷˙#°¶jÚZŃ0˝Ďí ´”í˘ÜS6@ţ=¸ŁLźĂůží‰\I;B»ŕ Ô.t]pě}5°qA˝‰żkůoÄMŕol`ÖĐMF7hË?µżZ|VCk6µałŚh]!`;¶ÂĚ.°ËtŰ#»Öh4<¸a \‚çAř‰°~» d-ßg·«1ôČńLât=DÎÔĂŞë!rş3®§*HžióTťźg+yŞ@ćv‚äłX03ŢwEa¬ŢYë<ŕŘ]ÍĐ››řĹ·żŁjěő2ŕkńšKÂśyݱŁG±ďńGS+“1<­Ű©`ŁN0`QnÜţ©;PוČz•w­c·x?żĆJ´xţó.ÂŰ~đÇűŮ ŔŚČDÇŇ8ČË×Ň‹[¶Öw ‹@éet)2Ű@"ífHF|)Â|Űa҉…ĚqP ±±ö•ň;üMű í˛hü &Âϰl$Z~7&Ŕfţ¦Łß%(`”˙Ó|–B7MŘí¶ËíG €‡Ý:ëŃ4hšMŁńŕc‡Q/Šg[vňl1_‰€˙T01O`q¦J.gŮ W–řĚ]wŁPĘw2u' F x͵/ÁKŻąÖŻ3 ö:fÜÔ57ćţîĂh4 ţ6`jS¬ák»rícDŔ#Ź>Šűîű˛źčçEbRđŕ_n0a\Őřµ_řeĚ.,vÖO}fź°mzś2Ý$ŔAS áßËnmZBčą:đ¤÷úÁ6ť@­RGzŁ:”()qÍ!vAŇe˝>¸úŚś}ö.ËZm-wČÖuë˝ňólżuÓř2€Müήôŕ˛v1ÜČ”L«¤/0&€ť—ż,)0ÄŃľ¸‡‚dD xŕá}ŘŹăór–b}ĆR¬O;ňLgŮ‘§ßůY]_çżx§ńlj¨ü6`Ž_Ťź˙±·css3ö! ĆŚ€ ˙Ź;ŽGzH8ăÜEťoxčBśŮšFă¶Ű>a¦&©”"Oç‚“.cc4ÂźţÁ˙ ¬­´v4xń·µ© Ç ¤Ůx. §@ŠŰ,O ř1¸ŘŞ ×¤`&˙ëňÄ,jěŤ˙é©›ť‡¬»‰ľë\öŢLZ‡źMúoQŰ÷ĄJZ'”~˛ą,ą~ťhĐŤö¬ë&°Ń>4Ńň<íŻŰŃÔ5ęz Ö ţécźCQĐYŠő« XśeG΂§ęü†>ţű_˙ôĘŤ*rQw¶Ţ'zs?ů?EĘďo $pĚřkĆ÷߇ŃxŚ„TŐx<©ćYL¨ý»Öż>€sć.ľěŠ7JQQ”({=lnŽ0;7‹ç>÷9ILqożpť3FA„ Îß‹ÁÂn»őŁP˝~¤î7 ~)oD°ĐĄ´‡ž2íäI롣ĺPEÉůÚ+batťa@‘Ż€\o÷6mgűă÷x‹bËU°o 4€Éýô€Ĺ6ćČa l|ús’íÔ<×n>ZŁźZ,îwą®örś"6ŁŰ!x¶Ë•`±?öZ’źg¸mc +¬ŃTcJ—ůĆWp%ĚQ*-/ Őy ; ňč8—ýç·5µĹMOrn›â‹ŮŽůy˙{Y§ë ż'ĚT¦äŃúŘ8TEďŤo*W§Ď#Z´ÎUŞU™ôž°ůKב<óŕ´…Rx˙nĆ}Ď_c<®P–efëĎR¬Ď ü™\'~şĐúgb]ą,ö™~~r÷”EÍŃřÇ˙ ďý›żEżěŮxâ|{¬qŇxçĎý+_÷w5}FľäC0}äaéŐş˙os(âÉq_~đA;&ݸ©Ş‚P ‡fsó Ýî›Ĺw§ |Sck€zccýńţ°g\á„Üź™qŰ'nÇž=»qá…ÄîEŰóZA––đOď{?nzÓ7€ĘńD>ë @ŽÉářg;°ÇâÄPbĐ­R€+9(kňÓe¤ą`Ţ ®‚!‘8ßĎDíqąI ÷‡-Ţ?tt#Ĺ.pŽ{0¶Á2ť¨ĂÁQ®0q’ô=9ó%ŽJÖřßą:*ră› ¨˘„Ň%€ąą<ôČăxđáÇ ˇ,Š0ŢY–˛Ď Š#”yM>‹şŚÇ”ř|¶ďßÖŹŻT„›ůî‰Üł2yoô÷Č)2łb˙đ˘hRŮ–Ź`š°g”ű'Oő0§“Ź'ŹđN¶I} Ŕë|FaF–ŹîäÓ aÄŞňöű$Ż“•38~_ôĂtďřş·N.w÷iéżÂđČü˛uĽŹ.¨F0úÍáaĺţŘf×k·1=®.~„ĂË`3X™!e;wě@ŐÔpZ9îÜ1iĆ#üŇĎüöž{.tŁ[±"öʎč"RDU#Ü}Ď=¨ë±H¸О„* ›G=j@ec¸L&YĐŚ÷?ţĐ}W]węqe¨ây´¶ľŽôfĽéŤoŔŇâ´ćVý6őŢgęÎÝsŢ˙ŢżÁ7żĺ Ţ*8Őř€Enj‚Ęf‰“~Fń4HLl?ÄÄlKf‚M‡f{˝čś<_)[Źő,fPË!şô®ćěŽÓrH÷śyšÚY1TşĹâZěŞ<ü‡É?~ěB™:b<‹q¨1@~*ľ¦Óę-a€ôóËÔ¦věfŞs‚`nł<ţ8¸ł-Ôćţ°‘ Ś.ZBôl–kÔ.vW9§ďPþ؀ˇ8)ĐĄŚ'ŮĽŽµAˇ–n— Ó8âĆŃÄZKβErŁß @pÇ&yÔV™_U 677°şľ†ĺĺśX[Çćxl Ë(>&¬f´‰wüčżŔĹĎy.ꦎ‡ú$u”‚ k<đŔýX>±loş UDŠAGź<ň€±˛ ŕż'1˛fŕ€ń‘'<Ôô"*X‡@鲾ÇźÄͷ܊׿ţë0č÷Z×|śĺĆA@ă’‹.Á{˙ü=řŽď~+07ź˘@R‚s\/'Q6đËč¸{s ě“˙ÖĚ„ö‚ĂösAu‚’p쨓‘ČĹ™řf$Á*Lâ`ëT÷Á—ż]‚@üÄR“K5ą2@[÷Đ®-o]`ď@IJAq`(R@żŹ™AKółXZ\Ŕěěý~…-oůéČ™´™LiZBqŠ÷w€„©éYÚâ“™t8›ůŰsśÄ…“بéyfÚâ8ś¶(MŰ ÉłŰͧTťé*)Pňw§_Ůjń]ϲ®ĎrÇqńÚ!NsýlčŽcËY¦@fíöľÔr8'wVżÂâu¶ÜÓzŤ!¸ë|ŇYĐ(Ó*ĺDyd&FŠ#ĺ´NĆž\±ă”ďç7­Ę56Ş1–—WqäŘq:z +kk@Ó Ď­zs„üŢ·áĘË_şn";ľ,ýď†ę‰Ëp˙ţ}8pŕ –çFŻ+*Qö çćq÷>w—µ†ŕ$űŻŚčµ•_\ܱëÚjT9EźpäSxđˇGđ™;>‹WĽâQnĐP”UÓš¦Á5W\ż|ĎűđÖďűv 7”š:Coě¤[MA++Îó€ŔÔ6đ™´Ţ‰€"íB@žˇÄLH •ĄmQr¦cQ,€˘vößęČ@Č„Ys”ç@UŽĹş–łŤ6ŕŮfŽ©o‚=w¤ łŤĄ9Š3Ăv.-`ÇÂ,ff†( 9d3$~wÖÍyĹäřKîĚ:şF]g/4yě©ű¶Žë*ń'ĚVĚçţÔÍD°(íQ+~¦Ô^D< ÍżdČŕ‹0n?Ŕ‡= h¶C$‡Ó „ťX" Ôä‰ü”GńÉĽ SLypÁíŕ kz]Hśů¬6ż$ÖÖĹVhK v‰! ’Í*2ž-’Ţ÷ŰîşŇY6CŇő-ö eŠd{8[Ö ×z¬Řβ ˝(ĚßÝq(@Á©†CR˘013;‹ţ`€‡ăřň tSż”ń?ô}˙/»ć4uc«•‘j-űř$á;~ü8|č!$o’š˘@0ŕŃxtŔŞŤŮ´Ęĺw‡cÂń#ŢwÇ+^óu/YçuÓł¨a‘vÍzřěľůůY\uŐ‹;o .`Ý4xń ŻÄţćáőo}#ضnäi[Ř]&Ц[Á?Ř'GݢíŰ%d·#=]&AyýAÜ&—Ó=„’%“:Ů…|}=¬ź(béuĐíZč” ţ[±13Ô=ŽYŽ56/©čňç@¤¸Ş(jPf%v-ÍaÇŇf}(ĺĺI­»#pgئV$˘8¸ćµ×mjÇë4zH Q†IĆNSÔÖ»Xż1Zzúú=GĂŔ( BRJ;¬ĽĘ!AXCMŠž˙Id›¤YŘäÝ„”ÜyjDëLR\nŁ$ÎŐ뽀ŚÄ?“ťä3”†^ÎmźXÚ÷=`ef¸8”sŁÍRl!ˇaŹ‹ýXŐ€ ;'Ξ1߉%¨xß=OĂtŮ0{Ć1˘#`–Ca‹,IşOQĐM0«ŔÚk”Ł]8GZÜl,®>Bż×ÇâbUĐ̨´Ć‰•e4ă ?ýŁ?ŠË.ľuUGI™`Ńä?I˙°±ľ‰{îý’1K“Ţ+D Bˇěő0™ŁGď˝óđ7m쮓ŔD€;€1€ŤŰoýČŻů†7ţH5® ň©:kV4˙ä(ĘW^ńBLěŤo  ĄráŢ đ‰ü(^÷-ß„őŤŤ“9Ť@5€¶0}}k0CÝŽ–M0¦Ř—Ŕ tů[ łxR [o»¸ą&ëDť9f"ß‘L ¸ >2ž~÷< ŕ\[nq¦O (ŃďXZśĹŽĄ9ĚÎ |űڬn3ĺéhĘC#Ä÷1‹QČÔ™Ůúě‰ŇV@ä䄪]Źđ´ŚĘVş´Ďa9Ó4śHßť)}Wť^vÔdÖŔĚu·®G÷ô¶Ő…păDô‘˛Üމ{@JR –¤»ăĚ›’#§¬ľČĘC Äřs…Šg‘Č`-)kŘ)*3Ä>*q1ȱ ň@SëLĹŞ°ŕžwî'Ą 4;Ć^¨(Ů<×":´A źĂ‚fgg±çś]XßÜÄúĆ~ö' {Ď=Ť®Ť~Ž'Čv©®ŹńĹ»îD=®"ă67]Ę~ó‹ó¸ő˙ëă6,0Îd˙[2śhĆvaÖîě“çě>ďƶը;ÉŽ…R Ö¨ę»íSčőJ\~Ůej–©@ĐÝ< óó¸í>Ś˙ý;ľ€*Ś’;›aO ü۵yluťhŹî2>G7w±™ ęČS˙B÷@Q;±\\W…ÚF7GšˇäJ$ÄeiŔ EŔĚp€ĹąY ‡Ş€&0iÚ`*Žc„’ Ëí?EŮÖ}>A"k‹—M „•{řˇÝą ʱ—u¦˝”2$źťÔSQ‡Ćˇ`¨ŽăËńß'Rđ4ť ašŕŢ.«p$¨¤i>Oíçvgž8Ű^3kqĐ‘~ĚŘ€ŽTýś,J¨qbÚĘ´L`¶1PÜADH6s÷eH‘źfůÔV<÷†P2?$|ç%ůÂ^®9­÷S( xQąQ…Ä !üÓŢž6”94Á·ç‰áűö2±Î›łiż\g+ŻĚÍĚ`÷9»đÝßňĚÍÎŁqjÇŠr>ŘGő;$č®»îÁhsÓ|^»ýµ@(ËýaźŹ?öŕÚÚęÎcˇNE±…GŽ.¬‡Çź<˛ú˛Żąék«ŃČ´üił©Ę×P­±˙ěXZŔÎť;&ŢJNl–¦ Jřńď˙aÜuß=řň—mŁëE~ńU¶éĺčö® ×ůľ4@dkŮśY&|Ť:˘ćs"CLZFNýOö)c;,ÚJh‚Ű_îřř€Ţń`ÎY0·ŹqJk§%Őą=î!Đ şňĽdíśÍz˝ s3X\AżW=€m‹ z%Î[ž¸H®‡üy =Ľd'aŠQŮţľ0 ň˝ŽŮ ËP¶ĂF|ľP Eţ[É÷űoó9Ąşţż†Ž×ÍöÄŻűő©Ü2ÝzĹ6BYU˛ě¦ýŇý]ůýVĘýÝî·2ŰŻěqRŞđŻ»mVé~)‚Űť~“?&íĎSř{Aâ‹í¦®ĺŞxßÉĽr˝­cćţmö9ÝfĄ”żNä±u׍˛×•?ŽVŕś1É$`nÄő{]…{JŘ{›őđ;H°8„±áúO–#žýá™ÄţúĎ„p±EÂ,™0yż‘lˇE łdC8fv$±Â+ß˙ß÷çsÔŠÉ‚ˇÖž‘°#Ë) µeL«Ł6ËĐ`~~Ż}ĺŤčőz­sőó% ’{afčÜu÷=X_]™v‡ŤŔ(Ę˝Á K;č“7ô˙{ü‘‡p ÁŘi¤#ŕ–(űţ€ÁňńcŁkoxĺKzýÁ’®rŢëî˘mS7Řwŕ °sÇŽ,5زšM^ÝÔř¶7}+ćqó‡>ôz-¬B¤îŕž¦!ťÁPŰ §VŹnRp(s `pB-Ę•“—Ý &$qž(ů?˘H˙€Vű^'(QÇE ČPĂ-W‘BżW`a~łĂ>ʲH*b&c‰Ě8Ü6±RȧˇI˝Ů™t„et•¬A¦°%ŢîOő$»],¸4°cEÄTÎđ0ýů”ů|ş;“cY( )X‰ŔŚř/*€("%¶ËŃ8hşŕ-˛{ÍS*ą€›;đłrrŔH€ŻxŮČ‚%ĺ·«ăó€B P  ĚĐDt.eRB>†łćŻ5燡„@TqT‰¬•€›eśűÉ”Ľ&±ľddÖŁărşç38űQ¬iŕ°ľ÷_l›gŔĽ,qĎ=!Ł÷*š)”K\đ×±eŻg`…o€µ"×e÷¤®k\pîůxńĺ/đĆ[ž‰Q“=\íź Pp÷]÷`euŐ?ëĺ$Aę87ĂEQ¬ľ÷?˙ńĂř˙°"JŽŠHźäôě÷ĚćúúęU׿üUŐxd'¸ç‘6ĘŢhMٱ˙ńÇ1°űś]ه}űÁ?ĆŐ×_snşéuxĎ_˙eDŰÉ÷q¬jeç]"®v/ÁJ|RBw ďÉ-“â*0Möö–źíí`ŹlđÍgŢŠ)áNp"»•ý43Ń(ş–;©L‘#”Rč÷{Xśb8(M6ĺ‘7‰\Ĺ kv[&EiÚrBv”íyHĆIĐĺ¬ĘĚL ŚHôć·×ăţćŠ!–řF‘Őąş˛ĘO ÷Kl:·žĐVNÝB”ę bE3É{$.ń šĚ·H0‘cU|€”‰ěŠ  ŁĚŔ u˝7z}‹o"´ÁPôw [˝&†©±8wŃľ·uľ¬C"Sç l‰ďC«QŐŃĺĂ3}6¶ŚHP/kéŇ/@,… źĄŇžărÁŽgJ4 Á“@3ÇÁ;ęŞŕDÚĂÄ’ˇi d ’íóş7aaß0ŁŞ5®¸ěryŰűĽďK÷8jA€ěhR`1EđOA€›Ř;t`ßňµŻ¸ńş~Żż¤›†¸iŽłT"ČĚP¤l9ŕ ”RŘłgw‹.ŽhÔf us÷ěÁŹ|ßŕ–O|‡ě%ť>…d‡câ&xkjśĺ4?jŤnjŽ€Müď ‹Ě$Č˙®LŮ.8Űź¦@Ů}Ţ´TR4H(Uň*K–ĐÁĐÖµuĘݤš:–IÁ>f4 Pbî“c/˘‡ĐÉr´Ź«d¨Ą'pN °ëôKĚÍ Đë•íú`4xH¨‰ÔĹĚń(o?H‰­h)1SˇErN<­Č‰U°lÉJN–Ă ;1|vÂ$@űqÉń{:‚/ŇŇy5´QĘ{‚7âIĂľd$‹}‘A•ČÔ5†-bBrBKGy'j@Š–ÉľP,†¤Ö(pů cÁt™L‹)D ®T!3ză(mvzÄ® €N%,P»Vź¶,ŻN{-ˇ ·ÁDę eęvě¸+.ťř\[žfn;ěÉźZÖßť"ßvěhń:Ňg˘Ţ/˙ ™Ëtâ;ŕiŽßďÜý˘ŻCí?€38‰Ƹ©đÜ˝{ń’+_ *T(A;m(0ŕ|? ý~ոwߍjT…•»×ÎÄP¶íŻ?baçúČ?Ľ˙Ďö=ňđIöďD€Ň p[  N;:şô…W^°°´ó¦©|}BRâd… 2€>ô$VWV±gĎn ý¨u&—·§Af`\Ťpý5×á-ßňVüýţk+Ëí»ťlk …›®3MÔtuQI! â‡F&č·bö Đŕ˛ĹP.ßeĎáşM‚ż]Ž­™ěV@g«n}fzźŽ€´ŇQ°ogŕ­×í¶kÖQFĎ6ř·ö[‡ŔŹ(čjźý3‹Ľ6íę¤^vÍ5¸đĽ˝h´‰R H00\¤ěłűšťâÄň˛éó×MÔ˝ˇŮÜKZR˙e‰r0ŔĚüo¬Ż?ňľ˙ög˙ÝfţNü·‘ˇ˙q˛ @g)ŕsźüřŻ}Ă›ż±©5qÓk-J•‚LáŘń8xčvíÜąąŮl}s˘@ U27;‡źřˇĂ“ÇŹá źú¸×łu-Îdş]}Gą±ąÓ¨âsš‚vI @lŻěw†ă ĄŚt;)# LXBvrÜęÖ5í‘:::.)ĎŚ† –f“ŔT§rĽ-6Núľ®ćbRkÎJdęCx”5µ:Ľ¨Ýs'is_kđÇ#1KĹ4!©S#*|·[ď"ŮsL5˛¤wc%–śe@Ü.äÇ}áâŘRZ7&ńF·ş*ůůŕTÜČ-Z¤âcA±8Q@AZ[—ă ”Ýű_[§ŘˇMęČ•t˝h1<ěÓď<”GCh•Äe⯱˙ yQĹżĆTŠEy©°.ŕĂ‘u.·—eßi€lgęń`Ł!sQ ź[‘ĐZ@ R´(xÁźĺ˙]ŕÔ¨čXČpËkŃţčxŁ1n*śż{7^uÝő ű^¤HQBĄ¦pfÚŻíyśźźĂăŹďĂ=ěA´»'‚Ć@{Pë„™^Úµ“ţřw˙ďßml>a˙TŮ˙v€.=€Őxôä‹®~ÉËęŞ t‹sq"6˘đ@T X_ßÄľÇ`ff;–ÁĎtA" ®kĽîŐ7áMox3>tËG°|쨷ČOäxrĆlgͤŕčÖw"đI0Ü%˛Żś·˘ÁŃŃ-Đ}z}–ë“®’@’]fXćD©›Q˝·@ŠPĄçJůcD˘›-č÷ ĚÎ Đ+Kßű,…lA˛đ@Ő‹n‘žrhăŇ‹Ąr}±SĎęÓ?ä‚V99níô“ٱڎ´@śfĘú«…±ŚŚ>®ÓÁď"ś© ‰řÓ.­yQb˘ˇËO,Fk‡ľ[˝ 8¤”€Y6Ä;¦D1#“%E­’C¬íńćÔľ&89ľ0şç–Ő‰[^jgż‘ŃM dsK•žÖöŁŚ\\ČV·ĚrX¶»ĹÁ?ixa·„řů“c8)¸Ů„ZÝ$ 4L÷‚Đ^¤§ÝëV@§µ ęh˘źřąĎhŘÍŚqUáŇ‹.Ć+݆ýľ ţP¶&} Dâ—06î8ĚÍ͡PŔç?V×VÍp;Ź©M©$ęP ”Ëľ©űĎÎĎs]×ţě˙ů}'ü;j©˙µi˛˙í2[1ĺg>~Ë˝Ż~ý7żZ)ęëF“;I$‚ąëŤ ć¦UPpřĐ}ňvěXÂĚěLüPšR HdµW_‡xŰŕÓź˙ö=řĐ뉙ň1kqjwÎNYăě@‹ ×ě:ĐAˇőpŤÖ!©Iž.ŕNŞéÇ"Ô©·\G’u/łcéß)é LUNh)$"NłŤý^‰™aß2b4*'<~ęj–<ĚĄ:rkKýÔ“Q§Üš—ž« ›ŻźKQ^\ĐćÄĆ.ťţ(m^3®ÂkŮĹň„\€”#—ÔĄ¤ëőOPáţ5”=>bd%Ţü”´DDn’Ž’Ťîyé7'@Ž;H¶‡ Ał˘¤‘kkVPvD…4ľ‘ýuHgůfÔó”dîůú}J‘s’­·Ţë—Ł˝(OGTĽTě#SgwۢcŕŃĺR3—˘z˝«Ź‹őB¨óS  EmŢ­SKá®#\ ‚á§Ž~w ˇŃŚş©1;;›^ń*\xţ^?ܬU eDĘYtçNa×®ť8|äîľëKht˘"€dŮŃŕíP=cř337Çł óú~ó×ßU×őáDř·¶˙?N@†űr @ÝőŮOßó5_˙ŤŻÓŤffcčJu8s‚)€VVVńŘăűŃ+KěرU"ă™N čf5÷Ęľď;ľ×_nľí¬-/GµTmśôPçUáběbGm= m·'ę\GšjnUżG«Wz’65]eąXβÁ|D§™>űĎ9" ĺB~Y“J+Ö+›Śŕ̰Ź^ˇĽú< آîÉɰšĐ“źzü“p+k›<Ĺ‚3®•›Űyôp)Sľ=1›ŤÇŐ‰őŹ«> sTŠ Çżs P:h‡TDË“‚F±4Qň-‡ÜÖ5P>[ϵ ÇÇXú-H3´ŚŹĽc¤ß_˙©Đ”2eŽ»}Śs µĘdr¤Ţ©ĂE«];nSćQ­ÜSďśOJĄÍ:śĐîm~«Ć-SŠvFĎČdüąő¸m3żř@Ý®Çk´­#‡ě>ŇȬžĺ6'Lt»dÝDxé‹ŻĆ ×^Ą S©mv!}(˘R”Óř2aĐ`ÇŇľxç=Řżż˝VTç˙nßCîóö›ÄďnĘ®_%Ë Ű–Wáwóď2ü]•(J·¬ÂZó’Ř%Ü˙Tä$î‚©ýłRÂ_ X,;¦TI“#±—ÄČĺ1g˛ĂC–Ł(öQ Ší® Şí˙5eÄ­ ’Á‹€aîw |‹‰+ŮG9ĺ÷ŹbťEëyÜUSK’§pŁQŐ®Ľě¸é•7bqaMÓř!D) şŤ¦xű—v,ac}w|ćsX_[ó׋Ll3f8š*Kô} fg°¸s'}úc·ţŐí·Ţüqüťę?˙ËČk•·čo›.űwłf,Ř ŕ»ßň¶~ë•/yé7Ż?ńćMUšAdnŔB(‹T”(Ü D*ôŐ*3Émqa×_w .¸đ…ň$¦ˇš‰b EˇP żńŰ˙˙őżü 07E…Đ$8*0önĎ)Ń»ŐéąÚ4µ]űŘÝ\śQĐS¶Ťm­ßZÇŮMj÷›ŰŹX9O“{,)z•»¶—2€„2mśßoŽŘtY,wí«R„ůŮ!ÎYšĂěLßĐöm@™^řčüR¸éUa®ePęÔ—üźĆĂ2Ů$YŮźÔÎvĄ ^ĺŹmJŚÇŮl‚Đ ÷Ř‘Čˬ%u̬)ęť§ö„ޤOÉ;u=5“~yň"âHŮť'a¸”íý§¬Ţ‡ć# ą‡^°4 ¸©ÍlYns“é ž ôD6s§?'s»굎M­j‘Ôń·ÍÉ,\Űě;ęˇw%I©ëPV`-hö„Y€¤űµŘOâĐë/„ł±Ö‰`Pgôi‰ă΄ԄH0 ~ż2íŁń]řÜpíKĚ<›F·Ú%łJ3˘K08ýAĂáwÝ}|"8W&ú"íÄŚ–°cˇTa‚˙Ě ćwěŔ“‡~ö?˙Ţż˙CKű±?WDíżÚŞö:YˇoAŔś»ěřŃź˙ĄźÚł÷9ׯťXFµ9BS7`­ˇ`Ń5)ĄAŘĄËeŔ¶ň•ŞÄóžs®ľú ,,.Nµ rİ‘ ˝^ÇŽĂ;ë]řźóWŔü‚‡ö%3Ú¨=S ô]ŔšLI«|ĐöÁš;€@wĐŽÁ­ŠúžI¸ĐĹ˝ůŞĂ®·ËÍ/g;K™u¤Ŕ VT†öď:6Ý,e(ÚĽ!QxM)…ąŮ>ÎYšÇÜĚ@(n…đ«ÝtŃü>ë Ű+M–H9ĺ6ZCU¤÷yafŔ)ŢßĘn—łń€¤P1ĹĄĘVfEqĄ,rß‹u ébR)hK‡6Iš4p(Çȵ=(“ĹE–ąŚ¸ul•ePş»V Z(uÓ@W•™‡6ó»ćÉ 7{66¶‰hi„×4jŢlÝŇp˘Î÷ŻiůţpBşLyBź¶îix R(é|„Ţů jO†Ý†0$9ę@đďĎĽ/ŃDÝ™ěĐ ^éŻ5ŞŞÂ…{÷âĺ×]Źů™YŚÇcTUe î:<ŘMUDRú`)`av‡ŹÇťwÝ‹qUůrµÇzC/ď“ …¨” zĘ^Ă™ĚíX@5?ö{żńÎwŮŔˇí/ţ5čť*—ĐŘ0Ě€€ťo˙×ďüŮť»wżxýÄ ĆŁ1tUű,ľ Ş(mfn~Şh*<+ ›ťÁW\†K/ą˝^mT,´ęýś°&Éô«îˇCśYǤJÜ@2@LfK”Rź`׎9ĚűP…Ędw±@,u¦óoSô{= b•âDdébŮoDKMëúĚeteÇČ7IZ7Ą\ĺ8YFŇMŻ:€,ŹłŠ­ ŚĚÍúg·[ŇÂ-7ĽÄANrT[ü"€˘‚1v L®ńPIŘ˙7'Ç(qu\ó‘''öżŹű]Ý3s0čăń}űđ«ďţ7¸ů˙p’@`« Ť)2kÉđ%†\©`Bönt[± .Ŕć2é.Ö Ĺ.¤Ž‹śŁíŐ”BľI3(FÓ[€B)ĚÍô±siŢ—RJś2ţ(—1ćÁR–({=;ŮĐÜČŤďn@¤ĐëőPEtLj­1®4Z·ÄŤ’=pŮ©µ^­µ ¦ěD&»– ĆŹ.ŐŚ6– _ “"{iR#ÝͨEąKž¸íVů‘Ľ*yh&YzËHĐóţ=±÷ Ą•f:^‹Č™^|0[ ,›cX Ę…°?MŁ1ÚÜŔúĘ ĆŁQ&óG<5.*GĆż§ŢýQ‹(Vĺ#i9ˇ-äs›TK×uăłÚx;âľülÉŔŤ˘E€8[ďĐ«ź|ÖgţşĹT¤‚D$lCŚş6⼴Üw«ÜAŮĂěpAż‡BÁeŐŚ±±¶‰Ý»ĎÁ«ox.<÷\Ôşö\łFUŐ¨ĆcÔumÄ€ %ŕŤ~ŻÄÜězřqÜsß}hęFL€ 0\2Ó’ő0m˛ Şg<ţű33›źgRęÉßůŐ_úő Á?íůçiř©R@ –ěp ŕçă·~i83wŃúĘ**d5% '¡°J ŚÍúěMÝ+z¸ôŇçáňËźŹąą9Ó‹ÉÝBé´$Ú“ĂŤ= đŕ#ăÝż÷;řŕű˙_fŁç:é™iËmYĎĹî˛Cwć-÷±µ¬VżötS'«-÷Ť»?[(Âěě;ç0;Ółu¸-‚=!+r$ĄP(Ü]ŕ`üµF]רěÍ? Ńë•BŚëëă 㺀 Şâ[­( /\lęÚNăh9- E˙3ň&ÖuÓŘţea‡cgŇw€R„T ˘ŕŚD,˙˘,Ń+{Ůíoš¨\ŠX( Äý§$;`·ˇPÁWđű*ŐU$‚2…˘W˘×ď{ 3Ađ­ËPW5Ö–—qôČln¬[űÚ–ň(i÷ä(h!* ŰiÖ¨uă•ďčxz]Ę"$Ć5n­Ž%-ŠĂÁš›››¨Ş*é«o—!˛Šţ„†l€ŐÜxŠ>3Ö6Pn>®n±ȲDl÷ű03677PUµ7ô'¦9ö8”Eą™!vĚĎcnf˛(mjüçíŢ—\}5öî9MUŁp#™•6Śş®0®*Ôue¦ÝZý‚·bv‚`;ॅy=zźýÂ]X]Y  p:{JG7ÖW 3rľ*T(kńŰĂp8ŮĹ.Ëމßúĺ_x'€CVôwTţŇ௧ˇţOHA@ą°ëç~ýßţÂÜüŇ%ëË+FX;Ż´-ťW(¤ú*ĚÓ›=;;Ë/ż—\|úýşć l%”miýŢO;Š÷GżŹ÷ţĹź!TYd@ČvO^Č7-ČŠ §ÝŢúŕ®QĹ[×Ö§řńVA:“Mn9B·8nmćA©ł3}ěZś5%E^ĹP‚'Űâ8 pĄ ʰ6 nj“=Ô5Tˇ03˘×ë{%?3°Y7XÝÜĸ®ˇ5·ęř Ł!”…a°uÉ:6Ąi‰űRš;ÜMc3@­ý{•rza@Iű\:G Eë;¦%.®Cˇě÷0č÷»ýu]gTŢí ťjN|MWb§”W$¦gr,đK×%@ Đëő1lgäy8Ň0U5ƉcÇpřŕ~¬Ż®űąoJ§x`€–Ů %Ö˝Q†Űh *86Ó™§öŕAř·ŕ5=ĚÎ΂™±¶¶†Íń¬1j7 Y˙—™2˶‚dŽ{j˝]Jµţ €ŃŇÍŹŘ{(˝~łĂ!ëëŘU†–GĆóŔ°^Q`qnç,-b~fšW\z)^qýK1?;‡ŐŐ5ÔMŤ‚eˇP¸® Đę:0Î\(h C‰o~nşŃ¸ýł_ÄÁ'™ŚX1«ŕă‡s‰ŔOÁNC©ŞW ß`0;Äěâ"xňßýĘ/żKł>(jţiđźZôw:Ú'I=ČźnűđożâšëžsÎyçîőŠGnł”Tôb¨)*ĄP× zź8„AY`n~Ö x$Šě®ĂIËhtAżŹŻÍkńöy;4·úvŁúUµĺĄFiď}hdLk”CÔ’…a@I˝1ö8©[skŞajľÎŮśŮŢ)LRgEâĐh/Ť&ú!LsٵŰŁţç$«î•†>ĘRµÄY2pHU/!Ëăxš—ëX1‰ űÚb]7–¦„m%SvÍ@ŐÔU5ęş¶˘$ 9ŞÔ ĚĹ1s˨-ŔśŽIuýĎŇťÍf^^EmA€ŽÓdżP㦜Áş¤iŽťŐřĄ;Á—7QAŘgfŰí@Uרµ Á˛•S#vű˛TGőj 6Šč ×!€8AZä çśäÜÜZ/µçRGc_ÍÄşşn°ľ¶ŽŐĺUŚ67ŃÔ¦Flν¶Şńp-hĐ ;ÔŘĺšňʶ óFŇÔuş©ýßQŻ6Ëo<ÓÔhFĂî=ń:ű~0 ĐhŤÍńăńČüťÍ¶7ŤˇŐµÖvyl—ŃŘupŰmoě{µn¬#źŔŤßF6íň¸1?m˝ß>˙^+®´ëwű¨µ¶Ű_ Ń†Á[lŽQc÷Ó­˝ľ˛LÝË®ąßöMoŔU—ż˝^‰ńxŚş©˝q”gălťě)š1A››ĹÜÜ,îţҸíw`uuÍ€_Ą"Ż“TăˇÉć+¤·Wb0`87‹ůKmn>ú»ďü?ßĹŕC˘Ý/Ąý«íŇţgpć©Í‘hűMźţřÍ_Ř{ŃĹóĎ˝äů—覱Ü ‘‚š‚2;ކŁŃűÂŃ'Źafv€Ů™ˇ0·ÂF‡`Č-×4 ^uĂËńsověŘ;ďąkGŹÎIŽ„WĽŔŔdŁźIJăv@Ť@Ë®-4Űý÷[xNgşćć`ŇLî Ňé[i»+ b[,/gĐD“g3Řm0Žp&+z$’W#;‘]Q·Ő`%ý,Ç »‡rmJ  ,JköJŐhŚ«MŁăV1·lźw×rČVnrŽ‚L;~ĄŚ ˛ĎZü]ű-ËQ«ś/ř‹E-q~ ňI`­m‰Ť@•M šµđo—ăŇ„fÇŤPŤ&äI—ŚXö›˘…Z<ÉiŹ‚(jKsÚ#wď[8b aŘ«ĚuUcc}k+«Fجí 1Ď> p uc鉯ČÔšfH`¦ÓV7 le;[2OfŘî˝Ę˛UĚăŃČ”4{Đ&í~›źlŻłZîút°<¦pxp )ÔăŘ[?B‹2€őʱËPJˇ( 3„§ŁnŞxbRźÖ ŞŞBŻWâ5Żx%Ţö­ß†+/{úei„·Đ¨°Ö±'…˝×śă ©˛óhnn‹ xŕÁÇpË-źŔˇĂ‡ ű¤TÔĺĘ˄ԽŃ]w†˝*ŠEßý†ssXÜąGúâ˝ű7˙˝ĄűŹv˙m ţÎ$HźŇśîwşóÓźş0ś˝ŕŞ«_Ěć*q“.<ĺŘöŰH IDATÉ"őł Ó~u˛tîúĆ&ßw+'N`ffápz­Ó6†ÔAĐÖ±™I =sÁVu…k®Ľ ?ýŁ?Žnxž8ôą÷nhg(#<ŕăÉ™Ŕ?ÉiprtžĐč)–ÁH§ĺĄďóŹsBxé1mŕ!†Á ­>}‘ńü‚t™Ô @şĚŤXN˝#BŮ+0č—č•*nÁ ɬtň‚eđłŕŮ2&Ăil†Ó0WU¨ŕ'Ż Í;ŞkÔ6Ę€†D”EîA˘ ;ó˘ń±4ö•{nŹšvśh4Ś{ŕkŽşÜĂÝ•AŇi)Đ>#ÔsKB3aD’5tÓř™đś‚Ü´Ű ŽL™d`÷3–ÜăRu;ä,yĎhĎ)*“ľýŰž§Ş®±ą±µŐŚÇc *¨Ąň—“ú¤ĺ-dÔ1Čb0tĂ ź#¦Ę—t®Ç_Ń&ç°eY€™1×hęʲ<đĘ{9xÇ·ĚI0…¤'ß[Ő˛Řěş[Qú~™:žč]‡]iń«”)iÖŹ+ĂśqµjÝ`cs„ó÷ś‹oüÚ›đ–oz#.yîs0;bP ‚üP*m™°YvaUúä˝ABąĚëŮŮ!v.-á‘G÷á#ů8Ű·ĎÜ;…ŠćZřű’(žˇ@â|’1î*zĄ›ę‡™ů9ŢqÎ9ôŕ}÷ŢügřţĆÝĎeţ+µót9 Y €¸çÎÇ—ŹŰwí Ż|ąO!ŇqVŃ#ŐČśö#SśŤ)ű XY]Ăľý±|âfgf0" 0ÉAĐá—yąui­1ŹqŢžóđíoz3Ţö˝ßÝ4řĚ>®Ć€Raľ{¤»¨rŢĆáĚ—:ăy')“˛™íĘ•¸+ŕNÖXä3xŽj_)[±uieş¬żŐźM䀲(|‹&1˘!)±Z9ž‰Nr̬›.fłCmš§»ÓŹ8A3ŁÖÚ”š¦x|†*NˇwácW#n˛Yżż•Ňc'„VéCß…ŕ ˝ÝŃ`!†/C±²@Ôž"'Á˘Ó`ŔÖV=€a1xHÎRHldĺLŰhH ‹>lGÝÚÚ‰ć8©hőş#xÚ;ŠŮB99ŽE¨FS×Ř\ßŔÚę*Şjl„Ž müµä¤_·Ŕ%n»3@RvŽ)0e•ŕcźĎ%â=OTd€(3Ű şi—[d˝žăV<_žqö´ó …٦Ŕ¬“AC’iěJŽŃŇ„j+~4Cp `·ß^CNp;Źqí•WâŰßôĎđ5/v,-Ěô{ Lţńt Öcß¶ęJ?D†>víZÂăűžŔ?t ľüĐĂĐ ňĺéh.*%gŃf#–TĄBŮ+Ń0ťÁěÂď8g'}ěĂ|ĎßýĹ{źţÎâ׍÷ť®ŕ&@JJć@€Ţ˙Ř#Gď¸őŁwÜřş×_ßźÎÄbń“Ř‹Uä\ívi@ŘeÚZýęę:öí;€ĺ•1˘žç†oŹ’ #r­ ©›˝~Ż~ůŤřąźü<ďąĎĹţqđÁŔ˝2é!ďbrxişŚ6 "Z¬¶ÝA;C2މ%„ Ó.!´É„ög×ńŁŚŁrF÷ĎtŞ î ú=N1ĺXÖĄLPÓ,ję©(K¶ŻůńĄ˘\7l‹r3ăí˛jTU¨ĺG‚®h?CýŃM ÓâáN%E­IĚÜ*‘Č„I´ËĄ3ŕ[űĘh ¤IŮ•\ОDČĐmŹ=LyDGŔ‡[¬G4 éÜz©XG,Fµ}9¬ĆeÚí ě~'/ÂCúľĚ?^kSŘÜÜŔúĘ*ŞqĺĎ{˙zy>Ú5ÎqZ˘f:ĽÍAă3r8*I0•žbÚ]pą óă™Ůz­ĐZ›úw]›ĺ‹ýôĺ÷YťtČ~żÎ"|źľ­Çłß+=÷µźŘ§CŕעÜaő'Žéж °Pʰ±ŐŐ¸ÂĆĆ:ÎŮą7Ýx#ľ÷[ߊ+.}tă4*€^Ď”xě]ď:foéěm¬­ýńÜě ććđđŁűđŢŚűîuSŰŔ›n9ĘĚHÉ ˛płTĘtĉ~ĚĚÎbni‘gććĆö˙áw>÷ÉŰ>e3ţŁ6ř/‹ŕźËüOéëLlÁhz4Ú}ô˙ţăW_˙ňçî>ďĽó4k&+çVďlŇ·ś(ŤĄxPÖöŔęĘö8ĺĺĚzŘŇC€‰ Aߥb\3ŁW¸ü’Kń}ßů=ř®ďú”e‰;ď˝ăĺepŃ‹´ ž*XN<¨g‘@Y*ÍwőI´G¤FýÎäËń`ň”±89á ń· °޵ö>uÓ |ĆĆ:PfxĎy0{Á“g ‘šČüµ вÖ.ÚĐŇéA,÷9ąv8Pe]3µw•nlEaK^Ä(©~ťŚeFۉN,—µ¨ĄÚlßq†Bo ’ CG4·FČľ]— '3čµ ° Ŕł%€µ5TŐŘÖ•}tŹ”é hTE°óďgר Ýp¬!°ÂFŽN`'t¤-ęý $R†őňz<’ˇ@÷ě#bARw>é¶ f…ޞ.ďË\±ÚcĂ- MP…Âx<Ćh4ĆuW]…ďřgoĆ7~í×áü={lS‹Yćľôú Ťa—çK%)#´?w,ÍcnvwÝ}/Ţ˙Âý÷?„Ş®Ěü áOtcˇc†5']–µ¶“˘g=ýg†ť›Ă⮝Řmîűí_ţĹßohnĂçTÝÔ¶»"0š…x/ýĹ€%|ÇŚŠCŤÚ;ĐuĚP¸m2ź·]0ľĽŕŽ»ůÝt!TŘŹqŮ%—ŕ Ż{=ľű[ß‚Ë.ş3ĂŐŮXŰ\1PŽ Pz Ź~ĎÍągK㏱˝˛ÄÎKöűřÔźĹßţý?âË>‚¦Ö6đŁ=őÂ#KL÷f’źËú‡łł[\ŕĄ={čË÷ŢóŃ?ůťßúCřťÁĎ €uüs&?§ĚĐSü•r€łž‡ń Ř`ÇE—^~ŮýË_ü)‚ZÜ\[ĹxTˇ©ÍTAó`,,Rł^…™ÎUťf‘\kŞš"ůň€ĄÝćqŃó.ŔŢóĎCŮ닚 &;Š{Ś·„„uKý!ŞşÂ_ýýßŕ˝ýWřâ§>i†•=QŞ`a”3ÉŚčvË›ä+@SňśĽA뵩űüółZďáî™-żîÚ#úśô±¸0á /†O‘|ˇf-…‰ůa7E®Awţ]űR]רk R„Á Ź˛ěyc+0nlŚ*TMmsßÄ~7ôHë¸(ŃëÁi]™6«hX0‘ŕ(vDf4µ÷Ż`o ̬8*aŰ8jÍeĎŔ±wäP‚VĘž‡˘,Ńď÷lŁóWĎ÷ůGmŔÂÔ'š ™L{#ę·Q‹•؇Т%ěöőŤÎÂiDMÍů 0uUaueÇŽĆćĆF»E”2-™11gEvŇŁ’ŤĄçc?~éŃÉ}O:Z„¬î˝^1ŇŮŘÜÄxÁ`4\f# ďqŚ8Gž§šč"O˝÷«· ŚůK^l5ĆZ•©ąj¤WB Í©V•ŔOeNdăŘĆđJH”uŤ~Q˘¬µ‹ç_EĽýőŐ%Š"$±* µ±& öJürç¨mŚäP ŕÇÖ˘V]ÚťĚcÜź<čŠu3ČđŚŚbj”¸-˝W’‹«±˙et߀Q[&§ 2 Ë>0 «¤cđ(ۧ‹˝\3:^¸µťßŞ5Ćk++¸uă†ý>an|ďŃYp°¦)$IDäŚ)š”tŔt¤ŽGĚ×5¨źšg b’DČŇĐôQqô]ţüdÂ1ˇC4P1íŁ˘śó|óç~(·?3Ć©1 0;=O<ó1<űĚ3Ř6ż€˛('1˛4Ó·_9 ŮÎ#ťSÄ#Lä9&{=tóLŤ@0)f ň4Ĺąłçń7ĎżŚÓ§ĎhPĎ­čÖĽÎÍN’ç#Ě•|tś)Ę?Nb$Y†,ĎőzrjfŠ]˝|ůŤ˙óúţ•žőß"˙Şîúű„ňĹ~ň˝(Îß+Ŕ1jśA9vL 0őѧ?ţčŻýćďüVUUŮpm]ą2•5d%ěËß°ÜZ»¸a““)+@|ÖávůÓ$Áö…yÜyçLMO±ČŇy͡B°…^šyʧ^fŢÜźk0ĐëôpîŇyüűĎ˙1ţ䋆+§N6€Ń"öNŔŔĆ6ľşXÓ.oĂâż‘Íń·OĘ-˛ÍźŹŢć¦fÖP"Αg)¦&@oż$tFÂkF“ěLvEd÷ǵ ®QéNš1†4MĐNcR*`P*+ŕ `łSM“×#ła1ÄD·‡Ź=ů4>ńĚǰoĎ ‡ő»„˛ŮM’ť40QVĄŚs •FG7Ď0Őí˘“ĺČňÓ“=0!°˙!|÷o^ÄÍ[·” RćnÜO­·1Îť~sBTµôúÇͬ_Ůů&iŠ4Ëvrt'z˛Ű›`őĹ?˙żżý—_ýk]ěÇuýtŢ_ż›”˙÷ ŕŢ(H6`‚Ó˙ôżýďcĎ=÷>±¶´,‹Á€UE Q© ×?Žs5"ŽÇ6§]ŮŻFVDbS™tŇ hqsŕś1LMM`÷;±}ű’$µn]ŁĂŇÓIIşde}G¤paÖ| X„^·‡3çÎŕOżüEüůWľ„S‡˝ 5&`A”l‹é€uę›xú[ú•m9čöĘ›m}ÄĐŔ24˙›8StüôDY–ZĘ8LăónUyK»^łšiúVµvR«•ŔŹq†$VŔQ ‰˘ĄŽîv.o:ű(âăD€JuXä¦IjU–‘Řh/”Äasn@ڱ &Ѥ~Ô/aHŮÉHü.±îŤ˘‰Ą5IňWÂNX†pT‘űg ÝÔ0aUÄrä˛gÍXŚPŚĽF —b»Ŕş*±¶şŠĄ[71 Ha§«_ 5özŕŘóS‹s%¬ťSş«łöü N:vH›MÇ Ň,Uy÷Cĺ¤g3î‰@h”˘‡ó`ˇM°Îş€4i5aú Yű«EŤÁp€ůŮ9|üɧđĚObßŢ˝jS%s›í ™1ĹdЇz‹ž'żA¦Šq/ϱc~;ćpăĆ <˙Ý—°˙ŕa”ĹP©˙#)9¸éô đCşdđę„]µVÔĆÇ?M¤ ŇĽĽ×•“3SlĺÖâ™˙ýüďţʞ^ŃŘőĺOçýâ˝*ţß‚'śŚa&50ńřÇž}ü—˙ńoţF6Ń×l@]VUm3Çm°P) /ĐśGtŢ7g.dČÍ9ń€wšÓ)diŠí۰{×t{=H0Ú<9FŮłÇm•\Ě˝]{“« Î8:ť×oŢÄź}ĺ˙Ăľü%~ů ď‚§‰Jó 5}Ę· ŘJÇÎ6 ňĂ²™fá6|˙ĺÖF›Ž:6 ť,ĂdŻ,K´˘w›Đ\8©kžŮŽôČɬn mźZŐBuż: Űm†JÔĘ×D˘z·5G\(@íˇ‹ZŃşĚubdÉt1Ś<~®xşżť±j5ń`Łc„P í˙wE:9d„áĹHćućĐLĽ4KĽc…t‹‡ůóňpŐ—š\Ú‡—)=GśÄŕ<ÖŹ=1C2ŕJŻ1–U…őŐ5¬,ŢÂp0pîcą”‘ľ†!p`[AŚž0âuďĄč‘®öýb=âRb8Pô¨ÓŕčLťFýŇŽđ˙;óřK%kꤨězĂ!vß± {ňI|ěń§°kLJ¨Ąkň3ă0¨Hß lI(7ĺGĹŹgÂ$9¬Úa‹ Ł?ęĹť§)&zdiŇĚFćä4ÔĆ/@úyq57Ô1•Ć?ľ*@Ú$żČe0<,JTĆ‹žŤľ$išç‘J3cPŢófáśhŘČz hK8! ‰?Vćn^U¸ŮŐž7aX‘ľ ĹľEVÄXWzÄ ;_şVÂ8›ů"EŚP˙ŁYŢ|śIŹ©đ`™é2}űâD'Dr·­BĄŽ¨°ľ¶†ĺĹEĂťÁî};ŽE‡Ű¸n¨„EĘIŇü[đ3 Řţď ‹6ŕ€$Ž‘$C’¸†1ľRޏ0Ňß'…ˇÇëZmJŐµ¨đĐýâ‰GÇÇs33E“Üđţč)Žc&5ÔF@ô!q†Ľ“aŰÜ Ö—přŕaĽzčµúaS`ő&¶!Ń×uHHnŚĆ•ł Ń%I‚¤“!ËsäÝ®śš™a§Ž}á_˙o˙Ëż#˙2éúűĐŹî÷‹÷şđż_@Ů€Dł)Đ#c©É™Ů]żűßü‹8ż}ç=«++˛ YUޱ€ZÉq4ŐýGŽ Łő˵VŔĚEÍ… ĽL=áQ’Ä›ťÁ;095Î#/ Ĺ(¤7"0Ž0†&Ö$MŠL«xżűň‹řę×˙ _ůĆŔ•“'€îxB7 FG[›ăŹn(ôChŔ?{#@Ŕ7b {€ÍG¤I˘\#©"śŤŁÎĂ.Ú±GFĘőlS*ÝEŐ'4š5a&ô⫲p+ŁŇéĹÝ’ŽÜŘďŇŃ0ĐßĹ#ĺ|Ć$´˝‘/şÇšjčÜžŢĎŃ}`Î|·F›ă@’sađŰČfłőŕć&Đ…[¦żľŽ•Ĺ% ‡CŻsíŰÄ?·¶éŚD«`Ś _m.÷72ěüĄÇ6@otPŕĹŇÄŤĘŞn ^˘c j Ľ˘ďQ™ď/†Lô&ńÄŁŹâ‰Ź>ŽÇzP”…·ĘWG óY& ¤ÄP7}µ"·=;3Ŕ‰c'đňËűqńŇÔ˝ţ‡Ńk”tĆöyáüć,#EÇ€śsed’@ÓIš"ËsdÝ®śš`Ĺpxăsż˙{pć­oꂿDćüMł~ęé/ľ…˙ýÂßOA@¨ čú€iť˙ĚĎ|âłżňźü*ëö×ú˛*†¬*`.ZjľŻFw[\Ç +]€žărćt6Ň踗ŹNsň,Ŷmsر}yž+WDąE ÓŚą(ѸĄ¨ˇ‚=şť.]˝‚Ż~ă/ńµoüžţ»@UÝ®e@5‚•O)%ł.eqø)·3ŻöEyľÖÁwúŻ<}éJ¤íuÚś Da”?gÍžž:IuJFč(îPl G˙űj@ďgĘńˇ/Ň ¶)@ĆvRŕ®ö‘f  TľýýaTU…Áú:V——Qhŕ-捬é s]5ĄŰ™ÇmdÔ› Ü@|ń‰ÜAÝż$It€aŕfřÖ­ĐŹ– kÎܧVZ‚şĆGî˝O>ú8ž~ôIěľăô‡}­#anˇ’?k.!ŔÔ#IHe‰8âšžŔDžáě[g°˙«8öćIşVë~śYVŽ^«G6a¬‘ś$„š{^1ˇń‰PZ‘qś ÎT„´ňńź@–gőKýÍ/|é˙ý÷_ÖEžvük¤ë7…?ú˝ç”˙ű „·…“÷ń&cĂtĺţ“żóěO~úçŠAÁ†ýuTE©hŇŞ¶óxÎÜhŔl Äv{@+ą9Gd,!uçoőÜĂ ŚŽ^Żm łź›Ašĺ5łf ’Í‚ţH@Sp&3IĎ Ě¸"OR$iŚ—_=€o|ç[xî;ßÂŻîâ,Ďȸ ©~7Á  vÜÇč6b$6e <ęŽů_Ó"®,MŃëĺČ’Ä7u슞#ű9™C2âřA˝mbă>‰!Pm˛ «M0 ®%ŠZ1łÚ¨vŤ]÷! =ŮC)+µQgPĄźJfFo˝űĄŚE˙â>âÇŻŤ‹‚Č_D¬ŐR µĹ“-˝ĆčhxÔľ´Ű !«áł14%ĐędhM>4OĂčÇ™seeV„˝, BEK-ÂT`e1Ôq»Ô6™hžó -ęt,@ŘC ˛6X[v‘x oÎg%bp¤ÄĐĚĐIRĚco©Ť©:޸D=`÷Ţ˝x⡏âŁ?‚‡ďŚ1”U¦×ůĆ炎Rˇ$3xŻž»Iab˛‹éÉ ô˛çĎśĂý‡pđĐ ‹ˇbá"€ËH©ńŻe€żĹEš“P «üŢ톏`ăXíó'Y‚4Ë‘ureĺ;5‰Ł‡^}îßţŢżüS]đ—ćü¦đ‡ł~ŐÄ÷»?4C‘`“>`ŔÔ?ů/˙ë_üčSĎüŘúÚŞ,úCVĄLiËGývvŽô*ˇJ.c6ëÝhĚX ¦ĚÇ|ÝtEŚsLö:źźÁÜÜ Ň$CEŠ‚ߢ@Đv/ĆžüŁťŔé-çYžCď<˙|ý;ßĆsßů.?ä9X–»UČŰز plÇRýŤż{´‹o Ř›ŔĽ‚Á9Cš$čuő€űm§'Dlč:-‘ÜvܰHäďc5 6Ô÷qíFVKl»9źžM} H…Řy2i“ëůHIöp´W§ĎiŻxKXĄk …OAăfť™Ń0h÷Ĺş®ěŔ‹Qa ĄŔUHĎ ¬pĐ€#1ÂzHHż» 8©M!Né_XWÖV–Q…ý[Č ÉI„ď–©Ý_§Łc†»e@2á9sŠ $Éxčűë‚j%.‰ŐÂďu IDATÉ„éH!‚-7PfDeYA YXŔÇźzO=úžüčăHłTíăjŁChG=Iţ…G7=Ýץ?ď‘zż“%™žÂüĚ$®\ş„ŻÂ+^ĂĘň ˘8ŇŕR…°KőÚük„ô3d¸cŚ}]+Ş_~•Ú—f™)ürbzšť;}ęŕ˙őżţĎź+†Ă«şřŻşźŞű‡Ý˙}ëú߯`#6 i,ĐÄLö&'¶˙ö?˙żş÷Ţ{][^‘ĹpČę˘R@@Ejy@€úC!E*R3 jFČÉ,™ yŔü»ľćĹ7Ńë`~~słÓăU%ěZˇé·"´*A’ˇ.™ ŚńčG!ć ť,ÇĘúľóâóřîK/ŕů—_ŔÉ#GCĐÉ›¶ŃŠŢíwě[žőc‹Âľ†żO ó ÂY„4ŤŃíäH“¬r¸F’Lšµá‡j°ŐWąÝ`ÚCś[vČ÷Ź×©n$Ëś›µT¦@UŁ&j~Ĺô°‘ąľéÎŁ(¶F+´Kg$÷‹?uďy7AĆRş'´zş əŠŞ(űť5ĽU]-Ň5]3€©ß!}ĆÁ˝Ć”Míp0ŔúÚšL˙NF iŹę %„ľýBJ_—ał„÷Zö Ľ{ďűM€zÄ©U:)%Ęa‰˛.Q‰Őp”%îčA|â™gđěÓOáăO>…n·őőŠáĄzsCč ş2>ý$˙B3ś&¨Č°LŤ+~š©‘RŤŃz9ćç&1™wqúôiěů öżz+«kHb7’纯—ÍÜţÝhţ†]Y5Ż ˛6ę ăÔÎřö'i˘]ü”˛bzš-ÝĽqţ+ňGźýŔţ×t‘§3ţµ đc ˙ű˘řżźŔ¸±@´> ‰čîŢ»ď®_˙íú‹{îąűáµeę˛Rv§u ý<ŐbAŹ[­@ěč[é÷f4@7¸·î­8ç„zŐkiyŽ™éćf¦‘ç„PQ±B¸îR_Řh<2zléđL?Ŕ$Ëŕ4˛,Ź8~ /ÜŹ—ŔË`éÂy=6hŇŔw“ŰP7°ńčŕ¶3——뚀Ӡ›gH´3źł„m˛´ ·*‚Q€Z}ţółF§•Üf Î ˇt!e]Ł™¸ťM­d:˛”Gęo/\p«oä…2ş÷ç<űG^ZÁ*|›Y#tá>Âů„ŕN;§y"x}× Ëh«X)Ç üF9˘§6ŔYŘ,Ă4@0ŮPŚś™‹qt´&@’ľÇµ®+Ă!úkkVĐČ´ŚŽŁ[(Đy@ĆĆ,G g/, ĽîŢ‘ľ‘Ź ©ŚĆiúůhô-ĂáťNŹ?üž|ôQ|ü‰Çńń§źB'KQVĘ—˘®kÔĄ.ôum {]ë¬SřÍ×ĚČKkEĘĘU±P篟7yš`j¦‡í3łu…cGßÄţýńÚ‘Łč÷‡c®\S#=*u‹úĐŁ‰±ľtCŲ~zÄ«hţQ¬vů“4uľýyŽĽŰ‘“Ó3ěÖőkçżüÇôů7xM÷e]đ©}ď`9˙÷\á˙AM@ Ü0–ÂMŁIýľ»kĎŢ˝ďwţ‹_Üsß}Ź8 PZS&M¦µëöÍŔ#-ć2šF,†i'č¶Í´—Ľ®I$iŠé©fg&ŃŐ»ţU­:Eo¦Ç6zFDšZvúCIzK‰¶ÄIŚ<ͱ´˛—ěÇË_ĹKŻîǡŻĹHs0ÝAŰâ­Ť6ßhôó'‘»Ł_»=`&1:yfťůÂŰm®5žTŮ Ł!a8z `÷çáö˘Í\R:łmpí¨#Ié^ľ-tĘÍl‡b4n¦ â{ĎFVvČJçě–ő0wQzÖÇF­Ţ¤n ßŘ]1°ě WăTŃ +˘Ô4.#"łĎoĘ›HmĂę]]}# ›á^nTŔôăkóĽqšˇ¬EŤ˛˘ż¶®®´ŕ{É›ÂÉĚ$ü™Y˝Gď»ű#ČÖ…çĹW­őD¤tŐÔÔu…Ş,)qĎ˝ÁăŹ|O?ö8žxô1ěÚľEY@Č×.“Q„8VďÍJÔŠâ:ŮRآď3 ţfL 2 €3ôzĚĎMavf7o\ǡWăĹ—^Ĺé3ç „Pă4c—­zµ{Ź"‘íÄ؉é‹,$ëŃNÍŻĆr:¨'Šg ’$EšgHó ťnWö¦§ŘâőkçľôGźűüŃCŻŃ~ĺ6 ˙űŠî˙AMl ˘BÁĐQĐ0 ÜąwĎúź˙ÎĎŢýŔCO×Ö1 ¬…µó™Vî0 ŰuŮÍkýŞwş +Ŕ©—Ý$pqÂŚq·RŇěżéëYĚ9şÝSSšě!MÔ(K­qB#ŕă‚Ň{Ń8·BiŚV¤›­Ę H%b i–"IRĽuę$9„Găŕ‘#8ňúa ßWLA’xŃWŰn<>hbš ů8q ÷=Śůž€Öô#‰"äyŠ$Ž•ŢŢ®®‘oşI+MfÝÔ.ÚćJčÔe_.í,׋prq3±Ş®m4-Éb°3}WŕPEÚŘĄR-5y|ŔH—]ćQ¤˛á:Ĺ$5Îź7ŽŢői7!ŚŔLŽ)®t”EµŚůúIştjäĹ#ëą2:Şó6Č€.©©ecLÁ @˘·SbX`ĐW@ęAľdę˝7Ě1îę‰.€J]T2/ÎJ×€ ős%ŞŞF]•îÜ˝÷ě»÷í»Ü{?>rď}"u'cu,’HŃÝIÄUXS!N"ÄÚÜŠ®łVB@TŁ@ ŇÉ}.»FYU¨kˇ”ű˝¶ÍMs†S'Oă•—âĺý‡pýĆ Y¤@±ń€âÂBŔ™?ăđ4¶ů˛‚nĹňđXéQâ$A’Ć3-îS?&¦fpĺâů7żöů?ţ‹cŻ4…źŇüă hć#ßĎĹ˙ l´- ›Ä‚ tă8ž˙G˙ěżúěGźůřŹ×eĹŠA_–EÉĚh@etK’3MtL» S!g.Y‡Ap†Čř P—Aî”Ý#@µK–Ę5ß$Ť19ŃĹôDÝžbĘRÓmŇ]Ć =ŇÓ0Ň™`Hć€Sł"/ńJˇę(Š‘&jNvöüy:r‡^?ŚCGŽŕŐ#‡P/-i ¤©ĘbĐ/BŞlĹjă%ĆYŹc š·”:KSÄFđĹ<÷}˙cškë±îöP çŚQUNFÖ‰LoĄ/š´űőŞwŇt2ŇĚâuşť™±@`0±ëëé8ad‹ÎÓ0o6Í6˝˛0Ęe ¨1DgďŰ8WM }Š3˛ďł3DŽ9‚2;^F6-HZŁHŽ-3Y ”EÁ ALŤĹOŁtÝ+NJźE±¬‘ç}ď¶ĚO©E­ÇUUU Ä öÝy7öíąűîÚ‡»÷ŢÝ»î´=Dś¨ëR’DH“y–"Žőz3cŞă×]Gp$f©q•ťík{kcreŮ€Z šň,ÁäDÝ,ĂĄKWńÚ‘Łxĺĺ8~â4úý5; czťÚşńmŕŻbúqÖáóW˙\*č‹Ě.G'*ˇOĎ÷Máďôşčôz8y썗˙ě˙ő_ÜĽ~í<éř×7÷…?ŮPüß÷Ĺ?ŕ@ ôĆĘ ·îŻüŁ˙ě'źýä§~*MłŢ`m]–Ă‚‰Zĺ Hˇvaí…Üx hvŔ01âĆ!.â¶ó7ADŚdĐ›Bŕ´pqîşX=λ)&»=LNäHł eYˇ,kÔž3ŘćAçć< l¶$A҉Đő-ŁSGš%ČŇ WŻ_ÇŃăÇđú›GńĆ›oâŤăÇpęÄqeV+`Ŕ-Ú „ÂŤ´ÍŠwóßRŔ‚Ľů‘äąĆ÷íŚÚH›Ž‘¬S™-ă+ÁŤ°’1;/µ«W >ýĂÝI(öB¨OđÖň¤s»ó§ýáĆ]Ŕ–l~i0á0R†×9gMEtőT açĺÁß=·]áŁ˙şc¶‰‰Nßbr2 ç±# ó3tăcĚÎ…0r7 č…Pyň MR›:(LŚvî°Ö˙fö/Ľ‚ožĐť}YVęµ"vŢ=»öâÎ]{°w×^Üą{/¶/lG]W(kŁAž–éŐ?UČł,Eš&H"5ŹŚŹ#'Šb’[ kăŹ_U†ţWŰ+BÔඣ“Ąčv°¸¸ŚŁÇŢÂoŕµ#DZ´´¨Ż7jă@Ô*ÁO­ĺaC@E L eŢ“d©-üy7—ťnŹń8®ß8đĘ7>÷űż÷U¨xŢ>Fwř7*ü"óăˇř˙ €đ~„Ś@Č @Á@ňéźýůg?ůÓ?÷S ;wÜąľş†r8°†BB v»Ëv{€sCěĺpç6h(`ă?ŕk8é>6Ü^¸ť_ąRy–a˘×AOűÜ )QŠŞ†¨Ą—R¶ ™ëbŰL ¬8‘¬k™ŽQ Ţâ+¶ Ipćü9Ľ~ü8Žľyo?Žă§ŢÂĹS§ÔĹ.I,c@ †ßŮ7i 43Ń` ěo0$Ú“^ĹóÂËPđW„šoĽ@R˝ >1l¶uz ŚĂžđ÷ýŃ8Çg^ŘŤ$ݡ×ůŇfť‘ÁŇŘŤűxť¬_ňGŠY{4Ć:đőŚôżS.›ĚŽHLŠ›—ü‡q—Nż'wżÜĄ˙QC„ Dú]żŐZf††Á8@Bî—f_Ş˛DQ Q뱡$ă4úň;AźUčו¨€Ş„Ŕě¶íصóNěąăNÜąëNěŮuvíÜĄ6*ő˝v¤GÖEÍÇÜn˛0űxp®L€Ň4A–&ÚěHÍäy!Ť#í¨4‰É­H8ŇČý[1 ˘(F–ĸµ´‚S§.ŕČŃ·přđ›¸rí:D­ÖÜ…śÔUˇÇ[d?ßĆ‚T3ĘŠ1ąľŢŰ×`†vűv•/ĎçąěÍLłţňĘâţżůÎřĘźüŃsşŰ§Xř‹ ˙űzÎ˙aăP#@€Ž ČvíŮ»÷—ă7˙öŹ=öl]Ő(ë˛,*VWP;´ˇ"#Ćྯ€?&p›žpĐ&2Ëp<0KC„FŔť,AŻ“Ł×S+oBJTE…aU+P &\q=~ł@Đ×XáµÓű\jkě< 8Qßö8Vö¤IăüĄ‹8qň$Nś~ 'NťÂ‰S'ńÖéSXżző–$dÓb+ŕ`”9#Ž4M¬żC“âźŮ }ŕÇ ;_yŘÎß>†f3„ą1Đ”®óvpţł&Ţ—‘Ż; Ăřľé,`|Ččbä…Ţ`ÄŢćĺŔ0c®{T;2#¤üČ-0!ZôvK)<]ŁÚRdp¦ 2HŠ ŻËľ3źc)Âŕ &ĚEř )PWŠ˘PăÂŔ›źć(q\ QU@]!ęt°{çněÜ~víŘ…];vc×Î;°sŰ šfŻ•›ăÎ!”¬4†ţË,Ô@ÉnżÄ1˛ÔdR¨ÔÔ(1?ÖLŔăI!M"diŚ™ďÓn˙Uř?`«ŁŞČV cĆćí˙îoüČ'~ňSźš™ť]X_]•eY2ˇ‹¨Ôł9PO¨'d¬× Ť—@‘ â!Ďí|Ü)Ę™ö#w)…›Ę Ŕ‹ fCž%čä)şy†,SžçeUŁ–j˝ösĚŮfAImXťq‘‰"ő|ÔĚ\ÜKW׺*fÓ­3  ‹ož| §ĎťĆéłçqöÂ9ś>gÎťĂĘĺKŹ€(Rŕ ŠmvŻ7p+u‘އŽyävI±—dá{?r—ζm·-ýą®ťíęQ#ßkFr¤łfÎć™\Y8RĘćKNă)ĺG†P }ŤŔm\1h‚ÜČŻ…Ó%pÚˇ{ĹÄ6ŹŤĎĹŹ0ţÍ—Ţś_íä3űOŽ 74<ófő–NaĹ@ żŰ­ŐÎuQB µöńP”}…lb۶cűüvl_؆í ;°sŰěÚą˝ TuŤŠń°‘żQPĐ˝dŘńFHď FX*F= µŻ®7‰Ž6Z fźóŕĚuůĆśÍ$ąę1…‰šŽR•xd ŇTĎ÷»ąěNN±r0X;üĘ+ĎýéţÁsu‘o*úM…żţ ţ2ŘŠX°I05h +|ä‘Gďűů_˙űźş˙áGž.Ë Ĺ /ë˘du]Űđ!e.kBÁ 3 jĚckAěČş Ú'·]-tęUF“ ­ďůF@ý'^ďö=gŁťžšśÂTo˝n×zŐ ëW_Ű‚nuă92¨P{úB\˙±ĄŹy’í¶Ň7Եٙ’cV8gHÓłÓź›Âö…ěŘ6ɉÖÖÖpćĚ9~ý8^=ô9†ËW®`8ę׿‹8ŹâD±eq‚8ŠĹ©*ô€H‰]ÁŻ!e­;} ôÇBŻ JQŰ‘€Š€–Î+rżQďs-JŚâ¨±č+oţLvş=–d).ś>uäĹçľţÝ—ľőÍýş ÷.źýŰéö?Đ…˙Ă šî{Sú Í #Ę tŕoäŇO~ögźúáOú™{xđI!‚€YKHQ[ő·™ sĆF,Í6AEÖJV­޵Ď…ĐřZkbSL¸çJčB~¶¸Ł)íżąřcĄŞEÚ\$âBÖ(ËŰFQUÚ§ RŻ0!˝K%Žv` ŕ“ ~ś˛”._ŢFĄ†WöR—ÁWBGćk" c™śm`ÎŃ_ďciuË«ËX]]ĹňĘ*VVW°´¶ŠţÚÖCôű}¬Ö±>`˝ßן÷ŃďëĎ} Š!dQeÔ•{şr8˙Soći5˝ÚŮř+@´Ľ‚\E0·—¨k+ĚDś Mt:tňyŢA'Íg:yyžŁ“ĺČóY–ˇ“ečőzčöĐëö0Ńë˘Űía˘;n§«~e­DhµT¦<µŽ®Ud›°F;ŠŇ›‚¨ĎĆš0ÉźB¸ÇJRż}ąÁCę)%‚Ń5_bú¶«Î>bicj˛ůŮ),lźÁÎ…9,ĚM˘Ş+\ştGŹż…ŁGOŕőŁ'đć‰ÓX\\DUŐŁľ"´¸ü-€8µëtjŁ)FE¶°×uPü­(PmČÚü]*›6ČČ<_‹ř˘ŘëôŤćŔšő¤ Ň<—y·ÇŇ,ĹĄsçŽ~éů—ľń_|)čî›Ä|EC·O­zâ˙ˇ(ü-Ř|<ŔXpDŠ)3H?ýs?˙ôł?ń©gî}ŕÁÇ…”(ú}YW•f|9E IDAT„ňó–®Sö¶ 8ó#łJČőŘŔ‚- dn%†Ń9?hV·¸şaî@j‚vß8Žą ¸Hm‚3,Jµ…PV–•ö+Ţ$óéF ÂXŰ€ G” DČ`^úłcG$Hşđ`AФ"6;‘6Ýśtďˇ3ťd:ŚĘÍC9ÝП̉%$ĘaaY(UU(†%Šr˘,PęŮ´qµ¬uÂśÚ(ʸč7󳹉Će:M[VGĚůUp]@’$F'jn¬•ŘI’ ŤS·©錰®ÖĎw{[ Ýŕ ;Ę)¬RRP¨ţŽ‚Üx-0—!Ž « †VđXFZ}tíÔ(đ}Ő‹‘@o M4fEq!ďdź™ÄüÜ4¶-Ě`Űü¦§z¨Ş ×®ßŔÉSçđÖÉ3xýč {ó$®]˝†őţXŚűż&||»@uű ˘(Q ŔšĹŞČk ş}UřëŞÔ˘IĹ ˘/em_g\GíFQ¤F&rWű„Äi‚ÔtúY&ón—Ąy†ËçĎ˝yřĄ_ú«/ţŮKP&=EPüA§żQŃGóh  ¶>YP8ŚŃ Ś€ĎüÂüôł?ńÉgîľ˙Ç`8ěëš!„ÚÍ׳qĆŚ!K´Â‘ŹŤ¸Đ€lbFcÖ Ć"OĚŚŕ ĚšŐĽ`TÔÖč ęc)śE«Ç Q!KUîv’hĚ%•ËšŇTjśPŞNÎŽGrÚÇAâS)Ç`›\˛µŕŠ·»¬{Kˇ;"݇lŇ5Ľ›~ žjŇĄńŤŚKÁZ€éţ™DHÜW©x¤É´§"LSäΑč`ˇc]]A$÷]ş\©Ç+öëdÂh&@kďö™D;Ĺ? ŢńY÷»ĄëćeÓ2¤·ńçgŔfy›.&šW:¦Hč‚Ď Ç ˛,ÁĚô¦§'0?;…Ů™ ĚÍL#ˬ­­áŇĹ«8qę,Nś8…“§Îá䙳XĽµ„Á`ŕ‰äěó˝©ČKé}ľ)bDI˘‹{3P+ĚŠ’ç±×Jaş~$íú…´_ŐZ ą8¬'Ę™/1ÔľvčSa<˛Óë±$Mpőü…Göżüň×ţôŹ_„˛ä-¨ýPÁOwöŰnżďĘx`Ü`+`€ŠsýyňŁű3Ź}â'?ýä}>ňxg˘Ű®÷Q•…2éˇĚ€öŘ63xS´­%±Ő D:sÝů p-.ŚX¤‡d»€‚ Uä#Űíy¶štt`»ÔŰtOÜz§›Î$ŽA»őismăÉ9$a#EQ)v]Ł,\‚„żf3ăÇ%ÉÝŁĹjDĹE­ČÂuúĚčŮjŕR“źe2`VĂ_A@ Í}h—HŇ›ĚßÍ1ÄJţjźW¨Éý´qąVřçß7ŹA!ă—=!m€+ňŚĚĺ}°ân‡[AőţŽcŘ˙÷Q°/)|ř s!Od4"¬…oqÄIŚ^'Çädł3S›™ÄĚĚ$¦§&Ŕ°¶şŠ+Woŕěą‹8wáNźą€ó.ââĺ+X[]GUŐ.]“&wš˘®©ő™}7@#Šĺ ĄŕIä€fÔ¶Rě@ŹlŃŻEe;|H-„ĐÍ ěN?ă°[O1ˇ÷Ó4E’gȲťŢ„â©Ӈżňâ«ßţÚ—čżhýAC—oćúő&E_|»ýĽłÇ‰Ť6m1A2 Đ·čŢÚ÷Ů_úĺg>ňŘăOĚoŰľ­č÷Q…¬«ŠIŁ®8Тvç `‚Št×ogŃANe"ş^hnήAÍômz!gvĹĐD˙:ă"ě·ß& 5Iż×¤ťéB)„]KĄ3Čtˇ>ŹěďŻęZ±e‰˛PŮEU*㦑HV—.Ăô€Áßb;Ô‘B éŰ€Ůb#™mÍOA’ä:Ź1 2ú)¸NKBĆ÷˛ą3Ęl‡; ą% DC!nb|™ąŔ"Lý$ĺߎ@‚pŬúŹ)up”’)׼$Bž¦śčbb˘‹iťĐ955‰^g(Š‹K˸|ů.^ľŠ3gĎăüĹ«8î"n-.Łß_WŔŢ8"’±–  !´·)ú·ś…¶ÍĺLŃďj·?Ž"đ8E¤@DG±úšIĐăW?GŞůľzĚ\SmF“ň§vöąőăO’i–É,ĎYw˘‡Ő•ŐŐł'Ž|鯿ą˙őŻŃĽCí Bľ0~·)ŤŻíö[đžŤƉCłˇŤŘówz żô÷ţÁSŹ<ůôŁ{öÝý€P ‡e©‚Gôjˇe…¦ +"ˇE0#łnh-е"=bľăľm±qçR BwŮDkŕ.ěŇ^€Ţ°9čÂt@B˙żîŠ4ÇJÝô’8VĚAš Kc% JŐýgÚaĎÄ•QbQV¨ę eˇ3ĚmŹ$Z„@íeşzJ•3Śę$Ŕ¸á‡7 \Ň…wK~ f¤@hsřDŔź‚ l\aGŘőKÚ%ËĐô1`ÜÚ'˝on$ŕ§O6˛Áˇéľ»ŰA3* đÎhHZI Ú $bĹ+±j’&ču;Č;&{-:4ďsÄ1G]ŐX][ÇÍ›·půĘ5\ľr/_ĹŐk7půň5,/Ż ßj'»l°Vv@Íżc`áţ– ń"c QbFz'ZíŻ=ôµŃNdÖ˙b-Ö‹MěµËĽQk|°Š~ăĹ{f=jO?Žcܸ|ůě©ăÇó/ľđĘő«WÎé»1hčň›¨ý&z_´ ľß#‚ŤÄ „ě@: $âgü'ţáO~ęŃ{~ř‘…m;¶ĹĹp(EU3)”JjRÉO=ç4ÁЉ9#ĹQ°‘őŰv«‰.—Ţ|nv•ÍčŔ›Śz@ŕÝúcs—­ę[g¬K· TP3I˛zĄěOc$©Š46@!KŐžłqYR@TŠQ¨jˇABĄ­“kTUŤŞŞl·%Eí[óč6TP±˝ ,jě#wă—2p…™‘•±&?ČŐ¤2(@S$]·-}e»-ÄA¸”¤Ś™âŰĘ@řg¦čŇ&”%pWB5Gę9š&Ęż^yWdčvrtňťNŽĽ“Ł“ĄHÓ`UU˘żÖÇâň2nÜ\Ä­[‹¸~ý®_ż…›K‹¸~}+«k‡ x’?Ć<¶Ąéą;řľ+@ă%ýÂAÔ° jFŞU`\Ť,â8±6şPÄÎq/2GDGçĹo»}ő–$‰LłŚĺ˝.Vo­ś?uňČáW^>üâsőšîěËJü"(řŐBľ˝ ŻďO˝ÇřŐBş^Ř4.Čn fŔô/üÝđŘă?ôěŁűî˝ďá´ÓIĘţUUęqŮM&"3éAڞ<˘22p!FÜ0§'0*pĂpĚmëdFiV÷±ˇź…îH=«áwča/—ÚĽĹ~.€Ú|/QĄ ŘX­FGę2FŞC’&ČSEgF‘ٸ0–µŇf˛+ ,X(ę ˘¬µú^…ÄT•QK›ë6UĂôxÓç^ ťţ€aDŇ@ÔńbôgJ/¨ÇOúC0:Đ0‹áIőm–;‰ČŽu§ibiÓ$R.oY¬éăi’"ËTT˘SUĽr…ţúkýu,/­aqy+++X\ZĆâŇ VVÖ°ĽĽ‚ĄĄe †CµAjŮě=XŇŰp…]ă­÷Č‘®_zŕZBzZ; 1 Ě×;p®v퍽oś¨-€8V˝(‰‘h€úžX'ŞŹyDv÷ÍvOË$IXžwPË—Ďť=vâČk‡żţĹ/Z[YşL¨ýá9~Ń@íoE˝ßvű-x_Ž€&aÔÂqA(Hđ»ďűČ]?ńÓ?óđŹ>öŕî»î~ ÎRn¨j¦úń (ĹéFF ă(Šô×ÝZG‘3#‚—Z6ę„"›âYĺxÖ@Čw¸3 C‚(ś±a-¬řK.Y¨D8ٲ‘Ćś« *ç*Đ€‡Ä¬ÉEÚáĚDŻ2iGGâȨVőôşśĐáAz…OÉB”ŻD- Ň aév©çł‚ÄŰĽzéőĚaY@#]'¶ľÚŚŠýID®Ff#…GĘî:NÔóÇ='Ôí­¤@]ŐĘbw¨ ĄV×ÖŃ °¶6ŔÚę:ÖÖ×±ľ>Ŕú ŹµµuôתŞBY–ڜƱ€ol˘‰ŘRq~Ź5"˘ÂKűz ľĄö=s,Ęś8 „o÷ ˛I°(Ň»ö1â8UĹެáif Iőµ8Fśj Şç/Ź"ÄI$ă$ayžCBâęĹ §ÎĽyüŘď~ëőcŻ<® v9f†_ڎőÍ<ż"´~[ô[đMěŔ8@Śd   Ŕď{ŕˇ}?öŮź~řÁG{ŕλî~ NV ¨ĘRŠZ0iňçĄ›Łšy1‡od ‰†ŔŽ˘ÓcmŰi p¨mmhaę”XĚÍ©ÇuźŇwŠłlă÷˝k®:Â]á5@đŠ,Hâ?ďYeąŽ–Ö&>LÂ5E1S3YٱăÇ Ś°2q¬ŠjĚ™^Őâ^´ŞË`Ţî¸M›ÔĎN©Ç%v/ż6bLa‹”ĐTE­72̤¬j]€+ýą2‡©*SŘ+íűP`X QUÂFßÖµ°ö»ÂnjŔË‚ ĎßţŮţi¬×€ůÚ燓űż/$aaČ #1VĆeb$?‹¦t‘pAÖ÷ĂŚî¸ä%±Úą·A?f%/‰§©Ż©ű·4Ke’f,ďä`ŚáęĹó§Oź8~ěŔwľýĆë^>F(ú¦b? (ýq´ţfóü¶č·ŕ ă̇’ 4! đ>účÝ?öSź}čţ‡ľ˙Ž;÷ŢŰťčeEQ ,†•q$Ô{ÝÖś܆qNŢĎ%Ś c`W µ.H łIÝł*w—y.‰óŽSiţđ2č|l7+ő·Ô®pß[ íŻ’ŽĆ5*mif¶úvŘďő?V]ż+"ĘŃN8qža%îA@MßCĹbB’Ż“YżÇÎŔ›áŰŰBţ;Fż08î¶řZŤŠ¨úoĆďđcs˙\‘ýIž'ć9c|¤ôD«áĎ53|Çh‘„HPýŕíi2çši"m61ö2®˘‘a`¸Vń›?IÔţ}«•Ľ8M•Íw–!IR™u2–w{¨Š7®\zëÜ©S'ľđÝŁŻ˝ô7ÇH·ľQwżQÁߨËĂwڢ߀, `›hšŘh@LA šžžŮö©źýŹ>ňĐOÜ·çž{ďݶsçQ×(‡겒BÔĚŇn8‡B8·8NňB‘ˇë2™›ď"XÔ- #{4 ť®m1˙Hôn~ÍČ*śąí˘A@A}oşÜ÷ PĹ€G©o‡°ßi?– Ý¦éÖí˙Ř…Óřď»YóćĹP6j6šV?i1ßř{ß§@J6ĄÓ¤X—C× ÚÉ 'Ć”Ä6Y2é­&:Ź éyHňd·ŻFŔ3ń 0ľ{Ż…ľÄ__)ůu@˘ôĆ„'M3$yЬÓA–fXYZZĽzáü©SÇŹźxĺ[ß<~ĺâŮłúÁ« ý¸ů}ű­ü¦bßý|(¶Á[´ Y Ćű}?üÉOÝ˙Ô'ţÖý÷>řŔ};vÝąŻÓë%U1DQŞ/Q ;‡dşkńo¬oÄ™KĆóŠ>ś‰Č:ˇBřÉ„ôa˘GŚă§9dÄŕ°;őgŞđ:ä¦nŘÍi]‡Ý€<ŕ3&Í÷Ůx!oÇdÂgQčľĎ˘Ś¬”ÂĄzÉŚŚŇřD(imľu ÖčÄWf_::7¶ďµŞ?V˘ľ$MĹ ňny§˛(±xóú™KçΞ|óµCoľđŤż<ĺşW“˘ŢTě›{[)řăhýV˝ß€öďń6‚Í+‡$†#„@Ôíőćâł?sĎĂŹ?q÷Ţ{î»{çîÝűŇ<çUQ(§ÂZ[›‹§p‹]LŽ˘ŻŚ ŚšI/Â0Ŕ`íj9 ŻšôJjR¦ óĆÔŔĆRŞÂ]”=v  ´%±2BŠx9âeOż_6Ľ$[4‚é–^wĹYn "(ÔůŔä6Čŕci»y ̤›ëKAWčč9f‰‘q(0$kw ˇ ‘ÓzĐą˝ fö†Ć÷’>c]řŁ°ĂŹŔcŽ8Š˝$=+%'H;9Ň,EUVXĽ~ýܵKĎś9qüô«Ď÷ÔâŤëçIˇ.6 đ©Ż~SÁoRęפ¸7ĄěµEżíą vhÖ4‚Đ("€`#P@Ŕççvü­Ď|fߏ=q÷ž{îą{ÇÎ]{łN‡Wea싥‚ÂąŻ” ľ{dSŤöř®řs2 0L[_Fö›ŚSś7R€)DŐ»#ÁȆü8˝sĹĎXűJúý‚° WXăi®Âßu÷’ćưŢ<~ čtŚÎçÝ÷ůú€¦qIóçúţĐűć†ŕ^mĆJBŽ)ČögřNîq%lŽp«‡N*˝ŰĄ€ž€Ě9ŐyżvŁ ă"ň1ˇčÝÓ@ڤCJ˛Ž)›ž\ڤG‰2áÍëiŃ7b=âÚqđ(Vą¦čZß„ęıŚÓ„ĄY†4ÍP–oÝĽpőŇĹ3gŢ<~浞?uíĘĄł¤0—c }řVmP웺{} đµ =ďٸŘHCĐÄ4­!R‚PcŔđ<Ďç~äÓ?µçá'žŘ·çžűönŰąóŽů…móBJ(¶@'Uµîr…]KcúÂÍŕ  8QşZgçžÂ(ä›Ů…ŕżp[#×d—ügF ~  o ă[ôßdE±óŠČý”tDP GşJkf߆W8ťôŃ‚n»c)čhf„uŹÇČŔN…¤€°{çîvZJÜ`ŮĐéĂ1I’€ ó»…yLéď§6ÄžČŃĐď5¸­:áŃń‚04đ,›éŚž€5OârÔ?€ŃOË{«“!f[¶Đ›ýúHc®câx“QÉ$MYšĄŁËËË«·®_»xíŇů3gOĽuöĐ‹/ś_Yşu‘ä°‹Ĺyćăz‚/¶Pđ7Së·…żíyŔnŚ&ÖŔĽŮ˙ţŃ'źŢ÷ŘÇ?ľçîű>˛űŽ=wí™ßľ}Wwr"«Ë U] *+Ą+¨…íň”‘tETř´Şő0cž¸$WÝ §$FňĐ +Ŕ+ łÜÝ@#é÷Ň@ [úměŻ-NĘť†¸čŐľ›‹Ŕ!ŃÓx…'Ô+Pv…‰pˇ-[]q¤ŕ!¤č›1ŇS„rhWďŔ’÷KđŁ`€€űť:Nľy”´LÚéMŚ„Ů•ĚFţF#ţƵŇĎnGMp»ő€[Ű4â×°«7Iś0ť˝ěŮÍ=ŻWţů\»îĹâH&i”`/ĂúÚŞ\]Z<ýĘ•‹—Îť˝xüµ§Ź>tj׾Š}S'ß´ożQgżÁ^[đ[Đž÷9 ŘllĐ4>'4Ü Ć€ţśüÉúÄއžxbםwí۱{ď]{f¶OÍÍMËZ Ş*Ô*ë@ĘZ2!tś¨¨­ Ą[mЉłÍ ¬đ|žßxŇ›´AřŚŔ¨|@3rŚĽ€ĚýĂĚwĎětůž‹źo•tłŽJ¦kg~ˇ·PˇaT€3'` AÂAgJC2 ÄźIśč\@ЎęőxHxZ ÝM›˙–-ąŰC@†ő* ;ô°ĂÝ&Pv&sĚg[Ľż° 1˘>VÔÇ‚»Q”ŤĚćÎL‹1îÔřÓ ťLuú‘3ĚâQf̵´Ő®2ÜÉĹ«ËËĺ[·.ÝĽvő╠篞:vôě‘ý/_°DŠqŐĐÁW ´}ř°Đ7{9¦»)ý¶ŕ· =?×Ç! çZŘ 6c ÂŹcúsxř‘=<ţÄŽ»ď`×»wďśš›ź››_Ř•÷z±Ş˛†¨48‚Ő&ŃŚL0’'J$ŚŇŰańI–Ů$`°Ţeϧ‡ÍIŚĚý#q~ k‹ ¦Hć~¸Ű'ě÷ĘŃ„íĚE0ź–žă_HťĂó€íŞ]±$†<>“ŔĽ˘ŰDCŮăHi&řÔÔ† ţŔĽńFh+ěÝnF;xňžŃ˘Ž@^b‹;şZÇHWď+đuŃç4FŰ|3łwkxŢü^FqĬőnc}}ëËK—–nÝşuăĆő‹—Ďž˝úÖG.ž:öĆY¨5;ZčĂÂůÍćôőiü­ď´żíů€łŔčĆA ĆŤŔA´( Ŕ€H~üÉ=wäţą}÷?¸{űwĚĎoß±}n~aGozŞHÔUĄG ꪖ˘–LČ&Á1p Yá VAŘĎc=6Ę@(bÎĎYŽ\&G Ĺ!¸‚¤ń)oëKÁ ą4Ëŕß=Ż~*(´ f ˘Aü;O·FşÂ9H"ňŇďĽG̨Ĺ-óÇ!4ćęĄsçÖĎźzë €uŚŘÔďđMlBŃoÔĹ 4ę„Ĺ]l±Ło‹}{ZĐž÷”-Ř 0Řl˘1€apŘężGÁ¸ĂÚ1/lß±mמ=S“ssŮÎ]w.LÍÎLuz˝¤719Ýéö¦’4Í’4Ť˛nw:KÓÉ8MXś¦j^ Ĺ6±vTtŁ!Ą”ĚÎďkíâú<ş}‹¬‚köťâŢŰ«” ăŠMţň&̇˛đÖ’±@wgŠĽz:¨Y{PÜą ť˛źëÎݬѱŁ, TĂâXŻŠbq8č—ĂaQ űë«~˙ÖÚňr±˛Ľ´văʕ뷮]ë_˝xqőúŐË× „urL!m*ŇMťřVľ6®kßHeżŐ"ÎĺECAo‹}{ZĐž÷ [°`€M€A“q+Z„&VaŁŻGoó{Đp»Í×xžĺł;÷ěťšž›ÉşSÉôěěDobj"ďv˛$M“$ˢ<ĎÓ¬Ó™LłĽ“$I'q§ O“¬%I'â<áśÇĚĐŮvťL›™ő8éŻŇQŁ"h¬XoÜ‘vë Şyş˙®˘¤1 PW5„¨ÔEşµĄ¨ëAY•«ĺpX—EY—eQ–â_ kĂá`˝DŃVĂA¸ľ¶¶ľ˛Ľ´´ş´\.߼Y\»ryu}uĺ)¤˛ęĆ”ůf÷VŠřfĹ|Ł/·Päń6 }[äŰÓ€öü@±@łľ ›1iš@Ű„e¸]&b«?›mđŢ|,îoř8†ŹI 311™w&&“nŻ›¤YsÎçcśqspDŚEŚqΙˇËµŇ]} BÔR1B mÔ$„˛–RJ !P !Q Y !Šb(†ëýrmmµX]^čC­¨me}¬IeŢT 7ę7ű·­éŤćęňŤTő›­ÔmwŰúö´ =şçŢVŔĂÖ„‰[9löůFâF¶VIÁkŤIDAT…˘ľ8÷ůfoá}çx’ä={ŻyFşĎqE¨iî<®ŁÝĘ›Řŕs±É÷lĄ@oÖŤßN1'Ĺ˝ĄíŰÓ€ö´ç€(`pđvAĂíĽńwńga“ÂĎ6¸˙x‡Ĺ[,Pr x7AÁ8 €wP¬7+ŕ›öwÚ˝·Eľ=-hO{ŢĄçěF!Ř ßŇűŤ˘™±…®śš*˝“bÎnóvoD˝°°p°U lĽŇ&¶4ŢN—„aŘŘGŢĆcמö´ =íyŹžÓ[Ąľ7 [-˛›ýŰíđ¦źG5|Űy;@éí˙­˛a};€áíĽżťďi*ěr‹÷—µľ=-hO{>XĎű­tĎ,(›Ť(6ëĐßíĎßë×·ü~~;oÔ©3Üß÷ö´ =íi_#o 0ČM:qÖPhXCˇbďÁí{7Šţ;)¨M…š>o‡R—oă>´§=íĹ­=íiĎ{ňş’ďR‘fc đűńl(ĽÝâÍÚbŢžö´ =íů°żNĺűěu,·x{ŰÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžö´§=íiO{ÚÓžwpţŠuĐ]ř<ˇIEND®B`‚gammaray-2.3.0/resources/GammaRay.icns000066400000000000000000007432761255003167400177260ustar00rootroot00000000000000icnsĆľh8mk "$$$$$$$$$$$$$$$$$# Vę˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ďb =úţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţţH$čţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţî, ®˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙±25555@úţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ýů_˙˙˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'Ü˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'$˙űűűűűű˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'$˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'$˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'$˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'$˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'%˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'!‰â˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙'NË˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ý˙&$Ý˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Q˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˝/˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ŁĂţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Aţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Uď˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙K—˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţôŰ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙E ş˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙ň>Vß˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙ý” Cş˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙ßu W©č˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙úĹv$H¦ËÝü˙˙˙˙˙˙˙˙˙˙˙čÔ¶’[%  1>A7'ic08»ˇ jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdef»*jp2c˙O˙Q2˙R ˙\@@HHPHHPHHPHHPHHP˙d Axialis˙ şş˙S ˙]@@HHPHHPHHPHHPHHP˙S ˙]@@HHPHHPHHPHHPHHP˙S ˙]@@HHPHHPHHPHHPHHP˙“ßz@O…#şű=Qs×Ääé‰v衛¸Ý™˙ f ,˛¤CÖĂ‡Ž“ĆȶÖOKć 8!¨ÓźżW^ˇŢŠ›ňy3»ÄYg(JĽwĂćBG|hŤi’Ë7pVítü0^˘öݱEĄ7¤MVOfQßÇҬ'Č„¦&”ň`ĎŞH¤ <şĽ˛“E5¤AUX:»séŐL&ÝH»Jt>ŢĂßz Ot˛Ý•wú4čŞkú“S# ×Ky†?ĎVŚ'ü=@»ůWŃlDÇĚIm>l„\4*EWUńlăcĘúĄ@Ă;K‘sĎĽú}çń÷ˇ«<ÜVnJ˛ĄŞä€2RB2ačh(‰áśŃ«đôk ć6Oŕ*—8D‚ŁűJkż-¶ç×˝ĘEř¨X4Ő?Łs?,&0Đľ_A¶Ťójź:őd$“^@Ďw+cÎ+úŞZ7‹*PěÄÜ*,Ę®Ľ‹×}Đdäî%Đ?1¸w1vR=tI˝g52© ĂŤ XGŕf‹Xtť|.IÍU¨&Y3JZ$Ţ#NIL p)OĂ&Ę…˝Ť€'Ł—™ýŚEąX«E¨ĺŮ·1ş ¤¬Ť‡*$Ś őNí5*‚q€úőôśrżŘ@í^iÚŰŤ¨\”ö!¦®ß•“>ű2>úüť†ĘpY‰]yU‚3¬śd ¶öă"@Ц«ę,QLŃĹaÄȨ,JŐy ÷ä ÂđůËsSR—3 NłôʱQžď Í{µVSľ÷´Ç/QŃ«­U±"‘’®‰×ÖŞăŔdĺA!Ě….úWĹňÄ6=Żdą R/ ǨXqţ—Łó/×}â0W©!Ś[“ĺŮ­±ŽÜSB“ćăŮY‚2ö˘mŢĎ@ţń2Ńůµ•öǧÁĹčŇ=É z¸QřĽ˛~đÍjřî}aď-Ź! ¤›…Ȱ[´Vs1s]}A®Č7Ş*‘;żš™˛ÓŹç4JşżvşšĎޏ©(g'ˇPÔ3ďńÝ úS§®W¶SB–`Eʶşmgm ŚŇ¬ĺ<-kˇ”»«+-_ĺ×µ„Ŕ20†ňáZŃ” j{,cŤwě¤bÍW|6Ő É5s¤*Ë/“}]Rˇ†ŕĘëHsŞÚ”ú_/3Íx€?NÍǨYM†ŞR¸••?šUK‰îBłŹ7KŐÖDp›X%¬¶©/QÇ·D* î×űŕ^‚DI¤&ő¶ n´íť?E~ŽZ<[%D‚›éŽ šAG………<š?ÇÚĺ¦ű±ÄQĚŹěaý—«­kąőpŠ­?Ł €UÉÚźm¬”sKďŇiápo)jł'Mxu6f e·ţŃ^wnK‚Q椑±p öj…5\BőŰź|ńŠu›žY=H‡Îo šTű ¤ýľÝIÎÄoG?ľ»ëlµ·Hp©„ ăžĘě@Uö…Ť­ÁŠŘëVÂď“PUě˝rNÎeŔM\Ő˛€s3rĚô4ŰŻ®őK‘;4cB˘˙GiB 5Éăg‡č6¤y˛~Ŕđí(” ˘â‹_ËM¶`~¸Ši!Ćžc*ě†*¸Ą+ňŃŠěŁz¸ Ú'N!ö\ĽI.]d1ű_ňS‘ i«ôcQ8:=ćYE’ ‚W[Ě!üiČwŻQëVAŚ}C”*ű% ‡D@ś}«¬Ŕđd}ä.<ž{·gN„(ď2/Ćż?nË ŁŞĹ Ź¨{~§"â´Dć—ýZ Ď˝Ć}íq÷°\— „Äę˘o/n˛qrp%Ńpľ ľ»`ęü2„8ŮęŻvŞW- qËÔáęp°|qzÔâ˛-˘ü ć Đ~o±yýŘ ŤČw° ë4íI2ż±Řf¨ýtŇľâ|‹Gčń#ަ?Žő°ÍĎ *j?;[ąÇzős–Ë#{ĽxY멦ŹQIm‡Úg Ľ7x¸J—ˇîX}$7K©?TD“'éőëoÓ¨Ű]ěó#›ŃrŞh˘f T×™Ů_ß. =ň,=ĐÖWýcŔ™g9čČ:Ż3G÷RbŇŐ0Ť"ěu*‰«ů ›‚ŽaîÚ y12Y“w†VWęĆDÇ&•ri…7fawBF×~! %ÂĎČĐ‚đS—MKFśM›ćYoşî4s‚C‰2Q4B)ÝŠ§#îăe§ĎĂŁi÷ôŐ‡A ’ň’Ü9ö;yłšé]€;Pö]nM‰|Ý1UQ¸ŽěËmy'EÇáňQ/ý{ŽÓń6ĺ< äQĄŚ‰ěX¨Gf0ÄDIe@™±˙~ZŞg,üČDy¦¨}g0ćqZča,’Ĺkx0P©0ţiQN¬Q#Pt„}Ť-÷—vŔłTP**S/!(ŘŐ`DŇĎ.¶ňcĎ7#ÓHjÚ0 /žä_Ńťó]|;kČČPÉťUŮÎă˛-zK©ł N_KfcZtH ŻĽlyËśa1XíU‚3t—V÷T§ŇŮaě.=ž^űďĂ?sý2ěpöüSŮ˝Žě?ٵN©[xF•[\™ľÄaĺˇ8Đż™ĺV™áŚ)Ł‹ĐŽ·R6ŹSĺy+5d·mR˝®‰&PţčŐłŻäPÔ/í8şŞŤ”¬Ż±h J~#5b\W'ÁűD”âĄő«•N“Of}°8î禹$™Óˇěű_Ű–Ăą<żąoŐž ăŚÁťňOoŤvŔH„Č=©S "KB7CÁż[IŮmś®řę¬Ěuç}}]:o(Z· ă„†ëŁ]\Ŕ°­ËVG:›«˝É$g‘—@ŔYŽ®ąń›×‚ę1]€“QŤS€)Gů˙× •‡¨µµGJÍÁ óę~',˙€ü;˝úPµ¸±@4uX 6B®p^K˙/~˝56§ŰCDővĽ°´«ŃňpĎĺ®^µ]@Ě׳X1oXťžůŹă8%|ČH«Msčîćl~/çɰv˛÷ŠV î¸aÂş~(ś9Č8Sb s@“śŻLŤľź¸ĺsŕĘK~ý˛e©jrm¶Ëôüéˇ~€Ć‘¦5şŠy¤5XWŰJ¸wXÍĎ~GňŐ¤iç°nëŮý‰gCPU‹Íi.>ŕB&P GaF’pÔLíďuß\|aĚUii•$Mú±ˇ©[†+lÇUߦ­ˇDűXVW_ťŐ#cĺ"â‡L75Ě+ĄcE†Ôď#qµŻżQFf⮏’‚~ľwâ„ú@E ?ě!ß} §[ă㪵梅&ŢşM˘6ľ8jl-Ҧ‚ż”kűLĺC -‰©  {Yµś4żô÷Ţ m¬#x˘L©֡ē #óÄqÚ¬2“±沽Ŕ=^J:;ߡź$tSŃۢI •d­mKĹçA x´[|}qÚđü–Ó][ľ:·Q#˛áOňW‡.>äÚ –«?P T¨X°ŕtO))—ËĐľŢFi©ńż7`S¶×TĂë{śŘÇ:Ž]ŇÍÖ}'ş¦Yź90ĂíJK¸.´•¶CAfq?ôń¦OP/ăůp:[—ô„ƨ«»íěbĚ@2i3•ž/8Qc 6łřč—ČÎ1ÔR?ŤĘxŮN6ž2şSş­sL=‚đ–«Q©š¤óůA9ţ°GŰVBVPČ©Ż˝&l–&môË WÉ ·Ăi“7ۦYTjfh'ëVŚ–4Ő ç{Ö­d5„ęí“ďzWKľóňhâśÉĎ"‡şwřÄ8ŚXQnÜŕv"Űş‘šjŞŔ·Ű”„×L9Šb‰"íä¬Đp´ 3 rH‰G[ßýq"ý˙#5ľ,r‡Ď07°ţ:€kś÷v~ÜV˙`)ŹKŽ6Üçţűb§ťĘ“Ŕ™ u 0oU©ooϡŃ@Ríłď° ’ ÂH†5{['Î mvŽnaÄí! |ž×jä]żůeˇ ž®ŁŘąSŃk8ŹwŽ,”D˛Ű®čSÄFA§SŹóĄ˛5ŔÓHŹ.ř—A±Đőgý#žę’w`ð®©0đ•0s˘ČΫâ‘.Ł(kĽDÝ&ŕăÚÚŮ ›Ăăůx$ŤzKŠ‚Žh›Wäĺń•]ä÷ą¸řÍ0˝¨uüRĽĹܦŹSęóÉжl bí[ÝÄú¤ń?ÇŰĄńöę´>Ý&Ąâľ±ů{•±“t8‚Äö#k´vgjĂÔŤu*@čÎ(źÓž9ź{!ŔĎ—ň4ĹŰŚ )n|ö•żá ©l'Ź®Qż]Qó`§(âA¬ußm#CB< !^EočŁIÄEăŁ'#ů‹w<Ł(VĄVŔeżé*Ţř|2ľ˘‰Ë˘HÄ‚V•ďéíęóÉî%MŰM5íöĚúa•G ­˝p/WŘAˇ"Ś×­ „íu ¸Ę´—7»tžŔ¨›^¸)ô!ÁčOG·Ň31Y-UžŽa?q˙hAbÝÂqV»5„śěFG±‘Ä=ŹQ-čöX—h+sŐS¦»lˇą,ĺť3Q łŚlS3đ` HĄč;ňr6h ˇ’É™Ďg…Ns!Úôgăĺď¨H¸vW?VôIAD-Ň Źäjń„ľTË´öčý7RKS‡‡XíČrVnĽíT`¸á3çţ9ú] BWIľáśŰŐi8xĄ†'‡;‹µO«@Ľs]7™›®L5QÁ© ĘÖ[DBRŮĂL{…w[ŘaíU˙Pb3ëLśŃ.]ĚŻ5"BlŁŁd/g+ť6V٠ʵş™kÇŇöŠo¶Ő3ô›zWr+ßWܡÚUb2y™qĽsS€Ąż$[<÷/Ą)‰ŘĆąŮën˝ňŞ-v-űˇdśÎ* â2kî3) rU!Ďř„/„ščE%˝Ż‡đ­šŃoşŘ)ݰHű¸3kÜO±QůÚ¬ä澏©ňcçłT€Ů˛9!ű†śZOçšÚ"čRm•Ťˇŕ€IiűĆ‚ ť?ÚÉ žăż8ż‡@7 nkRGĄ˘Łe—-m|6™3I…KSXűĄŤJ¨p¶b4`Z©0ťă$ ·Ł}qęŮ{‡ŮU–Q3űP ‘™aFŻĆ“F‘a#AčňýŁÝ#ŕĘ$|a„ę~>č 'WŐůŘK}´ä„7€ ř9Ż]Äńď¦ŰŞo4¤đö 2›7kÚsëW ol$Ů-f>­=‚j̤|ŞPĺš<"fk›§;ϤÁÝ 78LqRĹjnŇ’!”iŰ0ßmĂ–ZĂÚÄ_ż»vľďO§[CŻî':ű>>ú Ý‡tcMPc‡đB2PtŚxÓ+ú/„Śń/ľtRő˙zŁ'rš ä»bŰÓTłśT‘F/c2S\C(¶tďŚ}g)F¶ŇöˇÖż¸_ç҆sÉß<^ŚSz=>ľ$îs+ ëĄ_´ŮT;V]ŕÝ]ŔF$‚‚ŃŔ:]ŇażIt?jâx÷çDyü˝:¶˙AŚQÁ-S» ůt$ČY ™>gŤ´a5j:ü}·m§6ߥ±. 5Ů}+˛nţx43%ź¦nC\ˇ:‰8g‘pďC]ľĺŘB\šőŘ9tď4ßp|§—Ŕ˛‰kşöŢ’ç.ŠĎhâ†&/&qžă:bž’wđ2łÓÁ!J—˝=\QĹńö‹ęJ"L‡¸ŔlMÄô2K´íłóů[‡×É,Ĺ'ô>™`STPm÷ŮRÂɰ <3Tł§đ*_ 0ŚTłĆat¨Tq´µňüÁ•6…™ŰÇ)±Z‡µ‹#¤ß¬äçě…É~ůW0‡Ć˛…U$× pĐT ÷c2ŞßFřĹčú4ď— OVäG¬Žíů;¶wm˘ŽOĘAË9č6řdŰ÷ćHj×®˙^ü“YŐä î6ÜAÇu®JÝF}© MJşC•ĘɶÎ5ĎSrňôtHŐŃŁىä© Kĺż˝Pú\·o/jDţ±°ŐšůO©ýJO¤sňáŹNÖÄ<DűěÁmeőŽ™BkT¤T:–qp1E_ŤŮ—łgĘ…Uąa™†ßđ_ĎĂŮf~äŃřzŢ€éqÄÂ~ťSťő@đ§ë8ÁśČr‹ŹĚ5<şm6€|(˝ěĂX + öµę ˙~ě‘Mńµg=´ź<¦ý)v›?ë^CđU“32ŕú ť×ŰşÔÓ éâH@ŮÄo‘lNU҆ Ęd]q’Ě•Ż Dâő`iC3än^ĂŠ¶Ú>ͨĘË ÔLí´ŞÂYâůzçjŻCFzÜĺpo~N}Eô¬.—&$ÍĹ_6´H`9Ĺ9śŠ3X†5 ăC˘|‚ꆍBĂ9¤`7¨ăŽâçůÜۚҊ¦K‹é)SDËřŕ9MťFp§±jÚnűÚťó|‘Ŕ˙kyľ-ŐÓ䬫†÷@g5ľĄÁdVS"Íą ˘ęSÍχC€Ëĺ5? _Ú„:DĺM 7’W3űd´yĆe‘äž4ÉýTć=žS‹ßů­F‡o1iŔľŇ><(ją‡řŤv™ę°16WULe€hÍ<ěµ ‚II¨x]s™p×UZÜ‚Ľ+•‹ŃRźĹˇse* ŮjGűň”j¸{‰ÄFΰ$JŹ%q4š QŹO±Ţ[8ł4ĄŠYóţŹJk›†T.«+ă,ĺ8OUŹ/CĹ(ąldţ ÝMşH'ĐčŠ8+ŃM^2 S Źžńź÷Ůƶ▋Ť»Ě\‘Çď„]3ůĄ<ž„>}ĺhҧ9oŘdLÝΊÍeQr9űă´:9‡fS{ł2lšů[’"¶2˙.ŚÄżŃŕs ňż4W¶slj¦~ë„l6(EěühŻ#%X`‹Ú…˛šIĎ@dµ_îµ2S[`&ĚĄ©_ĺNÔO€×qôÚAô¶ĂlÝ»Gb€˝•¦]ńM3ÎKŇč Igl$ž}´†¦ăÓçI:˘Ĺo )ő«üšű,ľůMś;'ă§ĹŢňv8 ±÷cŠÜ†Ëw¸)…Áďb·čAÁ'ĹSşVˇj?•Ś; ßža=š¤®Ţ†Ŕ­Ę˙FŞő´\ĺĺtÔQ¦Mň‘‚ś~Čfćţ/´§aŻaceđpŰ1ĆŢ™1Đ«VCaogj-UÂ,?‚?®–zĹ“ž$ď4ŠłRJGűŢjLs@QŰ+~}fŻ–‡pSÉ™°J Ť.—•ţ¨éČ:˘;޵pźzÝoŽô03!¶ń]ŤČ˝áÉ xL+-E*ďŹ'‘y€,Đ/Ó¬-%Ĺ­ÔÔ>DÜą ›ZţásűĽ*ľËÜ1Ą%Eć"2 ­RŹhxě}s —š»‚r"°y!´‹Ůz»Og’‹?ôĺěçŃÎŦhĂܸŔ|w4üZ!XÔj{´Ú(k‚^;„źi$ů6Ź[U˝:â\Ęjç>Ŭyu·řŢ%uŐ‹ĺB€ ß'ް´ÔIçóؤb‰ýŐD,ôŕżrďŔ©D/Hěéľ[ś…Ťlhý –iŚ}Mgeţ˛‡„ôj‡”Ó\Łíüý0RđŞŞń6Q ôY&†iĆîŮq6štÁŢ­d”MfQÔď€Íż_îŤmHdްĽď’bÎ]ŃΡőâ*}„·q.,:ĐSî8w™CY©ź5KăZĆ™÷[đ»”ułR)„Ő{‘Ďo”6ă©•ĎvÝg˛Đw˛JńÁŇŘťŰr÷ĽŐť0ŹAsgŘůŢ1"ĐVTXÖß˝ëĹČŠ„[ŵٮkľŇâUň¨a˘ťqÜ„sNr ě×VPSX4ťÎä\5Ź„éĎ÷ ľîěl&‡µ2ň:oŹ÷^ž;Z™e„«Ňź€’Ęž¶§bo‹l«VwŁ‘žŕţ1 Ai» QkĹ"A]ěŇOÎeÜŐ+syPuUł(±Še ü}ů“%Ű&<YľhŞB{ß©Y+óľ„Ă®§(ĆđŧĚ<ň¦›źü—°ÉÁĘžź3ŤŐ÷JáßÝAąĂŔ1r^÷hŕ†|J)ŕvÇ{Hř–WBxźhR\zrž ·ş-®ţźę卹ٮéeQׯWÁ¤`ÂkXÄN6ٸŤ6éĽi}ç?ĺ^MM*Ó̧@5";†ÖŘÜŠŕÜČ*ÍUCnăő˝/AřšŃüeŘRŘ ă±ň66ÍÄŽ®ŇĐ×ÓÝ ·ÁXĘęę*„ţO7-}×%ë‚F'věiëŇlů_ů­”ˇ9h¨ä–m©4"Ú•O‚şŔ„ žĐĎmă4 ż`Ä.R?Đžbżö´0if‹nű,â\ ¸=9]}dśz›I‘ ˙h šLźZi…Îúç‡(VL §6vQ %ďĄÂŠ«@AŮŘ­îkŽłyđ@ę®F¸óĚ$yhýÄ“ćĂ!?éšÇ M)ŕÍ‹$bW…dĽ4sdő<”G Uqpt™ĂĹEšÇĎž«ZĹ=$Z.č%fI¦—¨ĂJ*‹YügŤ\Đ‘8K±ŻQJhźeZĆܗǡFx/•H˘¤Źşďo×@‡÷ßŢÎT>éĎݢ‡ŕ{ł„J˘Ľ&•Ź)rCOG˘+ X8$>©ĺ{üçŻ3>Ö˛;>#“ś›:Śŕq¬ żË!NŚ`$[ż‚Ę€Âh$ýşu8“0ëĆ­35,Ą®aŤthq媽8lLJ§h 7 × »C̢Ý'ńâoîWf2Të8‡=SÍx˛c‘żŚĐŞMâŞ|1ťksFĺ/¸Źů3•[WĎË`p ¤||:\d•T%2@âˇßrd&*prNHQŁGĚŠ~ă]Ş‘ři­:jń Že™Š5dJ†?/ş<•™śŹY@3Ăz¦7ŃłůFíěşô$Ţžvs? J”(\ ]˙Dk4Wµ‹ÍëT¶źq—k¨—Q0őŽłĐřÇ F‰g€?¦”|né&e¶°` kłŻÄ¬ř§ZuĽz ĆŽ`tĺę7†RŽ;L"Äz¬ů đÂ&Oäçµ4‰xi•ŕŞSŃd1•Ůł`íF™ď˘jĂŽ ŮÇeʧÇÜ”&|nýĚV‹°ŢřC2̂݀ӄq™˙4W为I¨A;q͆RqŃV+3Ô ą{űŤńÄ%÷ zk—¶’ÉÉeóä'm€q°h€Ł8Ď\ýW?”›ĂCYĺ_TCdĺăüF6˙8 LĽ4..xŤ±-ÚťţÝť}TdŔČ•,>O”‚ ąľż|«<íżŃO×Ó+Ľ,˝ĄŮqŹ‚}›*bo‰( 4ÓÝŽµ7pk®ěfŽ Ę[°ŕËě:Ů韪xÍVˇ±rŽésł‡őËŹĚÍu´¨ů‹Ůńx°C•Ň@ľV?ęűbíq!eµ•8ĘÉ!y脚Ţä¸^Ě/fÚlĎÔ„6Hë[Ýbh˘Î˙"ńö-ę.nIgČÓśgnc6ő%¸Ôo–ířďţ\ß-uCđą‹ĆWDý¸{Ţ€÷âŽhŐ Í=Ź u!Łőń\ť©˘[(ĆŢ…AžÚ0ÓmP[†–‘qŐŻ§L®Ń=ű®ęM'i¸ăť[cŤ%…BČ“·Ř|`…©ĚçŢűš9IřúÓ–ťbJÎ^…Č4š'ýó–ésß¶6OŔ0Ěť™L$!™ÔŘÄŔ ^U[Ńj/Á,wkŁ•„ľ˛nÉz~áÁ}÷ąK˛“ Hi—G`K3_(żŽëă™Ř—€›6λMiŔW©UJ’HŞń×.žôż¸ńꞣöŮĺ1-Ë­“j9ĎsŘśÔ9Ξfµ`ejý+„"ŞÝiÄ+!^ń!=ŇhäđŁŮ>ŔV× ®vÜ^nŤ 5Tzź2ykd?ŔîÍ2¸Dß+ˇ+ׯ…§đfnű~lz…a4މ>up'Ő Ňő~[#łś7čÜč$u8ş@ş§’GZâĺLźIzńpČ·aň3đ9‘|@[ g"Čą±kB› ¨_1ë„DĚ„ý˝^ĽŞu›Eźž iąfÝW$›•Ţ´íîTÝ*r…»Jž*5 Rkl8ÇB!KÓ$ŹŕvgŠ1ě­*&t›Ż“ĚpTjâ‚ÔŃ6m"Uľs¬j$ůaŘÔM3~ÁR'ë‡đ{´®K ô)ÚôiŃÓś&«t ăvÝČ«ćŇC#†OŔ!QÇďr X°5” &ËÔš÷y:5ëok.)ź}áRµkڰř&+x¦OŻĹéOÂ'ÂT;ö$Żü8´kĹ1eĹŁÄ (d¤E>1ŔőÚ$Š6!vď&Qżaűn@D`íL°Uf2ţĎ>»l$bŽ›gţž÷P‡ĎÇyľÜ!Çú‡ŻÝŤ2aťÉÔŽăvÇ­¸•b[Xš Fń3荄-ÎnzlrëMçwLÁ«38›¤¤#cöë9‘ '¨¸CZM›ž:Ç&KÚFZq#ˇ.úąĺj«ŹZUÉJČvearD¶z¨P¸#ë9‚wIŹŤËyáŠrPÖĘoč„’ŢÉůĆ{ŢŰ‘m őłn;0ehA^żÂ9?…ŽXIlneU&uä#ÇÓ}‰m’e ô@„{éŘŘÇU3‹}h}–AÁ˙rź *Žë†6Ĺs{ŐÝůć!–;´¬đĚÁ#vš 8h‚ę2 Źâřk gˇćëTŁ\OŞĚ@ÄŐA[ú«é‘]ö*`ćb6‚{=Ëď.%GˇÖŹäE”Ťľ­<ĆMČ„ŢkŃŘLńmt â<š•ŃI'FÁ_eâÚذF“ŃÓ5­ČŽüłcݰ¬Ő×,ß骪íXĂóß"Ťĺv¸€ey_ń€®Ďˇ¦yôójÇCO‰ľO…Bë…9X¸ßšł°ł¸ 2LěX+aUűľ5l×g©đ~ą 2Űúůc X ňĂ ˙naHg’°3ěw›f“řk‡Ňďţ1Ř#w^ÉWŤĐťŚ„Ü2“Ăz@ dź•Ú¬—Á#˛¶0 [+˙&…§ş=3ď!é‹úqŘçO>‡óąCóÄśjtbŢá×2ą†ęővĐÜÂXÎQ+pwŢż,ľ•0Íϱ#$çß5©”ó0ń×]ż@ďu“QćF—•ZL ’ÂÚŐó_EăČŞ^„§—]yĹ%ßÎď‡ ™­úŃ;¸šRr÷ĺ§ĘźqŔô“Ź5Ć97Ú”BÉ5ä{s·sňžćwŁčŔ›śăĄs/˙KĎ %z­NŁ$Ż‘Ź&ŠÜŔĺ2ęM5řÁŃ×9ĺéišŢďě·NM‡´ńYĹÉ©•ĹxĎ•Ą`ňuwB±ů}io4&6Âpz ©Ŕ xâKňŁqľJ~Â玢4Frý|×G#B¨LQM®˝ăÍÇ™—Ę5îôFoßŘ âĺ_É+G»Đg*EŰ9đ‡ŤÓpřë>Ýw®+0×fÄ çjĺ’|ů^°ŞoőĹ1ňcóŃEfŹrÍ$Ö×RĂ/ {^>b6(íĽ čuç-ˇ¸P‘ßWÉ?Č Ôxí;ö?TŠaü‰NWÔäďĺnŘ) NÎőq2nŔĺ@ÇĄ~ŁbźKÝŽLă×H ’#“Š8 H8¤ž€żTěŻĎ8y⇅jü(µÓÉŹpUÝ´)Ă››Ë»3[$Bď„W™CU÷¬ňŃÚłąşBCť®ĎŐ•Ó'C·šăŻŮ¦ő„ÁXÄ|_Ň“vOýűH€ză”Ńű,ž<řZµ|(Zđ¦>úÄ÷™ŽĹőpµŘ#üŹďSöĐ hČCbĺ>7’—íĆé°č› Ëźî›+uµiąź0ĂŤ4±=PDa>ěßX_w§"1ľfH•µPgíf®R;ŽxwtŹĘn˘”ϤuBMˇŢ>ô‚?;Á[Ůć¬o»ęčÉ Şčâ& PçâQ‰üŮč?îÍ0&,¦Çí§`°~ q ‚ÖD27ĚXfwçełQ©Ř¨s =Ă!m|6ÄÓc(= ¨O/ú~ Śőßߤm^µA{ &Ox±ç[ĺPŕ7J,beÍŹňĺň7‹^k «4FÔ†ĂV'ź_ę®1Ü—ĺ<÷Łî č˝qQTÁBüE%—q^¤®ŮđÂŻm©v…dęv®»»/ß jĘÍB9¤r/Ź«ß˘caľs:pŚíHŤä%XF ¨‘çíËŠBéŃ›ë”fÉȢ1Ax]@= »Sě·Ťž(§|Âé¸ď:ËVńo–©Dha2}Ť˛\' ź"jEc3÷rÝÔ2'.NágĆ÷Ô*(t>ăWř 5őäđâŐĘľÂR/ëěy<×aŰŔŇ$©ýąó覤 8 CM|â!h ––łőJ Ú§=dÝ{nÚŕ6äÎIs-jx>ń$k=Ü$±Ňôďd¬yéľH»…ZěÉn3dńë^}N—׫łef˝|sÇŰŐ?®¸>®¶ÚLa·§‡:šxfł—t1F[#§¤0o´žá^!–’ÄmôhęHJŘuĂü˘’‹×´BqőâĐäIx­"!‰€\ßŮŠxa#bb«ö3ńC¶çĽls2d{7g _j“gH–ďžQë}»3lH˘McŚŔ” TťQ­ćY}üČx¦¬™ßë茒}0@/~ CJ**Ůz ¤j®č ÓÜJĆBß˝Źą–]ĂM+śrxR‚9eÝĐDÄĹá@é¦Ôć–Ýx1HęUX*¤‰ńÝmÇvąťV#§Ţ» \“÷idH[˝ zL’Óôg˙/2ŤeäőM’.÷ÄQor9j OÝ^hĂ$˛“Љ1.'gL"·ů8şłŮ˛Ĺ¬(+Ő0$ŠŢ~DŹgń‹`˛˝ÜČ­‚,DÇ ßě;őf$ĺTÜą,XSQťw^hŰtK˙q «`—ţťB —˘ [–¶Á^h-˙u˙o>îËŁ%őÂ)qNž¦těj$OŔĐZȢOÖ]Đ-’ŻęÔż§¸o‰ă˘a#h[áç.Çe—|ź—RŽĚ»¬ň¬Qą5= R| Köý«¸-Üć3«r,RÉ]Qz˝äńXŇüŞy[÷[‘r,÷“˙7^6ň,®˘(•rE”˙—ě8ĎÍQe×CťWśĽ™ÜÄŔb_4$ĘBMĄ«I·úwń‰Ô‹ă!˝%íáîť«Nظ’šŢ°R”…÷K\V‡M°[GŕX šĚTL(•Hfžj5]0‹Y85gRçZ]lǢVŃa:Ăgü™Q1Á€‘tᓨŢúea Čö-eÎČć2=fv˘ôző[Âe+ŚĂ)*Ć{Ť¤ŕ‘›ŁÉ…Ž [ýS‡˙ đ3Ä ěťo˝k™ĺü7Ź$8‘ř*H¨ěPbC,ůď¦ÇÄVxô&hĽy^‘}wvËc©×÷‹s0úU,*8<éćÚ§ý€ Ůd˙jŰÎŰŔ÷‘vhÁ}áY]&šÍ‰ŚŃ™èö‹ŻVz1?-MgłýŢ€ ŔㇾLü:\R‡q».•FܬV•őý TěP{!šŘn÷W*WĎčü…rź~ÝlĽKĉ! O­tŢ\ç¤h”Pˇ/BTj] Śž&xTŕČÍŹĚŮÄFÄ ŮU}/k2(dVb"Ł.4”^wbŽ˘ýiJp¸ÇŰ|ŮDŠżuX éä–šĽ@wgŻć8ł´ˇ˙6Ëb3÷ŕŐîcÜ]ŽÜ¤¦\_gŹš^ڬÚú>•&4Š+›sµ•c±ęZA„ÇÄh—lÇ­@řwöu‚úhĽ4z5‘‹›ŚźÓ—|ľé$ŕíů˙!e˘qć·ĎT"č©+j|»Déx„$mö~ÄřŮ›§_F0Akőd,0C˘óž‘z©]Ëc°NO :¬ÇŕbJŐ,«'ş§˝îÓe™M|öŽŮz˘ď«ź<'ü/z•‘E[ O“É4v•S65ŰpĄ‹ęh 8'T'B8BiŞZ•Ěú™7•—ţ[Î˙ié’D“#?DîJp™ůBĐrĘ%2˙Dľ‡4ŔâÚůĺlqP;»<'`‚›ŇPOh×ţL"~‰S…EZHŻ5_źçUŻŇ‚ÉŠĐŐU’ő<ű°ŤâZ€ťďĆë÷§ăĹ´Ń7ý÷R^§:o”„îÉs[ĆŐl ˇ]ŘëŢV™]ťV:Ă1äůUŞ®š›EŁśtI”“4˝ŹXň­Ί[˘âę?Ú´dTŠ15bç˙" <ç|Źsůᆪ•aľ&ŕÚ-IßÚ†)ÄńĐE]˛5–6ąwł^ĘßĘĐ»OmhNEö\e†FQ•_ÚŹ·~[ář&{Úc+‹®ÎźT8ž óňŐ%ŹÜé-Űă$4ű8‹ŁÂśěŚë˘­ ž‡N!E^’Zq[Íĺ‡Ĺô#0Âl=s[;®-mĹ P9iŞ÷ ‹ŘTŠ%;$`äÉÚÔšjđÄŔ‰ÍGmQy{3dĹ<¶öˇ(¦˝*Ćg¸5Ő§_ đnŤ$`{}3©Ď百ŔTrÇ0Ö°üHÚaóŕëľ]Îr_súâcĺ!ő¸&´˛šŘ*ÝXţ8lG ŞĘ˛ €öüŞ Ň>O™†a…D7{Čú"±aTťëűČDź‚đ±j±)Ş5ă5/„%űĹc±(ĘsÉ8Ă75j¨$ç jÁ^ĆŐśdWVřwnŕ«…ďm'ôÚwSCeBőĘw¸(sÜF‰ Ź˙V&aXüCĘ`‘/3kŤ¶4ő˝ç°·<Ů|[ÚšďsYŽ°ŚŤĹ« l'…ü÷·÷ ÍŇÜ}Ąťeýauíć‘÷Sw€îż>r놴uĺË”x.Tgűl…Ę’íR[•vş € RÓ„ ŢŽIéëďÎQYř€ľçć$ 6qŇ{ÝIÝ.e é¬'ŚMcý)Ľ/W’±łń·ˇN~Śd±G™ÝA.»Á äfS‘MG¸řLU©.LÄż˘_ĺź2K>,ĚôAN‡y|ŮíÚ‘HŔ–ô<Ňď7üüâ±®÷ä›o˝*Sć_1úÍ–*yřqŃbQbçŐ5`V {Çą˛cľ_\K5QŁ9á·WăĎĺŻkŞÖĆW_—<Ě0~ĎNUj…Âq'7θ!EkĽŠ»„ëőE¦Â˘^ˇ9ăÇś·Ř·ßâ?î¶,† !@•„ŽĹKR€:\~§wd§G…$ Şî”A<Câd´,žVq…ľo*‚X>V `ět7‡É+=)°ó «"]‘#čI’f0 żÇŰÚ}˝ÝÁővśŮ˙7αbqľ?Ů©Ý^|Ďy ljšöG%P¬Đf>ĞР^řÝśź˝›î[§ßÔ‰Ť'VąŔQ“§ńdAXhăü„ 3«ŇÖ’ŇűŽ´zź6÷ć<đmLTÍn"`â˝ódÉđ*ŹqÝą¨+ô˙FYńo\e+)ýBX$ÉčŁ2šN6+S¦{Ű ćŚ^óAńĹM6畯Í-éqĄÝµ:ŘŃ]ł˙6Ö®–S»9Dzčź^óuom¸ç¦ŢíŚ$''•‡+[Đvv°Ç&µ4Hµ¦”>g”­ňCZ» ű::ůŇłěĆLČÄ»R/`jHGŤXŻĐ[ódžé|?ŽĘŽcdL—°gN˝Ţ™×˙{ AG{gü˙I¸Pőî—„“ł-sňžőŹ/Hü#§˘*Ţ,^{µňÉĄ™ţ>VŃ LX.m‹ßÝxzq@BN‚“K¤‚öĄýEqn- Ź1Á¨S†Ä ń»y¸ µÂsˇmí”5řm­®gťˇ’‹I” ’°ôCDţđúw4,6¬((»ŻLR!ŕ8Çdc©u|Ő<ü`Ł>`#…~hŻ1YC5Ŕ»”U°ďN6§;ź#Ó[ ©ś »Ç°çOEĄÚůMâ ŚĄ ¶Â“:dÁé"5§Ţł‰ĘĎf™¬4žŁą^nŃÚÎő•Y˛Wŕ3Ń®5ĺ -–ŃdöY’“⸶ÚCÔ–JhÚ“L8•±ÚĆ0ˇ`*M7®'˘O¶˛C3jѡ˛ă¨ßs ľV<«ť_4 >M€'Ň>Iýž}%›úĄÁąÖWq×Ĺ?©hiĆ6=ŕ¬ó/•’ď„@^ăń˝âÎÂ~Ç»¸ď{ý zH|ZóŐ›üŁ‚ŤRâ5ÉÓʴЇXâRšŻ.·K]ĺdO’=±ň}ÂJ°”âwWc’[ŃĽśôß řúśšyá~#î“ď'3SŢS–ČýzŞc;r:y`É7š"'M–OĚcĺ÷«gy}MŠ8Loí[:­QÁňvőR0ĆAŁbnß«=ç+ČÔ t‹­p“Ă śZaI±uó0»\îaÝNQ· Bëó{âĎâ7vBBYę$ĽÜÂÄArnč_ËL#¸)… 'hAÍĺňnĄ˛ĂůŕťLQ¤éj4á=—Í'”ö’%"/ńŻÇ˙h’ýĎ­vjceíŞËÝdĺ1¬Ú·Jü.ĹŹ ¸/(ţč„f5Ѧ>I@ô§óXőSÝúľ`Ĺ*Rű1"tV±#g”oíŞÝš :ć.ŤcĄ‚O«g8řwç*h&ó9<¸“"a*†^ ő (%Ĺqt‚bˇN$Ypü€çG2Ŕ!&ßTđ®•pj&i<ĚUŚTFö©÷A]¬ň“âq8 Rfb°˘˛ĺGJŤc»¨Ś;éÁľZ/äˇL’V™ß’y7 )ĂÉ”č1!Á6ĄĽ†öź˘KŤČß„4 ćܱÎČ.^Käő+±¦1ě­ůZ‰«’ÉçĘőFǰ~˛kâFĆ«ďîÎ_O˛ńÓ…j‡ÁŮîšŰ `“§WTÄĚVŮ[WŰ/Ô]˝ů˛@HĆťţZĽ®B|f —*×#|”·IPŮ.بXÉ<üúťŮI ż‡Ĺ>7–r'ÎÎţćŢ„cÇÇžĆ µgSżł©fÁb—ů|g;rŰő|܇;`ÍÇšlżüź9r¤¸·ĺ{5ęeb˘ÚËŃMËQIöB´ůDCŕ1k˝u•:úßďź»?ř´¤Ű٢OÇŠ>‘qźŇň†µöŚ€);"Ř9< ŘërÂz*0DϬd}WTG˘bX ‹ĺ**=ŘĹŹť}ŢĄňÜÇ}¨¨.“ĐŚ$ëzw"¦|HË%l—Ą­7{8đ6ýĐ…~§ŃoŽ;˝äŐ) ŽĄĽĽ¬łd4`Ť~…U|’áU[ť¶'ĆŚ˙Kaź ş[s+&Á‚ËuçÉ<—[¤uĐşňdîĎÍ Ű.»ö×V}Ż.Rętj8¬/em»Ë˛ëV»ŰO*ÝFhŃ÷ü®¬ ESćR‘"©H2č}–äěÉ\kżwµŔŰĆ«ĺďă//`IzĂńskŰŮ©^ĎĂb'ß°1÷éŔÓ÷z{‰úÇ÷ďaißj"·›T¶·-lŕ„&Ż#ó"Ď|‡.#T;‚„â&–b-TĘllʢ”· ú™ `XaËńĄ:{OŻý'|Őg{­'`ůŁE Nˇ*n@Ő Ý›:y7őSĐeŔG7IšmrQĹXXŮ×9.ń/BW˘Ű[ćëěÎ?™üňj¨:Óµ~bŁLWXiţťřľIeâ˙b‰íĹvôf]śs7_w(§ó¬¨Ue˙,† ¬{uľ¶—VŇęÚ][K¶˛ ’r Ł>e7Ń+Ĺ«Ą•Ń´Ĺ˝n^ÜęVĽD¦›gńťţK:n’»d Mô¸jť4uÝé”Ř…¤Ţ}®®­ő´ş¶—V¸!ŚŢb±Ąq”” ó۸^p!D˘ćTĽ l˝Mr¶g6d%¦âÍYÝUŔ×)Ž0KĐRŞU¬n¶±ĂčlT`řPHEöîš•–úÚ][K«ium.­Š˘ě~ż(Ăo–ęŢľęŔ ¨Ľ›ĂfĽ:RüďżO(.M€‚‡hG*Ąý„Bj)řŤ÷ěx~0đY Łg’€ăL˙ĄFĚ µAŐŇ)ŕGĎIÁµ©”´vÝ[«X¦_öR°±<#ąRl–fJo‡Ě‚×Öď4!ĺAćőƇłYćůÖßĐ-¶ bu+€&wݡĚqöş›5Ěáp*BäĽv'šHĘW~•/Ş3îN.㳆ŔUžŐí¨ĎŃ×™‘ĺ.„wĺpĐ9şr,#lŻÂG,JĚŠŤ¨ĚöÝíň-P­O Ż¨ÝŽÝŘ:… ë?ΦDNćą&†énH9^€ ˇ“t…ŹńĐÓL"ŰÜŐ= ܦjÍădI1d&bKĄDĄĎ*Q‹ç^+ ¨Qî_ÄkÂüR˘Öăž°Qş$żk ÖlÚ6N&^;m˘g+0¦2x˘W{źHŔ}”ĄĽš!0¬Ţŕ¬ÝdyńÂa˝Ń „ŃkŮm .SŕésŢv™čŚ ËMA ^j43R;Nđ«.ơפ'†!ű’ţEz#‰ H¬¬ DFRłu…j‰‡E­Ű 'ňőýWtç Ăb)˘#čˇW$Ś%Ńť­´ÓZX…٬÷Ę3B'ݸ絫Z˙~ŐŹŹ(ˇé\—jŞý`yM‡ŐyLź^1źÁYÝjRpl43Ł÷s|Ť—Łř—ĎPĄ4ăîĂŹT‰ş6O7Ô U‚Ŕ$»žŁ2ZbrGxšŽ ŹCY×ĚPnĎlKjęXaĺhk™ö§)şĺÇÝ/ę č<†)M_çđë ű}>‡¤íöú˘gđë·řz¶ßoŞmöű:cřt{ü;đţ‰—ŰéPíŞmŕ"úşęiÂꝣ]– ­ořa)-dŽhűęh)îw(ü #ROI”—iIŰ=O Fđ´íŔ ÇŃűŮ«‰Q]5Ë©­U şˇÓÜ!~Ě a¬{ť•Ľß_ôľ˙8 `©´~E`䪜0÷J«ĽŔŇő5ţlÜgaßgo5-ýŽčW:°Ěť˝‚­$HŕN3d8y*ÇőŹŹIŽÔ˝••΢«¸9ßq±öŽ’8™HîhçŽ]Ž5§<đ8Ţo¬ĘEÇ“|ŁdëŁ2n…¨W1{č˘*3‘ú&2|^A‰Ů$±Ý޵E"‚ WÉß ůŃ~„űî2ôľ{ý‡Ě[bÂ_yXĂKIŰĄł‡ÁŔOxĆúů5;ěó•˛ň@ş”l[ť¸n<ęµ?Hgť±ęD:ńŠ?“$Bx.R!­ŕţĺď÷™ą!h¤ŽçĘpë¶×‡PçO®}ř—_Ľšń´6ń/f·“v-üÎ W(€ˇ`K§ůŰĎČCůlĚHbú›_žm…ź„AFl‚ĺş\ üŐ—˙t2kBsÄ€Tm·`žî"q+14[×ĐU|\ŕö®aqŃÁ1G`qÚ'@SKPVp„Tćöu+üőąň±E†Od(ÎĄC_ńT—ꆔäÝ;~*&„ŐŽń kx: ź»ČšźvZłŻź˛ÎĎ€¦:EEyµ˛ÓJ©—ď>ź/EŠç#O‡/1BhşúĎ!ë›…wÂ)ŚM€"ŕ–ç¶G€>PßB—딜\1îQ_‘ŮŹoŢ-}9ř[š=÷ś"ʎ¬txÝ{yi×Q ş 2 'háĺI7g¸X˘ŰŤîR-ÉNR-,öęČWĎXm쮦j^±Ă«- ąűjTG®•ÁŹ—?Ů&ÍGŻv.‰úéjçÔ–˛˙D‰Ą;ć…nÔ*šQš0Ým5‘.zhé÷Ý*š˙,`Ę; ßµÝěJŠř?ŻgzM©´S¦vθôcŁhyWŁă#cÓzä¬' ŕA“ß]˛aŻ{»­±¸©˘šŢ=ů4žxq‹ăeů»¶F†úQ!Ŕ:÷S™:a¸RJZĂÁG6`Ź-Ąźu$[‹ě`Ŕ¶˝‹ ö˛»ę.›€şUčÂń÷&µť7*®‰MlćCö Ń{€Ţł^#­kî)çšŐç+seĹQóM“7‚˙€é^j#IĎĽâňš¨ÂşşÄc¦„Ě‘SzŰasŰ˝ŘX–É„ŃÚÚU[)ŁMÄlB±@LŁč÷HE8¶Ň]x· BSád”wŻ©“™`9‰J'őhЍvAŇ"Íi˙" 0R( ß$f†s™ýZ&ë%v¦ĽŐ)Ş˝‚ ľßmRv©Ć‘řZ׋÷őça_§\C—ř«6Ĺę$kť+/H··1Żt˝ě3 mËe]G5Ţj‚ď‡V@cŃřÍËËP,|×YrČ´ł€tş›âĎ h±+\= BĎQ& a~ V#ýôU\ćLř)ďŻß(ëöţe=^LJ<•wŮt’e ËÁ3?I©}1-¤B˝â}ŇuyáĽHąá°ÜjłćŻHŞ’Šů\Pv÷g[V·‘čN/ű5j™Î&sŤÇQ¦důŃőňř‘I IżJíÍW`:¸J·H»XýŐ+Őc 6í^P6éHµŰnźŘ˙×n¸†e }` WEř˙{G˙);ň9L¸ŘH”µ ٜ٠» ó^S{Ł8YŘĺăĹf9/Ť9,_ś]ŽÚĐsŻ–ě™EÚ;máUîí-˛Ű¦ş ´ëý“mŤŢâ ţAC›jžl[á.* m›"~‰TŽ’­‘âF†ěoG˘BÜČÜě„lŰç°ˇX‰ ¸kkě«f˛Ěŕ*&ă˘ă3És:ÓÖź×ćéW®o+ŘwÜŁ;~]ĎeŇĆ’ó‚?¸a\"w€Gßâ ÍDظ'<Űs[iué›4ä [šÂ9†{ĆIwó<ťĎ…ŞŁ>˘…˙C„;‡’xoŽ“'žâ…¸ň]Ĺus‚˝0-»>® 7§Uh|¤3§¸żÓAr›¸V öÇ [ eÜ000UŻÂćD:pµó˛ŕ'—±Mĺ˛âć[‹ÉÝ vóp†Ć×n—łVµB'ĽSş yŃ)UŐ$ ˇQ±čÚČd»ËĹČČ+ŽJ–XłGą“ř …Ţ| â‡ómW™&gž§ŕ3î޸›°­†) +§ăăJw€la/6¤|o2ßpÁ :ir¶*–襣.Ř:ŰČňôţÁIŞo×5Ú±ž&”ŚRXŐâő”áüuĺ«›:óŮÖ$ű"OBř(üc=‡]BąfÓÍ·&ĺÓăé”ČzZŐŚçŁL˛ďCi­Ś¶}Xw*öó̉ ’#i"<ţťp«‘q Y@ŃX´L€ßő®˛`Y÷ZŢ9˝íďFŽ”}†heN弊Oo%řT»żqş“33Úďž Ňbd«_%‰D&qĹ1’⥌{­Ů—Ń—Ëç)÷ Ž™•۱Üę4Ůn×µEÝ„ÍÝARÝ…›oĚä‰y…śu#^ÄŁŰM[ُÄćkOyÁ4ę C7‰×ˇ‰3^kÖ1,“[Ô'^wAŁ%Ô«ć¶ď BŹ{yqĎfî·ťé«”HA°aňż™$»Ö«Š˛ťË3P‰˛ żâ†Ě„ĆW„XşsHm[wlr—Źŕv‡>ŕ–‘_ţ\.ű˛ęšű'äÚ›> T&}$qoď·D=mMWËd´ĐĐď¨UĂ­vľX^ňĂŰ‚ÜÄ0DhRě˝ým „!úŃĹH­bH­QáÇŤKýČЩ֩éW±>M.U%=ÎíĎX‚}á@˙DŇ›č$[5ţbjîYÇpÔŻÖařpüöŠ7ĘT.»Ł›ŢVN5ÎöÍ%˘˙<ŘżŻ]ˇ”‰Đ,óýC„‡|ĂÁv‰Š9‹éŽ™[w}óŻ븖G‘ś3š˝n?ĆíסĚŰÇO«\ćQ30»x¬G•iYZ6 îĐĐ÷"ËoTMiŹÜ2ô-¨Útî†rîútĂ.¤¶żľYËR/—ŘştJ0–lpAáľ>•y¤7%ŁŇĐ@×ďvë} |xęőőĄ7bń–˘,?~'|€„Ëź$v߆[Ź*Ëř´Śi ´¦Ś‰jM8ŕJ ‰Šb÷V¶Ę’±íÜ)YŘ‚ Iő“<ŕ‘ĚcM©ó9&źŰšźö‘*tVbuSŽ­ë–ĎÝČNş0zN_~´>ŰDKŤ€t6V÷Ç,»ĹmÄE©řyî)ÍÎQżpÓ*Q,>ž¦6˙Fmčŕ€Ŕ•"U“LÄ@%ÜSŁw10˘)Ą™Zg,ĺIĘu´»üáÉ@„ZëÇć/b‰|Y‘CíĺpŚ•‘ßČ`Ä µÜ(¸hpţkRZ±W8ĄÄq‘T˛ůŰ<¤;Ű+BŐ(9Ľ"®ń‘¤ĽP5¦ąIű-ů¶›ŽŔÍ]FOÉyôž˛ą MUa ˙/}fÍ+Ůž µ˝*ÇŐ%Á×&Ć< ¶Ś'Ý3q\2Ű3oKĎs¨mgŐ8´;Ç'ń=·!–nmąĺŁoóß´—&ĹÚ«ą{¦ěIßŲ^|"}7ä˝9ŢŃŠ`)ő+2áÔ—˘W3î=:PI÷BÝ( Q(‰“=BČC¶đđޤ˛sf¨+z:>2šľ}ňŇ–ń8OTTł#›r2˛µIŠÎŰw˘˛N ń­Tu•_'qź7ĽlŽÍ/Ť÷'5Sć8Ű·,¤ŤFJ‹Iu†¨ÄÇ FyŁ­’Ł« Cůłv“xŰ‹F§ń¬żj;f-Ç=;$ĹŽl^aq8ń$Dnř1hWkpĺt¦1Đž ¨ŞćźáeÖ]SéÎOĺT4¦j)c#ÉJ^[s+mľŕĄ´ a 1¨Ĺ0jc‰Ľć2ťDN.nŕěňġjd€týqşÜíGO?čY~±¤†Íj®ٱŢ·Ťpűˇ˛Fâ}ň*Ń7¤+_ď”k¶Ô *2×n/H 77ŕ˘zđiňo䇖8‚ˇ.Tg9—;hţ~M‡şç=gÎŕŚáŇĹUÖ–p=¶ĘĹrmE˛qw‰ŹĆÓKá(éĄă¦Ůk­”¬9«©qnçí`Ü9éTá‹!~<Ç\ľHŇU}˝6+µ *qBí} «§sĹÖźĂ'IfÝ|Ęěľ!˝ úR¨ş÷Ŕ1† hűoXíăĚ٦ÝVÝO˛ťĎ—!.u{ô«×aqZÄöĐ.Lz‘Dź)áŽ/×H“S‰@Ůz‚«=ˇsĽ.čwŞ]q6)Ď?’ĽÓTĚP ÖílOŠŻ„“9(”ţ0űÉÍó^RaÖsZĐË—pPŠ<"îÝ~ý¸í4č•ućŔăÚ#1gI5ç‘'ä0iź1ɰÖ3Użľźît©ÂăňÎVůś:Óě˙?­!®áNV—˝N2őQ%Ň˙4dŤds÷©0Ňe¤Ú`ý`‹aŔföBŐ/]ż :j)ŔćE­woˇÎÎÇń««“U‡pÁ¦Ďź@ëJUµl_]434µŔl>í!9<ĺgĄ€Íá·÷ţśÎ%uíg-?‚řşJę׼a2[N“Cöj?Ë K“ŇŃ+ĺg'L;m~ĺ|\Âď´˝Ő…lOq6]E A’y~éŠ9UvŃW™Á ,i˙=ÎM{Pt1e-§ÎËĆÜň] ŞĆťW±Ü&[Ľ¶ G4łw4~ŞĘS¸T¨Ă Xî¨M™B=ťXŤ¦±Î6…őĽŕÝQţ2IŁl¦„$3Ç‚?{ÔiŘZAUKĽ‹«ă’łFFŘ 2'Çíh)ÉýńĽWX°ŕ +–‘ň i‡9”gşCYf-9ĺ¨~h†ě¤j»Yv>5 uJ?Ű"p΄k˘68fmoüÇĚ6P«Ś:—𬱆 KĘ[PHěŕŐ|>ś/ú©1fSżvc±A† t8oúÄ %G5pf0ÚëKS°÷Ú—|pqČ1í¬Äćż6ż«šë©ˇ S«_i—z„Őu6ĆŽ…Vě­0lÍMË5/Úâ]‡• ¨ÂŘŹ›¶hf<“mčĂM@ĽŃ’óą š}Ő˛%ŚĄÁp¸ý}ĺÍDţ ňňđňĺÔ-HuČÂaďxM †ĎíT…"ĆO^4Âí:çh…áńWz%»˙c‰~üG¤űA  ßěĽő˘˘ćŰěFôzŢĆä#Ň3jń‡ dP°Ç KÇ” k{´ńÜß>v“J!™0k“ż,'xĹ%ůdśžq]0 ÷Ý-ĽĂ}© ´Ä¶rʵe*TĽNÎV›áAežI\™mĚËŠ.©«Ô˝Çš$äë/…«7 VsŚŮ÷%î-±–+÷‚ß™¨<´] 5¤—M•öńëńËĺż%TłŰ‚*\‡®–˛ąµ¨¨Ű*“8_äHfpÇĐB ­bÁ’Rű)˙s„Ń—›l*™˛Ę#0ĺk>†w9můLAI™ţ˙e€ŤĽÄaK1Š®ńc¶ŚŁf ˇ`âü–ůŶ—ËřWҫТÖű"żýő†Ńł*ÉĚĂ’ÉŮľbťYwäĘL›°GAĹ_nWé$‚&›zpLWbř*}5ó˛ ==U<ěqʆ.všá˙0?FYĎzĆ[ĐžZSČ’>±—ŽłaÜ‚AW°pL7Âcâ}ťŻĺ#tc¦Ö’?ÇíŚ]Ę˙l› ß?ţ7Źw:3ş>~  ťĆhŘ·ęXŕeŁÇ»jôuQöć1P•˝!áśŢ€!;/$TEź$Ą>q( őyeęťaBÎŞFąĐ-Í ßY$^Č~řř‚ęg¬}-Ôną€W‘!˘°Çz•ű%”×Çš~^ţuT"”Řcj§˝iś©@h7: Kćrş©)LŁg¬UÇÚ9°–`žLöäYJXůd8ůcašßźű7KĽ[€čÖ\“Ź˝oI,ôd‹…đRćD}+äéŘTVaZę ¶ă/ËĚäŇx ay<ß„ĽäQđŮäď†ú)ę–ßÔÓ[86!2˛JđSzßćt)=ŔO'–Á®¦›p,Ę0'Őú&ͦr…ú‘Ś^¬Š¸dnUfŠ Sţ‚‘N%mNđ‡[AżwŃ®ĽŻ·ňXSU8IÁBBśőÔ\c÷ü—B1ć9/ő7ĹűڍŠÔŚ_ÓŢ«Ć Ńž—ą×řt87ä°˝Zí?GGď\  Áčy…=9(vÚÂNČr:6\o6g=l[ëńť Q˛\˘ĚÜcź{M篧ŔCô\tą űť2ź{ědŰä+s†p]µ@a‡Ďŕ VŹ?1d0­Ď:kń ß/¨‰Ş@ŠJt›ÇA6»ŞRÔY¦R"ź Ŕbhc¤gú«pŃk1qF%,:,ŁÝ¦Ź6ă4’Zcţ.ÇPÉ…†ĽŰŰŞ%Éy˝t"ëčĆś l•㏻Â|č'ex¶ (űÁE˝č)T?­đîy'蓵⯗/2‰©Gz?ak‹ ‰üÜňT_övtcľľ·ˇv?ă%”JĂüZA=˘U[­;YZŤ ¬O«ŹC´ŮJ©‰a)«ý'ŮVUŁŘÚă †ß0î‹Ĺ1€f®UÜ„?ŕ˘űŔX3µú¬Ł=íş`č]†Ą˛ä!&ZˇĄ^Kkúk"ţâ•rĎľ­fMJ¬DůîS«cwݬ‹ÚQ"Ţę¨)Đ0 Š­’ţÍó/>!űîüőôqBŕ˝â±ĎŕQŁöB`§ńu—C<.{%ěS Ĺ2Ś8Wĺ‹cąUáĆh©ŞGű,ňýő‹Ź{Ä[>^€c[*2rť\vq/I4Ţě"÷Ę Ďô”ČOµ0–ˇ‘¶ Âa«=Aßi•óă‚5PĚL‘ůÉ“:0Áŕäç(WíĹë¨_p"‰ q«*(ŢĘ=Ą˝ôh1IÓ¬z†ż–‘Ť;ásyĽUG:Ě,ćŐ?MČ…¨?m®ł©¸27Şópň“yÁBQ¬APYÁ>ĐDöW]{‡őJĂ}Ś#˙o“„ŁĂ1°Ň ăŠ×ŔĆ.{;fQ;ŢšŤşˇ‰ ţ§ŁÎh8ó FŠ÷wGN0íJKďbTÍ4óĐ`ĘĽ0™ś8ĽëÔĐÔŹ.…ÂĎ > đ$:âpĄĄ€ŰĂf@©ĹîťBŮüKBssĐęvŘ=BU$×ŮNrËgÜű‰dëvKÚ$)AŠ4ˇB¶,Ď™ŕ(±‚…Ö)ÚĹ… á×ÄËŰ?ălH9}Ş•V‰’ëKŇăVQ<(ś&#QvŰÔ'˙x4Ka/żx0ä*݇¦ Lżâ]Y9%•'éÜRîÓü@@YsĚy Ô'”<ŘŁééŽw‘SÓĆžË·Ő áQŚ—g$Ńęí«»—ňA‘§‹>pĘróô/÷dP! Îdý3%íťËWGA§ş­ŮůÝĘć{qe=FF60!X-0•Ă!_ ­hm~•­p=ý›¶ű‰y"ř2M¨óE)nJ©×ę.d:eĚf?SĆčüwX¦ZR– ’ŽFA.®h?ŢÁ¤Śżbż°ďťkRaÁ ôŢŤu’ Ku*SŽ\µ\ka :ŇÚs'|c9s‹¨ů•öĹrµM3|x v>ĺ—čz|á¶dČŰrŽwŐ®¦j-Ńw>‘'<šŮó‚üŻóeÜ‚•äPei‚ ¨V…đ3â¬o %Ţď:ËOD~`J`8×’!:Ę·dËrĘlB0ą´ćËŔÓ7çŤŰzá=ĂÎ}¨ó“٨ ;:8®˝š0fpMč™<1TNÂՉȉ5S-<#•6“›c4ËËÝZ•°žJ,%«fd8ŕéî¬ŮÝ˝ć˙{ýč‰ČĽěMŰK `˛Ż×vŻČ鯒_:7µŰăyg>ˇj΀La·Ĺqš=÷ߊľń›ą’{ćí…X·N 9/8j6ě_|˙DI˝6•Ř÷ź™a)Ôąţ&¸UŤÓ3?ÓëSrlEÚ9půŢ…XqOKôo}eëŢ+N†(ĘâÔ¦¸GĘŔ°ĺÚ« 3Ntb¨†– ë0"KކjvŠ ˛Źág$b\2“"šćżćj N™P‚ĚcBA ĄÎĽŰC:,­Šz0 =Ä”îĚL y=EóÜł˛ ů†$QŽâC!ŔM?ÜiŰlśĘ}?ýSĘĺHë®˝¬‹SÎX›>(ű5ŠĄ~´«r`@üÉ_.AÜŮ‘ą|Ľ‚ Ţzúo{Űa¤$Ëĺ•Ęĺׄő‹‡˝ ńâĆĺń1eČńú™M!¦4xmS™Ç÷ˇmůsPĺ4»¦UAoö›…Q§ű8) CóâAŃ=ąwE® -‡"ź[±„đ‚řt%0Őßš6˘ľL×Ř-ŁÄJ9%îx˘&eŇŹ…€śďĘăĄňŻ9; yPQOˇŞnÔ)ßAôĄĽúó´ˇ<ăďa•>ąÔŲE ô÷¬±śCY– p 3ÝÔ'j©-@µ{×*áĂß!d‡ćagé8úGX*Ň’ZmgFŠ:Ěn’·TÄÉ˙ACUŢ_Č@ü öúbź=RH“P- ż0!lü=9Ňî>%‡A¶ŞÁvõˇ,ČłŚP ‹â?±<}ZfÂk#0#N@1ąÄݎm?źšéĽ”˙` Ĺ.h€ąĆú۵g˘?¸<đćű¶MTžä;_ÜžÉ}ąřLęd{€g’3ńҧĄ™ţÜ•‡ÂuKŽöq4ě­ŞĂ/a5Çó.L&ľ¤1±® ž´‘iRqŁäbŻ›ŤËBĘ·®uYyi'ʦ‰>ĐZéd_dVą&WŚţ›ú+,ŕ4čĐpĂO>š8yS>˛JY©3Ů´)ܸđřZ ňč6˘=Ý]ŻŚKéu»‚’tËNŘ÷J&·co]í‚5ç!‡mŘÖrYÁĹöŘş&$fŹÄ‹‰5ţa3Őŕ@ů«2ןńňOăҧÍé€i>Ńůás]pů“zŇěFTŢp‘|h]ýmüîĎ{şa"düבôÓą˘4LĽQy´Ä@ë¦5AćőÍÎw!?`*đ&ů¨O¨-5™Ö÷‰Z—¦ß•Y÷ÎÎ/Ű­UÇk D/‰ěÖŇ˙*1eobŮrJ!;čč:ÓÝ?ý“d$˙24GZ§pNqDkálđ«ĺ'ÝőˇŠ@Ôí»3¤€o—Ŕ ľĚ6¶űĐ ČÝ=†°‹ĺ‰8ĘžI“5kxˬćřâăöĘ×5Ę'Wĺšós™K“#K:kľÉ\ż—ąĘvehW’¤oC‰ŽóÇFÓ ĎS>–ę¦ŕA ¶m»čű=¨RQ^¤éE€ZbćÍ …jë'ý' ĄĽ'IC7!m š]MfŰU‚•ÚW{ËuŠ!R˛´Ő§°C¬ecŕ·(F™?ę+äZ,DŠßJ&˙0©˛Y Âśdűľś¬•8ÉŰeéŢO&­ !Ôřaď9 *]*']§P)âÔyúÎϦ؟Y´bH DT5ĚÁ¶ŻÎź#ôĎBk/ŐxZ’üE—‡_öămÝ.­®î«)’–;C>pĹžÉJtäËeŃ-KF «ÂSa´»ăk<˘2§Wčf‰‚ ď÷×čę–"[6ĘÄ1§ő«V»P´nčÚž$=~2˝şYu5ž˙\ţĂËŮ˙X^‘‘±"‰d)=őéfłrsP5 9Ѥî߆°Fl#»#¦ůÁÓ/«Ňȧ¦Ŕ€Y17ýÜE<Æ;~ÄKH¸ŰŢcžH–“ÜŤNޱ|*Ě@šv!ěBQ t팻ďš,Ýřddcż7ĺć[šEh©?× Ĺć…á*f„ţ_·Ĺ™ŐiyŤ·ś¤;± üÝSW4óôA€ ŻçđEÂ4ŞJůţF”¸Ž–H Y§ÂĎĹű"ŔoůđM:^QݶeH^al¨]J«ÓR-ŤČ…ý7|Őí2ú$µ˛ëVčY¤*Ďü*¸öÇÖy'ÓĂjń3ŚR[ljSăßę‘=ŘřׄźŐŽC$ď ä÷†{.—ŹXŢ3szŐ…ĹU“l ŁŐĐÉĽq~ëęn˙ĂDč‰ŮIć}u¦\ÔTüżzŤnú~Üę*Z€Â^dĄ­4â-BöSqmRs.#0‰úĆ«đž·@§¦ăgß“g€¨Şn§sásžĆúą)RhÂ\t›WPaۦ|Â÷eśIuŰ-!†JjqâČ˝ÁčD÷¶Ç'˝ě-c>Ťg¬·˙I’™u!Ĺě*qç´?¬ŚŐ,«űŻČ4ÓúSk~Ď1{Љ}\Y 4@ĽJŘ~nŇ=•TAó’ßń¶r—;%Ţë¶ă­”¤†@Ăŕ'gcü3Pn€rĂ„Šo@/ÇMQz¬0Çćż X€g,Ĺn˘]°ß,@áăˇh ó|3öL ai1˘ďöZB­÷›WćÉĘÎL…ë÷uMVRGfúEĎća§W¦ŢMĹô(ŕž—.RŽđ! žĂiđ ]B…ťx[?ĽŃŘQ§˝ť—Y(7L=9 ľ¨¬3ťŹR&„eodµâěŃqEłŰő5‡ąů¦„ŔşýĆ ĂH…ReOڧ"y÷*žlC·>źv^sĐ&Ëp”smrŹ·ÜCsKí¦ĺČĺݶôś ‡82ĂhŮcŃ Îm "Ó™µ~+4 ľOt´wÔfÓÖéVâ ˝4hQK„µ`M1Âň¦ŐD€?üSáśĹUÎ1»áÔ.¦Ďo3¤fĄIż<í2TŹ“rďb?L÷’FŕB(uůóäl`QŘ .„”SŘOh<â©QΨŢ8&śYwĺ•ç9ű_,RÓşÉK€ą—mŽőţRgÁ]ŕ♚‚~n:đE5S+'ʆŢČďeňŚ´6®ŤIšńúť9 HČŐm“ç`íňĆ×#¦Ćžˇš·éJP˛×DnN yĚv}~Ö0±5·GoYy¬ ŻkÓż¤i]ńU{Qtoě›EPíI˙4Ř‚~Ŕ𦛖ăŰ„ ˘ú;eqąy@ď#Ďç»sŽ»UdJ~ĄM[ďł‹y<ĆéC:–z˙y>‡ŞÉ'¶\÷©Áúô¦Ś=ň¤N‰BW¬·ÜşąáÍŚ ©2˘v—HH=J%´úi„ᝏđ(ŹŽýűGżÓ,Ż ŰĐaC+hľmą×;sĎ®J¦*g9/Ř| ¨Ń?şĆĎŃęTôcŘBx¤­ąÔ?nşr«Ť4ľKŞ˛ŚRa´™Ď…QRŇ‹ô×fpľ^€Qˇ—Sţ¶Vj QOĂřžŚ p"Í©Đkš…ŃúŕŽ^,„$&_÷ž•ĹÁev‰ůq4pó»‰yÓś(Ďý`Z»ľ»)„îrȆ{Ě®Î{xpŃĆJ‘xÝ»ńYö˛ ¦=ŘËT­×ęť ‰ Ů#˙DA vŐD~©~~˘Ó`EĄ+žöboĂ·U#°÷ŁübĐN*”ăb>9é˛~T›´=UÜÎX›Řŕ¬úąČcŇp6Ňç[řçRCÍ&µÜ\,íxhGřęđGBŹ]úů¸Ś›ź?,ěĺÓ&řS‡L‡ĎꀊQ°xĎ%w@JóźíÚ®¨Ĺ¸äŔŹéŻől9·#h¶ďi ęW‡aĽëR>U-‹De…_a08Ě/|„«şµ¦ů|7¬@®^ îě8¶ŞŘy{Kňgn¶ůFhŁ‘˘S® ŕęő¦Łx]ńśł}âOTĺX’} rÁëĘÁŽ —>"ŔáŮ1ý‰±ĘłbČŞžŐEŢ×ÜwĚć2ľa‚łö¸_ˇÍčFŽÍ9˝–©ëÂąđćhęl„!ścn'Ž×Á–!Ćy¸˙%äŤy{Ćo%ľČÖífHłĚ{DŃdI“J–"Nl~YgďU¤O8 •ŸÎŢ]~šĂŔuAÓŁâNDč—&ů3_ţ^ońůš§ł’Ž weâŁp‹ôŰÎhŻç" žî"ß ÂXĆ7'mjű:l-Î5Ů6_3]l¦ě·ýgr2¸ĚŢ“Čáť$ôît×ü¨ŞŕÝŽFç1tfřĚąŚ#ýB§Ť¦ţl´!ż•6ŽŮřżYIővśnÓĎYßXŘ•C– Ăź¶ˇ®rOfD‹,᪋„Ď0‹¦Ňx¬ —˙7Ĺ‚ŹAŰy 6ë·Žeýůg%ĺDńźµcZKěDąď©Ú$T˝š <ż śc›Ĺ• —…ÇĘÓĚŚ·Ţ˙'@ÖÉÔ\‡JŔȤZ¬đŞ?ĘŇŮů<6CĘ ›’ fBÎ5„8†Ú0…pÂ>ťJFŠ× *IMŠ‘ŮµR0‚#˝ôUĘü¨ kt·Îđ±”yÚvłă«Ý×TG ':ŢH.ß €vĽAľ)B[đÍ}Ůšˇ iűE‚ŻAĂŹëÇžő„çU=sĎę°»¦őnŤqѱ›‹.ËŰÎ‚Ł®ÝÄXJő:¤äÇBŇďô˙«ż ęˇGpNÖ´&^É`Şo­LŻŻň$€c .CS“¦Ş,~°#°s;×ÓnŰ@0 IGz«x*Ćĺ[˘ąĄŞRÚ¶/Ŕ­ß?Č\2QŚ1 ¨ ©ĐĎÖ@ÉáÓ†É^IĆ®falć=n@ĐI´EüŚßRYŻĺĺ^bÖ!Ő.1ĽDfąťb»WóĘčRžcKpń>·ááö6Ł\tQ]îęa§CE^˘¸ÁĂ‘­µíżmöĘ˝ŮţâlěĺµÇiÔěĐŽuXíéăŤÚ)hÓ†ŚĚZ~«WĂÇŤ?źÝNůŹ'Ź®4sŐO[¸ ďŞ4A_ĎZÔâWďnńü€Yß"­ˇae—‰)ĽMĆ PúÜźZ'Y ÎZtë­!¤Ü¨„“ÉúçMçv°ć·ÝË 5äU_ĂfđżźËpZ¦/öX5mWTuą°˙xČáî1€Şň;g(Ž÷9$ÚśBŠŤj7Ś?f¶‡Y_ GşiO9™rÇLŰßP˛¨2ňEŹ–Gݬ®>oâ ‚6Äî©âPŠŮ>p4Ć EŔWkRsHÍKLNAÓţ‘ |Ę‚ěȸäe2i¸żŘµő¬zę›ă}vJű3‘b¶“˘˙p‚ęúŰ ^3ůÔöH»·áÎ;‚‰˝nü[xąöÜŚ4őD󷊶n-ĐiÍ€˘R‚QWŤ˝v2ţÁŚ Çşt__Ëö/˙5©Ň®ěxmî łÔő…1N»Y[ýÓ\#ĹUZýť ”…sD©”ż!PBF¤ăęhţP0$¶9üŔ˝>á DÓ ˝LŘ4?¶RŰý ˘äöÓĚ­N9CŕE‰î(IŕżäkJQceDí~2;C+Âśů˘—cI«Ô§Îi™"Dvoo(×s¬,'˛6ň?}˘äýVá|ýý]!O“ŐDů=Oa|ýý]AĎ“Ö\ů=yŕľ~Śţ®ťçÉë"|žş@ňŇcŚËŽu ¨˘Jdଏp–Ě®K1ą«y0J„S÷ř‹~ż©»PŰYęçNÜâ] z:K›âśó|Â4)EbţÔä5F-»ź7Č–"3ËćÁ™ žGu;ŐšÔ9ŐĐ´jÓî—‡Oĺ‚ů•Jß—/4~źkcł†Ót´±ĺÖ)XÖô§Ă8îiÓô—š”ĄĽţłQ‘2đčŚO?B«§ÁgăÉ9-|ß¶T7tę{Ü ŞŚôŁóÚÓkünĄ&č'3Áqq®PbAjď‚ÝáÍPgĘgz K=ůŕRĎa-#ľ¶)^n=…°ż™¶^ ŚNSâÝĎtdQۧ9CažŘđ tM0ěQăÇßć5ë¦58>1x‡KsoďZŤ`{CÉ4€ —Ů&—(*Á KµrsgĐ7^ s4§ }čˇfŞÂV?MŘç*ňô~kÁĽiě#©gČ\Yˇěíľu:\ݨ«ëKMëÝôŐĂĺőAŃ i(´HÍ*kµ–‚W©~ˇâ§˘ H{ŽMĄEÍ1€2púz§˙mSŘ*őH Ž×ˇź-´ tÝZ,s/ŻŤŽżĐ›*ľhűx^ŘM:…KŢőäQ5IŠU†čz¦Xë¨w”?@T!c±:¨WŐÍćžPáçťľH‰!M5é;ŔŐ¤oU ŮŃ ü>­L…˛¤XΔnÁś¬‡˘l†Řsš÷ň$ Titń§»Öqă˝6ZŁč­Ŕ˙a¬«:8pNmHÄËçł(?µ řs'ĺk†jśęÓCű°{>kDiěşíô;I–Ďt=óČ!ĄUä#»§ýµcşí¸Đ)á/ JÜ*Đ=Ëeç’¦ů~łz€Ł‚,'ľ‘DBi»ŇBí©„†ÔćrJ›±´žeĆ8$Ŕz—Rb|Š/đą0wĂ"‰2űŞx?‰Ů€Í¬uCd8ôg\UR&%d_Ę.)Yąh)á/çwhÝVŐ‡fÍqŠ˙?fAú|űÂa´ÁgđqÍD.q«tޱŹ|óľĐ"i}Äď4“ß]ß Ö=J MBSÍmŹ}›,ĽŤJ…¤zů/c˘ ¤rĂ—v›5öčyćŹ=ĐTC‡©žsĐîŘ ČłfAśL¬¶Š ĐŇ@>Ö]źŰ€çl i%×DdµňBŹ[ű6—H(áfÂzÚęQe†IâîPŹjĄ9€†fµ Ř]cĘ€«±ŁTsmsÍäď»ń‡Ł&AO/Şiëo. 0/"-Vżď9hX,-‘xCÔžH6}ĂěšţµPs:9C8ç0× Do~ßFQ[”Ią%6 `›‹•!¬ )IŇáâs˘Z¸ŽŠÚK$ë=OűßŐŽW˘¨‰ES§ c/±é337U1ü”ߓܾ‚îM ­ŃüIÔdď ·Ĺŕ5FáD¤‡ú ßżEQ0qhŐ{~ lŔcbM˙ góťP_‡ę/âkM·™d…‹f‘»ˇŤ%0>]»ąęwśÇodőőp¶ÍçChM5ß{QíW‰ Ĺß;/ҵ-đn=×ZF׍ëqź©Ën‰Ńž¤}xňd¸©ÔŢ0/ßĎ©`V¶T<’ŠĂëáeÍŔú.hb¬.3,©mťÎ6PآI'Ľ˘v€HEŠçô÷RâP»oşžüČ@çK0Ť‚´N#˙1ă„Ú±Kj´š @&DiiĘÉdŚ_ďLHĹ0\mŢ+‰˝nÜDşv=üí-W*•¸~mXěÔ·5™ôŐ‡C`±ü±(y?÷Z™1xáđY»ŐČ]Ń>éMŕ^ˇÖ ţUŕós} Ł›$Î9IÖĂÎäf‘ĚN&ď“ÇĎ’šMOPj¬Ž”ţçL¬0uxúĄ†&ß鄟…>pG§(:®TE豑iŐ“śŹF=醮m1Ă9.OpÓs¦nIĄ„şő(ލŰ ÝmţqB5˘qA˛<ŞĘş!ŞCU˝ËM®´%řj3v–Y.RYĘÁ…+?`t•×ŰĚBŽÁ"^#ʬ–ď„>čU˙d°ěŻgţÄ6ĐgëĎKÖáQ@BU03Žßúěť?)ÁŁ–jÜĽZ­</§›/Šs1p?ľ$Žż%-‚y „Ü:Vçüć±´ńłŔ¤‰|8×BWáŚ~aŃ‘¨ĚBq°ó^‹TíV0őäą5±HŮ-ęg%* {Áz˘ŘČ, ص#Ńŕ™bESG,ߥ‹ăä×ËřEÝŹž;é籨8Ä6a”Šá9˙\ ˛mé†:ý¬F»•¬x`«5W·ŕáÍťEŰ%ŢÇrąPđŽĺ›çÚ€T8DćHAŽőťŢ]< نA»Ë€<$iÎQ˝‡8†–bmc@Ěf*­’N:óňŢŃ·8^źĹńüěŞ>jgRţ$x©Ňš 9Gäş[€ašqűůçY*Í>vĐeˇąKK)HÇl`Ń©jŻŻ'ŠL$t{—kIč5ßâćďo¦8řˇfxFmť‡Áczč$›Xw2Ga:LéŮ®ôőµ÷˙oć‚ĆÁřřT™í¨S‚*˝ROyµaćfŚ,˙MŚěCĘâ3ĆČ%%Z­×Ű3cŰĹIĽĘ§đ4 cĐřtÉX•”Gˇ‰q–80—Ésľ+yRôŽ‘i6E©W¤TqŢ7…±¨‘Ń^ěĄŇP!ë>B[Ĺ©roţATöm)ZřÎP2-»5Č:Éɦ%чzçĚ`Żm pżpcŻ—D¬ŵUŢlhH3Ą ä[›÷Ú|#đÂAL:C>m+ŇS©ŽX†Žć—SWŔŤ ¶|OQ¤+˘ěŐ…!Î9‚ÝŇ›AtĽ€eŞl\$¶şäš÷aw~ÎÝŘyÚ“Ę´aßd†Wľ$~!cĄňňźŠTXĺý ÉßęŔ˙7“;ţŤvQşżŠ(Izä[ÄŚ ÓÚ´{µÉĽĎáKăÉ٤Y–͙֡üíhűű¦|ĐpŢ~ÔÚúźF/Ń– <ĺ ČńÇK—Šé3,L®ôšŁíę,"˝(Ft9¬ć!q‹ŕźh–h`#ˇĆÝ'9KQ‘kž`*ĚyyDĘOĆöŚkPŤęއFqÖ´ÎMËą­0ł­Ç#ÎUaóT Ă0¶'†fˇÔWkĽ™Pňł‡sá_•euŃ ,–šĹ®}ŕ!{˝Íť  Ó&ÍŘJlÎBĽS <Ź]*eĘ1­żŮhtż6>6Wz!â%÷%Á ·#ĽsiNd€„9Á•0Č[ű śÓW"Ţ,»@ăÖtú0ŠéOI¨‰WR‹ž&A Ŕ”´O|-ţĘőF×ĆŤŠ×-rŃI?ßqv¶˛ŮCą<ý傡ŚřřfÍV˘ŰT#ż˛\"Yu>{*RŤŰ°l­ćaĄ¬!}BG1Zsü3” ŰLË'˙_öňůM@`şţ }ĺˇ"ˡ`N˘żBCĆ_A§ĐŻřĘ­wÇjt!©€ÔŘBUâ«)˘8Éb'¬#73z:}Y eěKB"†'8g@Z€ř{~ęBo§/w‰Í°¬Z*ÓűËb>ČJTÓ^bŐ¤Ú6đ˘pÖńĆlíUYwă§Î˙ÉůÁŘ5ol9»`aÔŚHvł]2śŹMFŞô„BMľ©:żc ¦†*_’⨜ž*±áÇB˝ź±ŐŇ™ í7ÇhĚÚ!!ÖjbręÄŠ^Š”Ë¬4ŹöüLfĺŇđŹŤBž5¸Ź­đőí/µ†Ü‘Ô®´ý(ę?­Îx$‹÷ü¬Ąlß LÄžôđרšŹoŔ8Ě^ć>¸čé#G_&Ű(ćgŹăîaŞđÜ’€ŕŻp>6y/˛Śü&*h&®őW.8jůôxµ›] ÝŽ- Ľ/ţe4_sŠ@đś0˛Ě\Ѷ~HK™#ĺámĂ›!ƦóŢ+Kgďń…üľ;ż-~2][>ÎÉłh°ćĄ˛ŕżŔĂwÉ2v ©sí!EŠ ±¬ F#/z(5íş®Đv®Gł€—%ëltÁŤaŇ˙O3‚-šTĘŚď‹;˘”ç•aÔ*e{ÍěĎÖŰü>Q-w^N~Ů@d°Ź{§“(/ćÂy‘BMcÓ" K¶…Ô¦˙t“K’Ś™‡¶H±gżřÖŔđůÜ…f­¶ĂĄ˝üĆví^Ô¬ŹT´’čŘr0ŃüŐt@×—'„đŐĐ9-?K˛¦G~ú…Ą1p¶+őŰőéđÚ®˙]iů~7847ö¤g€űłI„ľ˘ăztŇPaÉO  aŁĺDL¦§FM‡ë°®»€ł¦h)k–Çp"s¶‚  u ­¨4qâ’îěô=ÓF<ťÔ·iGŇř`o] G© µăcTÝřU¦3UÉĽ"§šrę2éÄśČa[˛64! P•ľűâwKöŞF%3AbÁjE6rh™\ÎÔ¤ Eć‚–Ę0Ű„/ĆÜ{)şĆ˙J-Ů&=ÚĄĎAC„‡¸”É™ô–¤Si“ĄN6l“°ąGZ*T^BłÔ "Ô) ‰±/5X€sŽżz]#‘y¸_řaC&,ßż÷úuĎˇŁ˝»ĄE73Ń Đy ¤sî÷u'‘—öLÉřÖĂ~˛¦Ă®éĺŮę‘«ůz˘ĆŤb˝łá ÚBSúĄš&í¸XÇ)†Ť6i\<Ż$<ĐQż#rRhiŤ#9í“ţ]cŔ5ş?¤Z®U ľU[ďsBžç®žá$^Ú2ż~zCĎÓşD‹€č?ö *eKŞŹQŻ; rä×ňüłcą˝˙~'ˇu4Bˇ8ťeĎý«’›\âL˝ę– ąbŽGžR‘®ÔlUK0VËÄ–är™% Ő ó7O5€ŃgŐŹ–ăCŚăęŔú˛ë¤÷Đ"ä˙ ţ“ęró‰˙_ˇç n(–+őýŚnÚAÉGž6ɦŁ?•m.X–ĺ5΋™R·HÖF`˙AŁO˙C|1y5hbÉç¸ě‚íKš¤˘6!«oŹÚb#x2u®ô±?‘šJĽü^—ż»Âβż3»0ßöýOö“[ęhçÍ8< PCŤŘ×(H=Ě×0´k Â4đ?›Ĺ‹Ş ˝z "µ!Fů‘ł˙iOďďW.¸˙rrßĹLłäÚ;ÝY9Ôź%ýN…`ćđŐČ( í}·x+3Yß8¸™NÖ P őKx…ČR‹wß°ŕżó*ôéHżNís,OH|ŐçüKްÄ&łüŤgę2„zMĂP2ł‰}­:ÚµGbůč«…ËÁüó‚«»On&]0ÖŻźW yIéě`P)OPőC µwBŘc¬Ű4¸1ý+2g^˛Ax÷s1ţ yć®ŕ’Ĺ,ÄD˘–…–!VÜ7ÂĹĆ«a0uÚ=Míhă]íyé$NüăiÜ«űŹ*ĄŚc—rA ßJ9\îi =h.Gt…@¬‘ţu ß— ޵3(Ô‰Ä!KSv0Sj/PÇ &—qsÎ4äp*Gvů\y®ädDŇîśr  ±2Ah°ÓěŁÔOФZ«.ˇÍŮĆL{"Ű]‚ şč(ĎÔŮîS×ĂWZ˛ç8`Ú…R/€2ĺxHţ†cŹŢ&zš5ŮY‰î÷*E|‚—A(s[§ÜF/0…ŢÚ 5É%ŁWÓtżoąÔôbUĺT‹=0Î6 aŽËOĆVÚ{eďh—”3÷™$łąâ"§7żĺź.‹@˙Oz­Š”Vĺ—Ă)ž- íŞTX^‡úÉ{üť ďŕs00€v}‰Ľú˙XÔÂĆżUË%‘”%ŚÇ[ŞHËňŚé]3Í))eř6NÇ+âý°'2{‡0;űĂdE:qŞícv“¨BĎ“˘¸] éâ€5Î Çm…v\GŞńÁŮąÍ Žk˝{pí™Zh·BŔ[¦DĘ@'•żÄˬ¸ĆŕËłÚ= q1P)ÎŽńĺZ‹0dSLz¨*6^ÁšŘ2?ońĹ”bĹgAy‰ÝK—|áćZÝÜ84u©\+aľşÄP5ß™¨Ĺü€ŻŔŢhk«sé˝<÷ĂÉR„—.-ŔČöÉ™ÓFŘ™(*ý˛ĄqpBýF0ŹqŃvĐř ŇúŚŕŮîÔ-x+Ľ'¦żR¶™ođZ5ó‰(ň+˛ńÍŹ?®$U ŘMçđ&"šYšéĹ…zí_‚Ćł¨ľ6ɤ NŁrüŃPąN‡ŰŁÁŽą“µľé~}SUąŽxĹĺŐ#Ä#CLß•ŠÎçfu¨V𺆊ŠĂYcx«e°ŰŠČ—óĘ;ÍcůMÔ˛l@P¦”ŰFˇ~ ~Rźçxýý•Ąő4aűď„Ď˙oľ<˘Z6E“4썷L ’ ·ŘKĚ®UŁ}EZęi|}ńĘZRQSOi™şÎ+Ŕ=í-*ż|ě-’Yą$+Ęś§ĹÉ Č»ľ:./˙8ž{çXâŔŁ”fKFĺÜHĎy^zŹÂkđÄ­Ů+.Ô; ÝÉ˝fťňTäSâ÷8°Ńú¬uµĺé¨`ËyáSF-R`px"»Źa@ů ÄOß詚´7Ź›)ž}sŕŰŹ§Ž‚ʧÇ/^Áń†F´»N!آÍJv/-ŽśÝ°ZęĶ® ő{¤Ďéś]×µ'áßr˝3j'ŐŢ ,tˇßěČĂŹŰË y}ĘMC.ěŚÚÍMˇ[ÇQ­ćFv…ĨÁŞ–ş´ľOZ'şŮBý4÷8RmxíQ@ ZŁżlďş—Íöńp]Ůw)V7UŞ‚MGj¤ŔűI\{›Ű÷IűLl ]stv*ĐIÚŻ? Ô<˙5”h ˇ?óçt^Á.¬‘ĹűmŢŁ;Ô›0H1 óÂŢ CXnÄÇł[óTňŰwÖ.]0iđłĆ[ř*é<é/ë#»G qÜ–ř“UOpŕo”t’tŹL|äô·w­H Ĺ1 `†˘üđf'Š|Ż éu#8żöŞkJp‘ĺß®/Uµ´zmrőbu$^wČěÎ-ŚAŁÎhw[y÷赯ëdCBÍŤôbgeSjIÖ™ŔU[î(×Uŕ7Šó ‘.ŐĹhLö&±iúo)ĺ§â¨Q‚bůᙨ]’u_ÁtŤr¤˝ŚÔIź’Ű!™˙eO¤đa‘p$Ŕ ęŰF±źř삏lsWÜJÖÜŞă}űJS®ď­¤Ü–KHĹö$DĹ·×ţr6ŚZŚş r”Aä*»MjÍŐzkZŔ'%ôcÄç(~Í7O›gÚĘ4~ ć>ÔSúË™u+ŤĘŃX‡#FP¬XKP=/{˝4-EBFÝąZoA{˙am¸·ÂZčÎ ŚSjŚĘ|Žě0“mźŘ°Z˙Clg™”l?×Ő˛ílŚeÜę w¦óżú„Š b#ŞPLź× 8oŐ‡ ‰´tä)xC¨í•f+łd¦íFĂ[)ůŚĽ@ËŰń9@Çs3¦Yó@;¤Jž‰XľŐ3׼‡ă–‰‚ůŰ߆Ń眇~łz–Ţ} 1âÄK„‹OÜŁË1Üj§«aO#[±š—oÝÖ 78C0M•c¶¶›»ëjĘJhGď©!ÄN:ÔĘę2óŰ 8ˇźZŔÓء5rîk KD_%Ý÷ş żÁŤ7-–Xtqoď«_˙H.I‹;>fË-~€Ŕc“¨É''ó#Hp^ď)% ů‹ń2ď>L¸läSźi´IĄ•¡}.đţłâDŕ±ŢřßgÓxXüîS"Ѭ8ŐíQK2Ó"Đj¤Ď”¸ąWffzŞřWž ‹Z`k—bCOäÂđĆ/JÇ-xeĄâsCŞé¶Ő‰ôř0Źéá B¤Ö–ZěŮřžGó§iŤâĚ LJÜ»1ýmâźĹN˛•ščű\­.%>Ž_Ţ„ĂÇ˙rŰI ź_zJáħę9ßjsâěßĂ’ţNmŃÝ;…vř­¶÷`UdvV2lw÷°­gí:[„üĆKĹ`:Ar·90Jé_âú´łöö>RSçö/‰óôűööo>[Sç÷_„ůú%űzĎŹ“Ö„|žĐôL—ˇVűŐgpí˙ŕęÝdÎűÜwAóY#„eTI·ň‘S˘ÝďciĚyičýf‰Mh4ŤÔBIˇĂ†%ÝT0@Á>}(—ÝOë>×Îp™‘›‡´ęó©Áöą°ÝwuŞĂ·F!o$¨3Y[s ýŠâÁ(…}&…”—ęX>ΤĚěáň Čń‚k¤;Ô$đĹäMýi«őĚx–Ţ<2FŻX°Wů.ČĹmÝs¶r·nµR®˘ĽâĚ(ý×ń?mÖĽBş±l~‘®'˝.%@ńőÖ†€~ůFíôf#±Äů’דA ß`ŕ›¶Â•V<ܬ(¸€u|»"ŘĄŻőŽ<őß‹žŚcbjÇgśBŐ(dÓ{?x„ťîcü·ä]pőĺŃ÷2_˙€µ’rźźóŕ>ʲÁ8ÔSR˝.ĽĆúĆ]dě^uץ•)áÖ{‚×ő^§Ťa%Ü2p !ŹHÍфͱRkŘĎ\ÓsĹśĄtMÔŮÍn”KxÜçgžŤeűt(¨ p•ÓzL#r­Ó<ŽYů$’ĐRNM×]vžš7źóŤň¬đ+łą¨Şéż®ď”Áľř&đ ˙s(śsď¶ńEőř\ĎᮿúƇşć9UĎĚíî3„˘´´ĚÍBG`‚žíÔRnJŇ]ťyâ“éČÝŁP °ŞćhŞtŰl7«vk‘@(TˇmĂkŁ™GŘł>ÂôŞ>>)nÜÖš‡(BÚŢ)­FuHçeGö3s%sTő4ö±#–§Pő„µy¶?D´Łw·1ňţUr®çúĘńř!}Łú˙5N‘aĚęÂn‰Ăćü&ü\§l¤KBíá`ƤNNřG'´żyňt­j´*°Źě¸łń?™UĹ/:Ô´•ş“/#gĄ7ëŻB˝Ç«B¬Śˇí–ź6oĽhŞ·ĆýqĚ>jyÚ{bčHAĆqS±©čśű»zgŽ_çÁE¶ŤŘ<ç‡BD_Ţ &±L3ť°rćEľ–ęjŰ©łÜR¬†»`ĄŇÝ—MzöS’–fČJ«vˇ‰«¸Äąŕ EÚ f%Mˇ8]Ę܇qŕ˛yĂEÁqÎÍ“5\®‡í!Ď™ <đ»vť ó%Z»«°B>Slţůi(ŞőĎ4"˘9«ŰzŞ˛—’ şhçź*đ»˙AMŮÉ őˢ]řüT<#â(0ľ<€DĆ&Źz˛­ ÷D†Kă CX Ă©ĹĺŤÁl!rkççŤW5iţÚ||fŽLP06X^ĽM/ÄĎ˝f^ i)«¤ jIói“ !čK2cŕ*č‘Ýo҆z[^hjMlkŘnŤ_éOy‹Ţ/µÁ•ŻŤS‰'žóąx@YŃ›–nń_ű€6yB,„$Éâň„#Hň°WĄ˘ÍvV8®’Úgľ\ŚrAŘşË(Ö|؇Çnmoo!Ŕ~§$ä& @Ă-ÔűHsČť>žľ×B%›O{ţŞä Ś#ĺÎĹěWČc°¦J‘: gFŁgTßI…çŔ%>Űu‘­üýÔGÇŘÖĎ6Hˇ`"—ŇDdWí¬Äµ-uĎŇŰŁ:˛šŘ?Ĺç AńÄŘôÜíÍ@żU1rśŰ'yŇʸíbG,ŰśM˛NfRß&ëo]{Qű6€äVôhKŘÚ÷X O´/€'ś,kľx+8»n— ZJˇŘüľ•­Z}ďOóŚ&b@ŐÝZ˝ č8‘Á¨FŁDµýLjÖ\{~äÚ© @÷ĎÓk ýűSŞâŇx.© zĺúżhOJR´ŔM¸‡Q€Ô&Z»ň ,UOš mXŹEą&'}¶˛lř/L~Ą=ŁŕUČŹvLŐQęátť21µŕ›Ť÷ůpĂ“ó’mWYÇfn\ ď ńłjى|8×BWâť6Vb–€ŰUG66tűąŠHą–žşR§iJÖ?pŐžÝ,ć§)źL*Aëͬ ™ĎÚq/áťpýúď«D*óZ" îčś39'Ż<,±Ż†+0óúN’.¦‘˘EŢáW˘m+ůL­‚<(tl}ŔkTpuŁĺ Ŕ«ÁŠúJŐŰůy® 4WWçRŔAŽîďâd_ž?Ŕ­saGn±z‚Ë&ë ^Qj"2{G6Dm“a1žZEeĂ †ÚO‹vĹ®bY˙oZ«yď“ďÄÖ„ŞŇÚŤĹ@<+7ľűJ´ĆŢ©' +H+ZŹ˝?RösŠVŻ(8*Đ4|ąó Âf1”`F™ňçű⇅d@"ŕ_Ę /š!'â3Ŕv[Ç^=|Či©·áĐ%«ĽÖ*"Žr š =ĹÂ[Đl//!ďŁn˂РmŮ &hşE_l'*ČĽ Fíű¨(ű‡@–- âÓ¨ZY ’äž7 :W­»<5–§5)†¦ŠtěŐ%věX§ąĄµë”Ů_LHýL|‚ŮĐXŚňÁ!qűoe®ż5Í?ůť=…ť”Ę~y€ĺE—™„˝Aßš.*á°W•D$DÄ-šürrbŚÝ§ŽaĂYż… ŕ35nüčýőiD?,k‹QěíH˛ SÍ8ďşíĐĽ´«zĘŘőU ˘-@Ö”H ÂÓy„¸F;*8ô®Đ ‘Ž ęÝYDÓJW2]e-l^ĚD±şľř&ś{SÝ+ó·©ŃŔʶg`HJ‹‹o“ݡF2BźTüŚаZ*é ^ݬ'ŃbK4pŻ“ę$a/n7b¤uR“ëËá`=6¨´8’"ć!«řkȤ¶´2$%$h¨{ˇÂ'aőŐśťRˇĐ ÷e|÷ľÎ×ĚÍâČÔ&ÚY "ŢŞ©Đ‡ź¬†` â3˙M‡đj'VîŔ~2žŮd¸ÎäŹüďŮ † ”BšUĐd'ĘbŮľdĺé$ŮßSßuA™-Fĺ×€aí˙Ls Łp~ăßÁ]ÎpŻ‘ů &Ť‚/—›AĄjšŮNĽk+k±¶Ó ™lů"€´NÉŻl3/uÇÇD`%ůE¬źÎ'ç¦ÔęAN“TR”óĆÓ? ł˙b9ß‚D¸~PW씥©Uđćľžy ŰF:t]ůŰn˝=eă}q—I› nHµÓ†9ž¦ämžůb‘dý„9÷­@ŞÁ$Ń !™“Ťů‘VGëŮĚăÖö™Ě\±Şî‚OcßĆÝ!ĽŮľű›)«=ß+”‚DÂpt":ČÚ$}23ÄGřy|!Jĺ‰Čs|ŁŘë–HP}­đöcÎ {|`¸ěŹ`t†«Y¸ Šz¦#Füi ŇͲ#‘´dó–ě>7ěĐ„Äţ#*”ľŮăOrÚVţŽKôĽŻőz¨ľpE÷©7YłŠ:řÂ:ëŠ*\(%ĐćYk†wUŞ›çĚö.ióQ~°WNTů*čŘň;;č´Ě˛•áé”Ω‚h´B¸RäúLÔi{W_%©¦¶śLV¸HQ|Żďđë Äő4Ţ„¨Ń@$ ™ ÂĐšQťţŔź‹ŻÄńŕˢbĹl% şĺTĆÓ˛ÎVß§„bQvÁ_ š7”duZżŻŘ¨‘b±a“ŮÁa‰A˘P§ÓËÔŠIC76QBŇQ‚w%á(諡3Ü–çBµö,Ҧ೅´­Ý ęăŇ#áš#_Łş:ţIČ6Ťä&ľ‚W‹}Źž»ĺ jXJě$±˛Sďč^V"E íAňyN¸ŔČ%‹ť=E“AáŢł•;`iÉ|v¶‹2Δ’ÚsC„í~)wÉű@’W ŰTąZbÚî&ßůgi€JxVRu–0|ľ^^Ţ`“gU Ý®Y T4B8ŕŞ#ŠýHŘj$ZĄŘ€Ď—ˇ¸Ś8)ŹzübôVę§p–¦…x‘™úÓéŐ|ÍľN„‚iě <üh·N•Š ţţ d—ťţÔ«?f—Oű TĽ'ĆŐTQ•Ď?ńĂËŹŐ‰¶MGT”ÇŽl#/Ł.óŚ `÷o„rbĄ&vĂËxĆąv+“ŐfŘŻĂ®´—#oĆóLK.5Ą›iźÎHx©ľ đ91"‘·GV©ZövŃ­Ţ"¸LąT33ŽýźĐ@˙j­[YŐśu’ öŰŻsç¦Ŕ"wWSÂ0 Ö>+‡…jţô8ľű pĚ‚J­üJp^jY–¦fl^Č& 4±u«ď7)ĄäúXpB®î釰×+ ƶލv[†dĂ|7ëÚő1F°2ÖÄ[;¸!Qnkč~]›>I[Űdź˛šÂg`Ȣµą÷Ôčô÷D%Ţ3ąy«ůëe9+K 8Ë´ĄéP«úlľI:‰őƀ̯WěîAGř[ąr‹6ž›¦’.$Ătżë}żąSČ®3ükL˛Ź«xŤEŕ¬.Ç´Y|BÓÉgŽąOp/łDAŹ Ââs4«B“r@j(ß_ň°îĂćZQ˙r˂ͣ˛¸ě‹ű“ŔDŃNzŇ@Ëő—Ą¬$Ôżu¦8ÖŽŘ-(Ç›·L© ,^G÷~†¬ét¤ł ę$ΖîMĺ×Ô·nŻ3†ĄcÚˇPţŇ÷şh­í@aĽKď>ěX®¤–ŇR“îřÉđü¸ťľµ÷×Č)Ď© WÄőöT'‘„{®—ńÂ>wO†2~Ś3č×C­¬DĄěŁÖTzî·QŁR»ÍőßNÖWävŕ1+(#Ýt^rŔ&đÂşČ6ËÎU˙üěZÚ̆Ł=–913YecYŞ)äg@hhŃ|.îË‹4ŞWŽ“:ĂN)Ő´H#w\¤¬…ĂKanšEď;™;Ü4_±öłĄF™ôF¦öć ZŮÎj%‰Zę6'Ó 7<ŹâąOňŮkŔL ],XĚ#·ñg9™P]RWhk$‚.Vî”jť\5ÄůdGJ’wdç˝™÷ňHŽ $ sÂPU ý¤á–Ö%ľŤ€gĚků"”B8‡q˙[#© d(ob.:.©X^E(¦‘OM ÄqŻŐö/h©#¸şü”ÓÁXńŃYĎKÓúF´ŕUAő>U°Łó îăó,~‚_p}ë) nBęśdĎçqʬ ç& Ćc×Íů°Kpjĸ’7šŚâ¶Č·˙X×v˝YY e˝nů_Ë1ťLćÝzoŠóŁ”'úüő#=ź»gdú¸Ú4‹ÔqˇNőöö|ŘVݧYťŻ~hp€Hâ*”˘6÷‘Äh©`ÄB“y¦ş¬đ$…ű6É(^•Ó÷«Ě‘e«§> Ô=OÖŔCáIjÉ=ŕ…zŰ~ąZÔą14˝!]ŁÝ¤ Ő÷® Ęúzäͨu˘§Tď_®sĘ—íp¬µ•&&öăˇnoľ%Ů2<Ŕ˝RAEź[ăŇb¤00üőą°.ł­WšhGľć‘ĄÂÎvŘřXÖ#D[ 㺪7tբî(5RŔ1Eşţ§ďŠ›\´řm—ţ¦Çf>ÖöśŰnźĹĎŮŕ¨dő™tTť­}ގ|óŻ×®¦Ę\ÓWž!îGşr°+ÍŐ=Đrą8ą2_'[âą,ż­h{mŽ75Č Í~{łĎÄfŐ$:Ş2GĄ©ß öîOw’>z6ÝʽĹň¤ÍŞ_‘4Ú˛ĂŢa™&cY¶‘-Ň_ÂvBżňŢ;ű?·¨U[úďÝsúV$*pż…¦GnűKu¦R<ô4z<±Ś‡ŞÍDŚI( ĆĺZËg”eŮ˲KK_şwTČ©îbš‰6ż( ş&ęłôˇ7í€DEư–쀨Ł~öO§ő/¦H]Ś@P‡Ř„5î‡;ŕÍ@u Šďx%p=bČ˙~¸S\( g†bʤÖ¦4Ű É˛T–ŐFĄŘZ—¨QęŃ"•^ÚPÜÂCÖdDÉÝťh܆˙=I©G?WĹ˙uoŹjE_˙`FśNn‘ ZĎD@ëđÇGo8Bźţľľ,ů4§ĐV—•/¶“ÝaD÷cŹÇNg͢˝M(ţš3Z+{#Ű7gYÜĐ{ ]Ó—z1˘¨"ú‘*đ¤ROo ţ˙M±t”µńę.é·˛ŢúˇÝÇ­“˘â67Ń,)U!vŤZET„ĂpB’ţŞČisLi­Ú-”JFNÁđ]ÉvD‚0¸YQěę Á I&E¨

Ęe@ÍĆJ‰Ę~;#Đ[ĂT5ŕBűtş3¤Lř·aŕÂĘZ§Ő íbíś´?hQ"â4śśĺ ¦HljsaŻÔúKm?ä:õ¶ÇśÜŘÜ'6Y,u>ŔĺÍ8‚Ű‘Äaééô…n~˙xź,#ý±UÇş™rŔéĆsy"jśOńZ$ëżY1ľ*ËŠNÇ fŃ JŹ ô—ÜÉkáß0?ČZ]®ĽJ˝™MĆH–ę]…zi›_ľąkďlcž“8ăV‚€´ĄhĚUTĘY$PŮđž}>ß~PoÉţ2‰™ˇľTEč–`hÎD–š™căeŇ ç¦nŢX™gÍ^ńă1ćh&TßÁřä`;3ýZ)†ŚC`QÖÄsBܣ﫟š–ŮUeűLŃLß*×Â5RĄőŤéËÖ)¤ů"Č‹ýËăŻpj‚¶ ·É4¤IÂDÇýâ”â˘,`i1R µŽŇaţś/ŮŐa“â4#4{>°j,,4aŤŹĘ%}ě­?q‹>qßFG+Łn–čji:ĚžT‹·ŢŇU+őš_Ĺ––"۬šOi+Ľ„iR~°ö„"0ßú ë¶ThŠĹLť‘ţúB›aĎ ;ή̴Üô»î÷ÄĎ 6NĚCLyЉÜçďaţ ˙ax ?{ďIýúO}·Ć?z/ď1ţ/đ­€í¬x¸mĚü#Ź´‡:=Ć­˙LďbŤNZÂąµD¸Ř¦çű,ŕ»j,Éh$˘ĺX áĺµč©Nzú Y¦٨hYšC»¨LpT¶Ă Ćôä:ä-`ü“ŁÜÜ“§ç7±ň·rDß3|lKĂhZżŘ4{¶\ŽŁjLë«ÓBȤżšŁc,€J˛C#ĘUśt•ڞAÎAŔŚK|Ř`Z.ţD iŔŇŔ2CŐ‚ĽÖˇşíąÔ/‡1ŚäśŞ]$řř!č iféÂ5śŕf?1ĺču`B­˘ÎĘĐäÜMóőqn NÜť{Ŕ Ô5o“€HöźZ7ź’v”­7¬-ůs¬MNCŠ“@;™3L®ŃYÎüţłŚrž=Ş6¸Ő¦ě‚ŇT{ ĎE1ĎÁ53š ěGC]vľ[¸”˛ąÎaë‡Ďßésp4”ͦ—W(‚ě§Ĺ]«uBwzî­ŕň8Ą€7zÖSgřq±ŐŐß5ŹÜ)đúýyßö˝ŕć¤Ëô8LýQ~‡ăŘë˘<Ş€Sě/)lµ G…Tđ –Ăç" 8ćN›Z h÷ü»ÖD!·ŢeČ$˝[&HOĽăM\Ó˘h¨ô>ôĘŐq%Đ]°^\?`á^úR;—Nô/ůŔ"^s'Fëśi©%â}ŚđšÚĂ ›‹> —&dsŰÝC—<ąX­Đľ©wě×c_j_ŁWžďë­jPoA0Ě߼¸ÇČęĂ$ťÁC4Ý+"‰lđáűܬĚ{o|[!Ü@ ܦ"gÝvVĹă„˝ž=ů,±>HŐl‡ü„IgýZçCc‰?[d`FČh ^H˘çiqús|őy˝Ô#Ë°Ś±é­\"¦}Ë$ĘF„ăwݲał¤Vć/Żşaç+–!9É2ëÓTLŠůë›{GX>Roř~éG;áQ& ŃÉŹ^Y/k…ëG˝– ´qŁźT=Ü?°ĽĐ,ísĹÝ’ĐCŹ‚Ť'“+ç·®´*zŐ˝´fLˇţ/č÷6ó‰ô§–~¦ÖßĚôd$ *ěu€ěÉéŞgü/Îä*Ŕ#F\¸cQ&4:…é϶Rżá!ŢŰÍÝŻU]ëµ[ŤăM…!ěĽő9ČęÔb9ßŃ×,7©G[Ůߏ­d–ěEv±´1Ý÷^}Íş¤J¸Okö7é͆Ղ}ŐyPŠ _ÚˇŚYoŰ=(nď*µĐ˘×ľžŠŘěÎ/‚˘}Šmż©<çi](ܵ"Ł´YŹ©ćIýřĎn$‚”=~ŔUpX˘dŕşŃG.˙vjťS&…!0VčŃ{€ÁĘ$YűtA˱ †ŕ‰m2O^ItŠýĎě+ýOÎPu’Ţ«JhöĎ Ă‹eĆIő­Ź0is8IÇ߯Ýx»ŢĐÎaĘ˙#® ÷J‚”dđĘťő6qqčűĆ4Ńcó-ŕqä˙ÝSěÍHí-Są™V:"¨›đ!“˙ëYÄmÄ~Z˙_oĐëśďŻňîh€&ć(Me–ëäž p!LŰČď:€ő“¤ĺŽÝ‹R3˝ĽM—I6Â$B”iË-y^JýĎ"PSgžŽ/•…á´ś‡;rí‹´ÍŤŮĘOtąYťĽgÇď©­ÔŠá äuôb|3í”®Ľ7M“TVZăÓ ÉGŁx{X†öˇččódĆÜH|D˘(bśÉí›—[ÚA’I ¸6î¦,±aý6-VŮßĂ?1é…Z/Ř^ďă;jŰ“˛Ó”{ŁBĺk\YÁŢYćH+Ü3¶Rzţdř‡ßĂâ[hAv©?R& ŁŽ%s…Űn{M˝±¨¬xŁÔŞ˝5I¶`Đä;˘ Mm€fGínç¨řwŮ 4…ç) äŚT3ľě1ęřJúÜJ±2gčN·=s%Żu­QŢńaq@ŕţWʧýORá yj“AÖŮáf«đItÍ{AÄ7첧zë€dv ckWĎu¸Ďdś*ÝŰ]>ö@9zęůF?żEŮç•ĐA#rx°˛‰•˙p:eÁ ďĂB>T{râĂ˙?ëÔĚ] iolw)lQ…c §x84f „Îh öĹ7Ýł°XA˙ĚĘĽřé€d€aRYҢ˝hNcçZ{Ł’ŕěóýĎŤĺđŁ0p‘]üZŮÔŁ…Ććł!mşŤ©÷hSuYŁ„˙Ůic09(ä jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdef(mjp2c˙O˙Q2˙R ˙\@@HHPHHPHHPHHPHHP˙d Axialis˙ 'ý˙S ˙]@@HHPHHPHHPHHPHHP˙S ˙]@@HHPHHPHHPHHPHHP˙S ˙]@@HHPHHPHHPHHPHHP˙“ß}řPW^ç:‡Ôe¬LzčW×l:a,‚ůŽ-•»1k#÷‚úů¨ź©·u'ÜiáwRÄ˙h{ÔPĺŔ#¶ĽNH¶ď*bP˛ż;îUšË&Łürűd7ű‡ŔuáȇM “‹ŽCČkHŚĽęűŁ»›¬ˇÜ ¨ë8+ p`uŞ0÷ÄU @AbމëH/EŢź•O‹cŘóÝ´›6­-KR‘›ŔîĄTo9µ"DxSňßÍĐ §JA7tŹ®‘Áf”_ë<´Áż\U#uH$|岂Í2a¬iŹĄšźŞüSk(AÁ•}…ĺ—ěZ˝ ,I„aCűJÉ0$ÇÔÜx ďejŕš쾀żĎwú1«É˘Ď®ĽtXCš_ĽALň”¦A Ő„r5ąçŕqc„~âÉÓAšŤŢđË66‰ĺ <|űp2­^ ß#Ö˛ž±ČëÝ@kŹ˝ÔĽ[ÚĄgŘň•RGAGç̤H#¸Á!ϲ’…OAF®~‹µ  Ľ˝„K„j·żżšŢíëľ™Č}öřĘ:<ůä×~¤ĽiMŠnâ|ZtMĂÉóA 6'¬5á¨(nW…&ěÍ>ńB–¬:K ­Uś/XŘPqń„:C¶|Á6Ţy·VV•°<;fćŐbŘPHuS Żé©ˇ×óŻ6:Ô›U˘B›*Ť“„ Xß}¤Ps„•¦: 9˝ “ŠxOVCł¦3¬bśÔ;ËKn÷¶âłw•”Ë- Ů C—ú‚ăiYŤK _  ęŠk3Mß9EídN=ňŻ×16 °ôŘ(éhÓsĄö( ć¸,ř°{›s “ő ň˘$7ľ űÎŕúßů˛§G,%k'D©&S8–H6!¤ö‘”…´HsZ﫚·AŽßř*g*ËLĚTI—ŇFNÍŻß‹şo‚™«ĺöL &M îĺiY·ß••>ű>>űť†ĘpY‰]~Ô˘g?ö4 ťŞŠá7[ňtęůĽŁ­4ýďÖË+˘,ęŃé˙ ’†^Ö´"?^äśKéx_îÂLŚŚćí&4¶`•ďłŕ;űíŠ×rWŨc®ÜÚóQ>'_p…°÷[ôČÜjM%˙=¦~ô8 &ď eÄ9„× }ŞđÇšĆđz”“âÇpâ[€<ĺ‡úů¤ĂR jĺGśżâ\pNŘÄ pžMy¶×Ńđsňż;[ÁŘB‘ | $8“{eߨ-MŐ¬h‘Łi ׊ÍVß|sßJ­IM‡'ž®iúž„ˇłÇR!jČQ7y`ŐNi"ďwÜ”Ůř^Á ź…˝(vwˇ$ šľrŘcł•oo}ŃÍP”ŞvqDDĘÉŞÖa‡.ÖŢ:0ź(3]>Éhg-úÎ!;ć>ÝjY§SB¸ 9żĚ8ę-h›yŰ˙C…ćŕ˝5¬µ”¬čbÎř`7Ş9&!Ź0đ=öŠÜp_,ł¸7x·ú.Ć«Ű4i4XkšłŠK}łŞIł2Č5V÷_)w!Ý,?:[Ůî’ŘźNÍǨYM~wS†ÇŹ6 ˝¤ ŔćŃ;ö4¸<˛ŁÜoş3Ňi×öŹFÎX4Ľ~¬ČÇł;#şOIÎ×ÄI˝’áaP;ŹY̲<¶“ďăÓôonŁ)?_ÇÚç¦ý±ŔQĚŹěaý—ňăÜú¸ĹVźŃ†Ŕ*äíO¶ŔŇÄvÎU) fANb;ąG ÇNnŔ’Hűą0·ôvkd“!!ćWU f8čSä v…ôŮ1á,7 ±“ô&J$ę_öŁôď\˙môky(Ë„ ăžŻ¸ýF…ú ±ŕrX!ëë¦_ći˛FÄRh†ŢFŔP꼋ÂĚ‘ÓO–Łâ´,}%“cTÔ7lÎCƧŰĐ5ył´"m¶—€˙V— ˘ë–äÔÜö˘Ď ­>z˛v;%ý«˛®  TFËąµ`ˇŚ-zQ.ťwN!ö†ŞŔg ¦OV…Y7ŽôŞĆSmC‰Ři-Vüwů7sµ;šŕę“IŁĆ“ú€ µ•!čű–ď?xŔÜs^sżéR%˝‡®µkřVRŕŇŽE˘°™ÔË—Ń­± üqůDŮŇ,żd:sŚ)…­Ď˝ş}í‘ř0€2ţĎč2`”6ś,NLhĚ8bů3+e"˘ě/Ń’ćŘxhää'ťÝ>óśđ ]Ť™Ž’Ď[ hę˝;| =$Ö(xž[÷Ô˛ŐOŘČŰ«VeŔŹjË:o ˘řÜq{Ţ­QĆ|ú@ňe;[ąÇzős–Ë#{Ë̸Ѫń‰zgĂG‹ŕĘU`6ôE›ł…Ĺ7¶¨K3ĄÔHÓËŠEÔÚéË2„4R ĘjhQžzW:Ńă Ž]yŞ8˝ßřňoŞň`xwGxKçéîđ2cĽéŠŐzEGßX«ĚS>WT¤~Ç ůű„űŁÉ™úRŐž¨4€›­x×ň°]Mt”+KěäđšYn®űő¸J€aŰýŻ*„-©2¨ţqxŰŻ‡ż¶˘(|1xž?t’¶yđ80K-Îş2dĚźCV&˛$ÁÚxÍ„î6é0D‰V Ĺ‰ÓŔj+-ĂU꯺ćß”-Ž—»Ä—s^ĄÍżr\rKÇl{y<Ŕ™ś›'ća±’–€Aęřż1h{gć<<Řň ÂŃ{ pűS=äH†áŻmçpĆ_Ű÷’„7VŹްąfnŃĽŞř•EÖ]ľ+„ëĎÓ­ĘÝNuUń›»Ťąă¤ţЇ|’ÍĂa{y§`­„mFŃbŕ•­µYŢýś¶ŕ¸<·L’='­ţĚ:ľůŕĚ˝i@?Íu'.r­U߆;H–đ5$p0?ĘólĎCÜ(Őô!a]?ŤŤ}S7[÷•Gys őŕúϧŘôrK5·íË_Ňklj&ű˙uG€š° ,Â'ŕc&ű´ă¨p±„^§[Ďbî0ůR{«¸ŻůŁ=ű`FoŃi0‚8ě~”Ľ§ÔÖ/,čňŞ;e« qo\}ţY-šÉ8>9eŔ߬mşÂucí)$R®YbÁÉ[ßů˘¶#ɰѥ“;Ţv2VĘřŠ’¦~w ›í2t°ŞÝóϧ¸EěLĘ‘)†)Pę¦ ňrĽß)±§‚Zš3|‰)'VN¬/ާ Źh×!ް7 ú+ұ?-0‰ŹPkyŃ]Ă›ÓGŃd䇪N'f©RŢ€ JĆH›Ţ 8s4ť@Ó‹“ô=ďS=~°8Fö¶FtC®q«ęfn K]ĂZ*>2Ƥ+´›đsěPŞÄ‰?Ű膉Đ$ŐŇXłÄ&™,ĘŞeÄ.=§Td[šÜЬ1r3 ‰ÄY‚Ť‚§1Ë3I#’еĹďb<ím_%0G tůŠ$––öBqňM°:Ă{D†m¦ŕV ľ_Ŕ†ß:¬˛*ĚÂQďłluř‚ěß@ěł)Ďß’%áîY™°Łuvté6®·ş”řał=0÷}ÝâÉ›"Ö‚)Ěë…g/=+4!D]¨ř6\ Mó±Ę]‘&Zęnřsb…t>VäĚă’éoĹÁ‘VÜ pËě%8˝JÁn…A>­gF)”ěF‰{ëBÎ?c*BŞ˝řČ‹ěę‘»5bRĚž:şuÍ}ZČĘ)©«KS.Š‘ht,=ëŇą”S`zžµFG@ąbę: h8¶/mä7 ĘŢgp°Ô¶· jĹĽevËâ°łůeĽ´«”ŔÖXń€ŔiÖ›{ÇĐÔŇ˝/vEéĐg~•0ćŠ)vé,C…†˝¨W̱H­3ăׄĚl@,ůŃ­RRUÄ÷rĎÚ˘“PŁ3?X5Ę|`Yő[ďK™Gß|Lźć1 «·€|ëj“ś<¤ľSCűÍ$—5|¨łßŠĐ,ŁÜ;Íô>$FmLĐ—H…ŤQôR€-/bčŢ0]E»Yî§—5•ŕ=Qß5x ęىű¦m›bš§6Üغϻzťďvý•KŻë ¦ŇŤŃŞôz K"d›R.PňNŁ÷-˛ě‡*÷Moą!†Úš–éĐďlp-AIVw,ŁSšFů|.>‘8>¤¨ńđç#Kĉ»śďhć‘XNl.ëNű‚A‡§Î{)ŠšţRr>2!”Ó źU=–éáá!o>h!Š™DM±ĎÁÓ±ö:FUqőŢą<ţ·é1őÁć߬šÖ“Hu1}Äň‘m¨ ď7Ý/ÁóďX}Zçߦô›IѤC÷mŹŚR˝…·I˙;Ůľ‹/€ˇ˙pˇ$Ůńî…µ*Ŕý„fŃ‚HNĂD!48<ˇAmµsrRV[(•ý,Ď$/ş—¬ Ş&açĹC2I_öĚ ŃÄ81î­kg‰S©âbďCixMŇ6k®Sę’X+ľ'+Í'>˘€9|&iÚ8̇Bo ˝ćAkł'üRŻáż^–1ěňłëĺ?5[˝žňpě*SĺÜ%öÎÝ9%Ž,bLţíO͵ ‚-4ŮŔăŻ\řg+Ď!Ě wöj‚–u{8v0"-zţęCÄ“<ˇ âÜ«KŘą'G*Ěć†/Îvü¸hf8ż‚Dyą}*~Óöâ|Ä%eô[çm‚Ą‹ż;ŕ_%SěY3 Ĺđnŕz%^KÂVٵě6µ©ÚeqŠŻZJ‚ţťč2LCšIŠiSyqÎşd·TčW`Ľ)y€XÓJőÎ_ߨ8­Vb ëę>áôé.‘źҬ_k—§€_ąhKm1[đ—BźŃ±U(ۇN$;Îť‡ö誛ÔżĽ-XŢt۳ΠwŞęŢ82_y=/˝úŹ™)˙eŕŰXařĎľ*Ľ>,÷ĐđŮ Ä4˛dŘľłŘqgľÓ§Ĺ1Ýâ€)s®QčąCvŁĎUČ_MެŐ7…0phŽ—š‚:…Ř™˘äCűţP>ď88bÂ"ćŞt„š@÷ o 5;ň Q E‚Ő>»U)ż´ëžÂ­ŽS„¦=ńíĎňc§.“,ă“×ęKůě Č»;Ť™z›×ÁacÎÄ(ť‰ďMâł§Ü@Š7‡ śĂµËZŽieZŢŻśXçüˇ/\¦ 8QSĚ!"?‰}ŞmqafhŽ”© Í®!l†Ź`ŚZÎË®VXhDů@_jŠŤop/ôÖ®&ŇvěHćܬ¬Ąp°Źŕ[ţ_Ţx"Ťüä4$uĂt‰ű±˝Ö`.áVh+v!°Ţ?Çۦ±öęä>Ý4Ąâľ±ů{‘m»1}}1şLńńÔ…ľFY$ÚAXQÄbĐaĂnµ”e¤Ý.3@»˛WůUĄÁ$Ľ˘śʼn…š“tŠ/Ń îB¨RčEß20†ŹßúV}F‰›rŐ)”䀯)ÓJěÚäÓ‰˛A:8»÷3é=ÜB3€˙×ÜrÝFş˛™ÜEďÁ~‘·°©´YĆ(NđNM ô0 —k(6ľKkÇ™mT(oQ€„RKĐpś5Ü„DÖžŞlbk?7=“îÚʆq;řŘô5 L·ňş`Âs¬ú&Gćâ>ěŤF•Řôo¤97ݦ ;n°NÁ1éç6„ĽŢRľ‚3źL —“ Ď'µ°ˇRÖÇŕŘůT'®Ô=’'j¨‰¤)đnë&AăU*E,™ŠAŘÎË…Nsì$ŮEŤ*E„O+ťÝ4Í‹fęzLf” TńŢ7ĎV•Şb›MaŽŁK÷­YIŐăUit¦ô=yTɲ…DďÄ’D mÉ–Ł PńUYAaëN«qOSđSô—=Î9mŇ`ĽÝŠI×)ĘÚtÚŹĽÖ~ŁXć›Ĺ¦'QÖÎT áq’$‰ą_ą:«Ů”0/ X› CÖbŤ%Ëéwłfm0 ř“noďß·îőőĹć§řăBľôÔÝÝ8§Zڵa<ě+Űzsďo_‡jŤÎěW›S3¸yą7xď¬C,¦Öh (bsŠ?úÍ•ISF<·Ě¸A„ź¸`ÜŔ¨…ţ_Rđ~ev©ŠŔ/iPrăË=á’»'YEÁęQ,ţŐ 9ů¦]—h‡őÚ¶x’<‚±Ö‘·he :.Űě7âŃŰl‚‡-ď1˙–r„ vÔT1Źáöç'Ř/9qyňt/ú—¸¬–‡ÇHäjĆży€Eľc[¦xőšK‰ř¨Äý0’iD©H­ŢjŃ\Ý Gľ´¶LéÍo–Ń2SÉĄŹäV.ׄq˙Żłž~mq”CĘĎš8{®őGĘO˙*ĂČ;ËE]༬3x›#µ«§*x’¦ťĂÉh4ŹóŃ^ŔE›ŠEU'\ŞÝ‚äł}Ĺń´pç0ş“Ď#‰Ëmę1Mü?gc"™v",u€~;<).V (|Ą?y]řLDÖßL”Á‹Á•‘Ťpöp‰)ˇuŘ›6…ý2dˇ|ľ4•ÎĐČHGu„äçý «EáđtăéŠđ/ ć׳rQ3¶ťň_¦Ć›F˝ÚĄŹŽąZs?Óß•»>űZ~U݇tcMPc‡đB1Ö°µŘşź&űŢ~°Ŕ»č¨”…üÂú!qŘTx&ę%®°Ú$*ť°®î§˝,ľ|ÎR@ÂŁ·Ä­éő±Řč .»Ýľj€,ś:ĺɵç+–oţ9›ň¤Ř¬M®ÉG–Čt§Ě}9Böâ×üގú^Ş6a~iţ¦ńśťřyo%垦1Š§Ň®jŮąi„lZW@6m‡÷á˙X§„ŽšĐ¤RMÚ˝îg˙5z¤üwÄ#X†Ú¤Ć¤O¤MśĹť®ę)îâJ}"L‹µSŕH]ľ+ŢYYcź´ě˛HVš-ZL<Ł”ęś ĆÁ}J»[Š BµH"ü®óÜTivűç¸U.kq)Ąwµ|üGÝs yĄ%ÝEř{d0+Ĺjs×ţ&Ő/Hcüf[¦ŁĽ…Ň'58{«Ť3ôk1?ťýNÔďŔwQČ}$…E…bL›uKZÂóŇ<­?%--uĄźµb0°§kµŮđâ÷|ÍCqüšačö+gĺ‡\!^xö-/Ę$˝ę´ľ ĐöëĐvÎÁÝ̨łžâ]ąP&uÓE„o·–«)Ąsë$L¬·ř­ÇÉ‹ś<ËÔ˙(#Y©?ÝťżŇ%Ő'ű%޶’ Sî˛măQ|ŰQÉkç[Ű#™˘JgăŞ÷ž|T÷ś—ŰčAP†¦ĺdťY3(ËWłăBqĽĽsÂű©ĚÁhvc×…p§źĚÔĽO“{ś”x›í§pĽŔ"ÝM?–Sń>»NčĂřQDW+–?ĎĂÚ~čńřzňÓů8·€}ăý¶ű©0R÷CőQ"đTfÍ?fŽ*š¨  ‹^Ł,¤¬Ł N\˘Î"˙59°JSÄ;¸ň2öŢ\(,QĺĄt"=NH6&×X{p{ôź;?-=±‚®śëR‡h€–zC§\v¨l/ą2űgńA„°=N©ź"5'V›ĺé E\ŔČ>„…§ŁćźqtşŮrvŚ~M“s ĄLł€RŃPˇ0ôg†Ž[)ń”±yn/+»r¦ÓĎzĆĎč»nÁ†C’1`¶­5ě14<%’}kȧ&ăiT‹lřnjŻ>$Ł+#’p ,ź™łžŢÔÚ©›ŇŁ z|č…6 t‹v’¶šĘ©0ŰAť¤•Ń ‹m¨ň;=‹Ę{řiĆ®©ű¨x‰Ž‚´+í|«M·Mʼnô ň̉ ÁµýÖkÜĽ~ţ>/XR¬2ŞČp®đ@ĎmÚîČrßn§CÄ'„ßI–›{~îźʶQŮ<9,ŃŐÚDč%íęť)aI•í b”·~ź}‰-G]zißóÄÇś¤´TT jŐöZŁÄÁŕ÷`%ň?ô®+PŻ 8k “0ď·÷ű¦|]Á’,KÄďa<ľ€x$J·Ú{ˇťe%ÓJ]~aśJőz`HÄüF¦z{HĆhÄ[ř*Dŕ[™,ˇ…Dú_rł”$×Z&l˛čĎ#Xʞƶjľ—6\Ó»ËL0Ţď;×–ačĹ&¦Ł~Y”M˘#‘,—„űŁŰuÇ^9­tVŘvu‹S;®›˘ľt“b"ŇD«ă˛Ż7¶UKm‘ęß͇S/Š9úS÷Ť„:÷z’Ňęýřz;yĐbč´2đQŐ­÷qŽ—é§}(¦mŇĺ/±0}fď4vÝ0ŔŁ3łž‚.Ř&FŘ×brt –! űJ€&\­w=RTŕ> gRóáŔ´íP’uspUűÔ"ckÎé°řŠíY×FÍhµ[†ä ‘mn‚¤™ÝbO7DC‰H¸WK ÉĎË“´}“řW“KÖŞ°Ďkţ`Ľî]Ënř$PŔűł=áŰ]á12†SN0łn¦şrĽ)eG¶Ź  źŤYąÖ°¨éfL uŘëł·ö˘A1ĺÜ6wŢ$íG‹©ÍsÇá`ZVô™:Üúí盝á”0ęđşô0&¦ܧ‡Ĺ ŘنQŮĐV,Ż„ă»'T%Đ% –ZŘĹ;bG¸Ę±hČ‘UuŐ,Ý„ŮĂŇqG§‡TsÚ .§#L¦jś€Ă,|ĄS'˛âČI9üţ‰Ër.eńb˛¶ś«9·Q‹­ĺČ^\3hI"GŔ?ki’+:Á ;µ÷Ć­ŁĚÖ·>ßńµľÝÝBwąÄ[~€eç?§ŻŇ/ \^KśÜxIăD!‰čĺ•cÇçëYŁĚÎ8Ú6ۮߙҦ;†ű4ň€^,a_=Ňš¸cöD!¬OĹĘĽuę\Ž”ĎX •÷FÔĐłPHŤčýgNx´gy·ŚÂîYfZîŢ"@ăe:!a'OFţ¤ľIóđŐAĺEEÂBęÂŃ’&i„x”Đ»?Ű}gF¬6Blj§ 9f‡dtĎ8´ĘWu´Kúx(>쉷ś,bÎ ĎÄÔż`ľčŤ©c„)ö›®?uumC~jĄZ,ĽfÖ×ŔôłvŰ­äă§îĺ'P ĽŁ t¶‚ óŁ·e¶Ć¬×c¶F¶`ąMI6ă!:ĚKQÓ88OĎ+řL¬0T ­†P·ˇlAŰý~#ěV¦Ăö>®›h3‹[ĹŞ˘ąĄéúm?ÂUŘ"˝gôQJ 1oj¨č$Krn"jś.DĚ,u32“2{jú·¨…±ôňó˝ŽÇLó$Ŕý} –†;×ó*K 5Klvá܉§ĎH¸a®­qŢ×Oň=[eV‹¦÷%ž›hËč×<딩äřŚ%\Ěü°bňó4Ś“;ĘŠš˝¨ÜÜ›śĐŤÜµ\żŮćĂŤ§»–łFAK*ý‚ZĚĽ P°ăplóL™&qŕ;Bq쑨~:Ľ|'%iEž3µ`ŰąÓŁż©ˇĆ˙)qOW˙=7pČuŇŁŢbNµáECf©Dµ :ŻL©áݎǝމý%ESAšËcÓxf4uvĺˇÍ4$0Ĺż\¦´AKé†tLJě‰h¸ý…€8â¨pŇďÄĹîůäŐgrŮń UsŹžÍsř…ś'‹µ'Ľ±< <Ü,ÂŤ“ěŮÁŤEFŞąS© \jŕ1uˇ?c¦©„Ť4ŤČ˝|h$ësűŔĎ7ĎN€Đ„řˇs×·#­VątŃ‚ž»óŻĘ•ń_˛Ú¤Áf>‰=Ą-‹Gq W÷ĐéµYě€ _žOů˘©˘W3רů ˛gÄ!%Ś„0‚o>e]úçF+đ• Ęő:ĆÖ o’ýńTüUŚ; ˙.Hť­üZćÄąÜ^—ď@U€pÓ%ÜS¶ę[cČ­p9–v™÷ÁŽśX˛ëB{6[ŮMoĽF®čÜŹ5[Ď˝ĘÁ µ$( X€÷]­Ć:¨ôÎh}„ •Ńť˙$ok±jźŕÔÇ‚]ň—B3Đ1iëó~Ćb´]ŢFŚÄŕŘü:M?=ĆťµďđŘÇVť®óvŤŤĘGąo#G•0Ś"GđKbiÜU‰61—pü5áW7ăśBějąa‚†?ÎOF5îd­í>|É^Ďód»@µ3˙j+qĺ_Ű-;řCy\`•«cjŰ…ýę€Ü˛ĂH6Żú‡ě(ńν“ţZII_Ýl®=#­wŐAhnů“Ä \” Í•-RÍžśy<˘˘|Á,Í#Śăšď6?d@x˙)ÁmĐBˇ¦Úłň.ßWO’W$VD=ŔŐkyňÉĘůsËĄďM# MšĚ'·aq¬e®hŃŻO]mˇĄ®0)x±ĹĄ7ZâE1=ÇŚ,Wë 34ěĎB~ŇňW·€şŻY.‡· ¶1[rj2a}Y=Ψ´É˙jŁŘš}7˛ŇT?[”QgF$řü›¶ ĄĚFÚѸS9šYǡ¸Öä“‹“Ľ>ŇŽÉzR®±. L0ćUG¤¤†úĚĄ·É„±Ë*ć\ßdű޵dĹŃČŁ[Ý#Óńˇ[D…ź] ’ÇŰi2®&űS°ő帩âäđU= ďIÁ"Ć‹ŻBz.kZo„é+Ô;XhNśKőIűl9Ëł¬ťÚťsc“GI$Šě|S%7ĚşP ÝÜú÷Ęs+ŮÓb}RĹ7 Ô-†É_lŻš†$ĂŃĘŔ˙<Ă d»tSŤ v}j÷¤P»ëĹ@t2(©éařn„eç}.áęWÍÚ"ˇ E.i¨4>!űÖâťŰÁ—DÜůĚŇF x†ź-—Öú«/I˝ÁZÍXgÇě ’®UËĄ1đĹm˛ßN«nXĚZ¸d´Ô{$×Yž÷—ęhxxM€=źĹ€éecOîłĂ4”_÷3‚Ą[ł Đ"d †ŤŻ÷Ť(u>öxă¶Đëł·C6xţF6µRı ü! G§;Hʤ°đ0ʆ¤Uű=ž% V> ďÂëŘ~Ţű}4p˘0~‰÷<đsL > ‹ő<Î:‡ľ[ ,Űňżu ¤{ŚC$ĺłéwşš«–ś×R7e&~ťĚ²Ą„{‹ę)ęňĚă(čdLI'‡ËçóŇO"úÓî,Ő›[Ç~ˇWMSéűbťŞť´˝Ŕ,Ł Őjč”íôój¬©5{l[§%’ęR†ę´gpqšÖtş ţľ[jÖ”vôô®lRđ9éř[M¶'[ýđĄyAĺ«gqý8‹líĹÍe»&1®JI»Żď\Â<D~ąÍ÷Ž,Ń–śYŢÉ Q;éḠ` vé«F_D:gĹ/ ‰ă Qdgi…vúź"m5Ü c•äĐ©ü#ZĐ8ţ@Xšîöńóęsę~Š•đG_ z4ÜRČ^„ř$,dcF$t‹!-6L‚¬{š¬xźÖÇ«hÜőÝč ´ Ů *š˝ŮÂ…K*?)çužľţ”ř»Ź«Â‡©ĘŹF?Âe3ř6ŮăěĹóőŐ›Ěyĺ˙|O"{EŐKÄŇCŢ=g?™Áh”{°ą_™ęV'RsTQ˝†%Aůę\řkbv‹đ1÷4ů…wşůżT늱Żđ—!©`ţn» ”¸Vćĺb‚)ßç¤ďŻJŽŢňeĹz($1ú4Ô؆€wŚz…˧Dˇŕ?mg·uO¸%%qňkö[2®‹d˙8ćAţďEb Ö­1źŤgkHŁskjş§É6üŽ\Éř„ú\:ńVëäŮÔŞśé6Q?3˛w*ÜkJ’mAp¦fĆéĆŔG¶ł5Ňw.í­˙[)o[".w–kgcÓ·×ä([̢çóé­»t‘ňř‘€5éď;rČtź‹M€|vČŃvş#—ž_şzaŤ:‘Ż)qO3AK†×b ›J|/Ámô8Š.ű'ďN-¶…üĂ'*CĚĽíŇ’łš2ç:Ë6ÔäÔnÜňâö†ÍŮí16YŐáĆžYŞ×,čn,O5ěHF…Ň›»X&¦T6r<>«±N­®]>ö&…´†wi3i‡±ßp ą®rDĽż¨lŐ?Ř5ü®e°«/ŹE_(˙=Nč÷›¸×Âsܬ)éët•Ě@K s~!ĄcPťôµHÖâAŞŢŢĂű3Tçhňfm_˙nžtX(Ô¤Iz”Ý%‘@6#Q—qE8qÍűĽ“ŕ'¤ŚĆ'EŰ[sôE“†=Űď+8K1Ô¨ZŔH§Ű—z»ÖK«đĚě*{¤TÓUî>+l(/zŽăÜŤ™g‘xę• ˇń#ýë`óىćć—ÓIW EŻIiUťB]ŕxÇK?AĂ\_P9¨ŮD!-;鼂čnx0~–Ž$3pQď\;Ü…TG‚DFŢ'®4h9ë¬ń9"xÍÎY.l«TŐ޸BţąüB(@SF)z¨WłŇ!ń-ąŇďbÔ­CXcČjŹő@ş2KüŰ÷űMĆ<Ůhc5™ž+ŐâËÁˇďŕŃ,‹lśDA {‰Ë+‘EýkÔX.Ř[ʢa/čB6,Ş…cĚb:aSzÝx¦Ë’ „#”ŇXčŮöţüËćşrXjšÖáRâ+ba_9ăÖôŔĎÓ"•×PeHĂVŹ$ŕO9·(ů5ÝYeĎZ s஺ăµrç:‚- H@\Lŕż Ýô*k2çx7<đšäăęŚ3Ŕ‹&Ç—ńt¶Á‰!ô†Kp ű=Ţřd\ě,Zˇ:7“Ă5<@™ľ*%‡"ŹOŻRŞśË„±`ú:®Ŕ úşćÚ¸’ć ?6šĺ{Čŕ/PYřŔŤĽˇ Ú˝jË ¤3ö%»˝ń ‡0xĆY•‰âÝ"†˛C p«_;´,ŞIÍšÎç˛w釪3T…ą›şˇ´řĺšŔ"ÓŽ{šv´Q7m®FE‡mX¬'TĚ„»ľ[â~ŻŻˇĆy‡Ë”\FhJvő°ß\rŕĹé©Iă^ştFÎÚŔ¨ăpĘ0óß;z/ýH¶*жvjý솰Tšć źíVMHzÄ*ä#ÚÖ}šŤ÷1ĽiĐŔżn®‘ŕŘüÚĽ™ŽŐy!ŽĺW`P%Y5愜ťôrĂô†•Ĺ, l·˙7Sziń7‹,| $–$1‰0YX’ÓŔF=+äşcjâŕ[GÍIІąi*´I$ěëÁîĹěűŹŹ|sX´ĺańçĺP{˛>O¶ˇ‘Jąö\‹műĚ%(Žv:jRz‰Üm¨ţ}¨X‘« «fµho¶^ěż*±JuµnÉ.ů7ŞáŐŐşęřŕD ¸°»ŇonBÓ9ůŢR©U+łúRb¦řůnAä«3C°L ¨MW&ÉĂ;I‰YŐ ŕ(*íZ€š9¨čß^Ű÷¦|š}iý^ {®mM ˇ+É„ńŮ1rnZęçş3=yʨA ™"śľÁéĘČŐ ±ťzWş™I”c Î<@>óşŚĎčÖGż<{ƲÄZ“vÉ8ţX4ë °_¦8MşbŔuź@¬¶LŚXż!ťäź'0‘†ŚVű`édoP4”×˙$öĹé‚ŮBtńÝ)ˇfsµ‹wYiDzĐZń­qv4©Ü˝ˇ**bűŹuµÎĄěč±Ú^5±É2`Ścµ&$˝üžź´°rMň_ř?Nš˙{Lé¸đŕɇdŢ7ďÜ®ZvĂřNCYOÁ}ł±·¶*(zŕÁÂźK¶ /M1˝ňYF“üRrc© ČÝĂÁm/ŔŃ– M \ ;Ó߉ľĚ)´•ŐŢbyÎvšÖŻÍ‚`gPÔťBŹŠ´Ń®a^•Ä*:ŽáŐ=‹+_C‹ű-D‚F˙!Ů¸™ˇé0TÍ‹:ˇş—ŕ±~¤O •ŻźÍ”IvąžřQK ¶ę48ňT"}ÖiܱÚ;g¶ű†E•?3˛5ţT“ńPoŰ=ŁqáůP, öEü<Ć0ofľNÎđ´ýɢ/Ţň’kź9Ţ%łGr¬$t;č ţµç\Ş@–›ŔśZůä;Ź™čaeŐj’lű–x÷s"ŘŤ ňż¬u»¬„…ďçE!~jL2Eí< #+·íZ$ň-á[É —vÁ¸ä€scÖžÄĆŠŘës~ĆLĎĽ§úž]ŹIxŁBpëAa.đ5Ö ć5ZŐÎôřýUČ„ŹFs¤čÓ›&>µŤšÂÔ†«\lQŽĘBäĺhŃLFoĘaţˇ–í\}ŕ‰e7‚ůh y'Č„í’ Ti3[Ţ®FŁĆŮáąsřÔ1Tad.\:¤ĹTjęFâ¬3ä“´ńQÍ”2ę豣Ł#`°™†?ł<—’÷ę[n#;¶$F_ĺ#EĽí§§.V6ş_¶ĹÓ,|8byŹ6Vn˙p 1PñPMęnç—şű%&ł¤#đBűUp.=Fˇě䊹!†p†ę=ď´ČĹ2ÝŹÚSäöÁúľZç߲F ź7!ĽEjôźťäKoĐOi¬A0čŢHÁ6@ä]M^÷žµAŢrO‰Śčă< ߆t™©hmkd>LÄ|ą+r{č`ßPăÝĘňBpčeS"š\;ýÄČ›i¨Qé~‘‘¨ť^[*úÎţ§B_IŹÓ#Â\^Çt$ëÂŽľ¬®˙cčí§uóC™­BýacOzůW… Ą“÷ă™˝5F ŃŞŰaę©NU#¦"{áp8×Ü2†Á ŕŘčO)z ¨ąŃ,`ŽËć¦3«c9U•.p;Ü{ÂŃ-ős·c÷§5xÓ•»ÎL¶ş Ě^Ö 4$5•C/á(6Ç–÷ű¸ĺ˝íQĹ+ł0¤Ź÷×Qý2¤±ö-–ĽŻ#K| %Ś@ľ7Śę×ůĺ™´ÍŞŇ\miŘ©(ÇÄD­Ë…@Z@·ˇŞ“/Gv0¶Žź™đżŽ§}®ĚçĘeM\‹-ťŚC‰3ͧ`‹Ó:ěíÎv-—šł›vB‰,˛”»lÝDŤmśÜ ›Ô˘lË×:ěy÷D'çWŚČšĄ‚¦82UŃ‚­Ń(×cáŇĚßŕëiźÇD.WňÂUE«ÔŔEtÖaX‚FÓű„\Îő!jń÷â¦5IËşRÇëčŮÔťvĂZ&>? ‰›Ô [†RÍĆ`ĂËŹ)ôĄ81Ú;.îg¤10] źě¦2Ä#éÇ“­Uý("Ś5Źk|*uâŹKİ G¤7ćÁM ­ę8Q± ˝Ań‰Šqh×áů<IJ‚!*J5Q/Rýą‰ęÎ]ľ÷“ć:Ńä|Öˇ¶‚M_ŁScKÜW€5Ŕné …Ď÷Měćąß^ĺĹ  řËźZ}éÍYN¨©wŃę¸ď1f4 çn‹Á˘Ő/–7Ö Šíy(WŁDTsh»ő űÝ–p‚ńÍŔéqPítDę}gQ+—ýT"˝é[ďŠŐĎFŚúŽ@%€]îě.ĄÜ©Š7<_ ĎŔ@Ĺ3 c¸›jřÔáŐ,ᮼ¦LY[/˝łÉ†ô—ö]˘‘´/»ńÚŻĆ ľOěŤmđ |mbŢ(Đó"Eoţ*˘ý;qťĘĂĘT •—幨ĸ”-Ť^óŠ—ŁĚë~Ď×§{$ý.~ Űáٱ`v>äܨněĐ ŤłkLp,zăćĺËIo:fŰ×őÓ¨•/xŇ;—IFń†«\Dq‡ÁÉTCËşĆ"ëÎ.y> ÉČ 9Äl?5(<ŤîGÎCŚ‘и_¬†ý;W”|ś89»ô[ݧńJ -(0×.,ĄIŰ  9!ĎŃ#çrultÖY«C^O@y_ţHΧü#·?_PźµŹ.>Öl †{0ÉŮŘţ”_ksŹBŤţ*ľd`BöĹxŤń?Ýß–Úc®qE|ç<LJěX]łżä“™6řz‘śÝo ňřGčÄ’Ů|®˝^Wç(&»2dđMuăSdöňµ^+Up$űy– ¬žżőřŞč }cžÉ‡5XŰÚ( ďĹ葪nµ†ŐɆ6 ÜŚ>ř! h1Š.ŕ$yíM -MÉßEŐ3öâ­Ř8Ą§@Třłţn9t= A "`v:bÉžNEť‹—wzzˇm©€’Í·y$Kä8Ô›¨EňG™Fkë¶Jý¨Ç¨Ż¦Č‚ČýzŞ“űâľ0ę2äß˝¸=X!DôcčgˇvnĆĺň ąěr+/T QÔd,ö¤ŠÁçÝn‘ŕŚ6®'Č­&č&°°vgđh ;‹Âv'Ǩ¨Ťl‰EŁŢőz¤4Őe¦„XŚR–ę‚R}ÄĂ€Îuâ𸆕ޑeăŢŢŤ©ëe{RUD8&$Ń]Ę‹Éë)ÓÂ#`¸Çńyntrđ/ĺ&ČŘcă›­cÓn#Ĺ —{Ź%ÓŘÜWT˛çŹjľçŇĄÔň…ńîo±ôöKňS1ň0âD`sd : *ł"—q uřT¦őĄ‰­˙wó'ýµv5×č&Ѳ|>sĘé*ĄíLŹ%‚4dc‚yÎfzh”#]Oíöyľw*Š}D-ÓŤNß(s6Źá5ŘśÖ˛Ł®h˝ŕBđlŁŠű§ 2 ŤŐyŤS%W>˝\1Ň7p$ŹU ¨´€–¸¦=˛ FAV'"ÓU¶‚ÁĽŻENYă+jgAĎë:6§.M…ë§6 Ž} P-ćŰśâ~0 ÚVÍSúđ~°:;3%ďšE©$/‹·‘ */¦âż)qŔ +<ײ®ŰĂ{>ć*Ĺčd2c÷Ăńř=şaĂţBvĎŢ@q|ţU`ŚŻ ”Ö­včL?Ś^N¸&üłjĹYI"F€ť÷ä‘÷ůţşVLË—Ň–ÚF›ŮžÔémźöűŹTŃ >ź brľ29xuÓR_<ȰaÜ9P+{”Ő°Ň˝ś ţ«:‹µő3UţxÝKÖÔMsš•:HŔŢě꫸ëŘó}Éć+Ć(ľ;HZćVŐ˛±đäkÁ’; öţ‡żÖÂjŽőú‹á›–ăť1şýRŢ‘§K]7ZTa‚é.řąŢ‚™<đţr§‰Ň‡"4łxPµÍđFÝŠ@µĚA3˝»U'©f€E/CčĘC~R "¸ŚŻî#•·Ž3MőůĚÔyE0´y:(ĹąË=\Ž/.»6ţłÓóřË“Oá'ĎĂe'߲‘÷ę ʧ‡—Ľ†ńň–×˙rsvcżv}Ôj'i m`ŽÖľűŤżÔ=j®ÓŰ,RŹöĚdń˝Iá Îá*F®ż©vTŕÝÂ*2lž¤‘‰Y3JT«B<úR1¶ĺŹâđçSuó|ß7ś7CKÎ0¦?ťXą¦[Ó9X}µ>jÍĂ|eGă‚đ‘RcÇ—˝<ÁŞ™ľě^UFµ˘d‘űW°`C„UĄ‚Ř ą¸†÷€·Ú/Ę·0ŮB|§ŰqPŠMwF^~G$ÉcăöĽŠÎIdůJaŃR1˛ )Ô–@uüÇŞÜî“h?Ľ¶g%?†ź…‹Ňl´…?lü#="„$LČŻą_0UofşYÉ$ ´‘]˙6ťiŹYÜ›CD˛°ď #窖)iŁď1»ET´VŔ iKď.•b9z.L&DëÁ~ŇZűaÂ÷¶Á2–Č<Žü/^ř¶ćßŢ ™ľć!űťŇ‡qÉ|wwb°=r^2^‹±Ú:jT Řb?÷ ŽĚŕËdŞŻ‰])×̧ +ŢüË˝Âú+®68·ô/)Ę€2uś”oűd"¦¤˘kŰ"=(î‚úrF §Át~ŔqźL\1ć­‰ĄĆ¸RG‚ IĂď6˘wcL=0ţŘŇű5ÇÖ < GyF@ňş…QĹęËż”ńćTS$^v´›ďľQ+-©é7ci—–¤#+˛+~ Xˇeúşěm©cfcr›S{ś÷.Ś>úą,˝ĘYŐÚŢş#.bŢj=˙;çö! }¤ýL'äjĐ7Á$;ĽR¦Ô‚­zůBpNśd'ňŻ Ńő±óě ¤ÚĘ«ëX;ÉÜ.üîZ“ŐéüLŇú2Ýłźżí-ŇÁ]ťÝ·ĹŽŹFBu#)Ą_GfGŻD.W˛®Kwz„+d“ˇ%H˛Błî;{hZZö0$âĄzÁřÉ)”\âĆÜ}Ok0y¶ń]›?ÂäÝ$›uÇ1ů¤Ç]‰G@Xč’CUű+Š'„PhÚßßďŃňSôÔÔ“ŞćÂeWô„quÔ÷=)­ÚßFdîí¤‰ŻĂEŚÔ˙e€Wť áÎě»ÝŻÓFăOý?´l|Č !íí˙*µőÓđˇ·2›đÖyŚ(ĺ‹g0žKĽÎÎ>ĐÍrRv.§„÷D‹( $\ůś˝˘ťĹ»o0°IÖ}ďoL@jENŚ›Ik[Ň›FaEö§®%I;/îh /$€ŠpćĽVôć ś*©Q<˙u ćdaŔ7?řB9;4ů–™-‘p~¸[…ŁśßP¸´ť”$?íUJVř%wé*ęƆ—Ť{jtđ!±vޢĚf]+78­ËtöS L¶Nô2Żg+DŢśŞˇ(5R/čâ5*¦á©Ä»Ľ‹÷­T.`”¦Ć&Ń{]p/ůľçuj bë`z‡ X¨znŔťŔëŹçđë†ű};‡§×đőaĎáŘđő`ţµwŰ훏áÓ7đô ţ›źĂÔćť:ŤŽ©•ůţźíJđö÷t;X ,Oj:*|F-¦2"t­ĂÝżłŘG˝m¬šŽhµVtżŻ-_%äk"–†6»Y`ý×˙†T·i)óOUî”Áł3đ3¬ű¨·Ż|ĄáíŘ¨Ä :f muýŁá‡SďÓőM¤ń,y˛˛G<@žîŤ´µŹt¦Ç_ŮÉŤK•ë:ĚĹŰéíęÜý‰&(d|J/ă ţ‡żčge'ň­>áašë˙§fë_GTó:xĹĚńŰk7ŮţçG]ÝůJ3‹‹š¸ ńq?Ł%Ô.×T!×N‡ń×őCö\jlŽ1úąÇ™Ä\MJ!4`•ű=mĆ%‘6łFLäóńD“ň"·KtîgIŚ{‘'mHx'tUĎnŢ(?ŕKĺaR2ţز»uŢfžn—ň)Ěj•-hš6a[ĽŘ0\ŮĽŐcś‘çé~ĎňKŻD UG: &¬„xĆ˙w—7A÷«»ĄÜÔg»Č—:ţ9çŹĐŐԚȜbň{ 7Vá%A}ÉáDŤDř…ę3ľY«>~1-¨Q;î†ĺÓżJă6Ĺ…†6ł.ńMmúRśúpɱŹű=ÇL?]Ąď›ţ†ł&ß)Os¸(¬qÍ~ŽÚňČ)Š­Če˛?ćNVŐ}Ó˙ňž)čhýKäń!ěşv$×óúű‡iŰÜFťëQr.r @_Z•`QIWŢŐ ĚžBi¦ľéb˝ýç[GJ"D·— đ\P0©ć-ŕďfąŠ¨”FĹu-^•Ő w ÷ 1A—l4 n|JÓŢ=ún€ŐňŔ#łů|çwÝę t¨Ü+ËŰ={űš›ĆťŽ‘+xăLÄźžp!gŚÂh!@’ĄĽ:¸T"ŔvO8 ň7`ŘYa¬NHÖľUďă¬{F$śyËŔن‡·7ßďKöeyŔ$j•EVĆřMź^Sć¸ÝdÝćVč& U #ęknň9č[oÖĘmqö0:~-Ů0îhé±ĺąVQč“B($c\őężąćf•°ŕ˝©Šh 0‘ŕXŰŠ«¦22bŤ_Ć\YSáţ•M§óŘŚí+Ic?ĺ`ćîűę7„F°!x6čäő ĚíYU×Ö ôIđ›ŘĎ˸ӑ©ăײPďkŽŔëBŁ=ZĘ1MŞ)ŠZ~¸ŰQŻ•Ů­«ĘP ß«îîa”•±†…čËüş¸ßGň¬N˛ŻÓâélś-ý·nŻéVó0÷×Ů+„Ă6ĺR|M?+ŕ’etŚléf{kę}úŮ-+‹J7ýM TŃďÎXqęK…=C|r­§&“s2ˇI;… ?Űdě{ôÚó‡Ä°v"@Ů14‹ˇ2%»”Ď$Űç´4Ćž¬/n•ž#w¸Ý€mţn6Ç_S¨áűÍ—»…c.e]„…ö—7LÚn˙5Í‹ď7dČ*|]‚Ş…ph‘]&©ŁJ#Üdőev‡ű[ćż}8šh±i‹ě7ë÷f‹÷Z ŢÜĚŹĂ —‚]`)ϵ ę{ĂÖ=?Ą3ň0ř› ¦äËOtü>„á0ů‡ő¦Ďx†&OHě¤_'ĚźG0ż#ÉĎ2Půiă™ř÷–D§‘Ĺďß;śÔf6ľűlŤŘ‹ŠŰ‰V"H÷ŁWÜ×ĚďéÁNµ˙MńTĹß#t´ÝNOĄZń ŕyŠĺĆôŔé%R@h|Ěh%$ąD®ÄČ„{«ÝĐŁo–g"¬TÍ šŐnśŃܸţ0óvŇßŕvŤF79Ü îQá·ÓŁ đҧúë„˝‰ĺ_a ^¬“GÝä§đm«$űzâßmčĘTeőáoŤéđZ€”mk–,v­¨ÍRKĂ­ăÔpI:ßľ) şó­s) §bÜÍŮ’.Šäă˙M]Ń7¬b­MOŁaŇ•ÜŘö¸řň Á Ő9Ło•¤óÉ<˙MҤmWčžI sH¨UÎy/ NL”śW©®TI÷©ÉŘ\“˙|d`]!ěn<„ⱡ,;ne+QźQpą¸ńĂe¦&2›l$©4ć·HZi8ťźŁ pÂë†ý-˝ő/ )ד e™€t.üňTQaŚÓ6BřÚ#yxvłhZv ńŕ\+ý×,Ń0’nIiow˛Ĺɦ·—ôĽ;Ř–N(ü©TMsßq‡ž–é¸÷€B`áU‡ÖëµgH9xZ @4ÝK"Źq‚’Aź„aË,·U±#°Xë˙â´ÓĘĆ8ůâ"Âi¬đm[˛bdł|QětĽqTZčV?7j »0ý=m® ×@€A8D5ŃžzŮ9AjťP7ĐPŢ4Pł3ĂT XťCăÇÓąĹ/É:XVŤKżťâ›n(„ă­”׋!ýýf¶á4˛ÄŹÜ6çOŰ, D¸=¤á´3Q:h0|ŇHz*Név«n˛žçăQöqQ\De,ĄÄ*eż$ Ő8ôu]˘˝5Čźä'»‡…‹#MÓŞ«đ Ž™Ł;Ć3jÇ–ňńŻ4†[Ęlú ťÍÍCő•Ośn1ů¸¨_"Rč8KÖÎ ó0qët” †,ýPăÝü“uđ-q‹›ă´<řÝěŮ>vűýáśfÎf@vý_Pń¤ }Q*„ÖßqÇWŚôIMŘÝZh€J ŠR‡4WŁ—ęI ¸ÄžáR-—Îí3eJ…]SÇ]Ĺ’qtrNlü/WĆ#ş5Âň™Ĺí­Űâ}»”Đ”@®/§Ś…ůlS^a}fꫣťö}¦GźX|¶ß^˘“2–3̦ĎČ௬Ą“:Ö«ęĺÄ …˙EÜ)‚(Ť&-˛‡wź×»«¤p^śČvKČ Ô<Ń@Ö™8A}+±…HI®+Zô˝eto»Ęfsw ÍqKőłIć«ÄSđ¬±Ĺá~Í_ŹÚ ó[m`Â?˘> ęË,iIł{FĄ˘$d.„Gř–śš·¸B=~®ţ9WŠYqÇ2Z_8:Ql˙Š–s«EŮŕrNűwťĹĂ ů‚Ş™‰ě=Lł”ÂÜüű‚ęß’FŰÓ d4]@ŐÔ?´€ý»˛m$J¤ů»SlÝ7öů¸ű“Ś(Żpqµ$¦ć€¸D˘•S· `YÄř[ [äôě×rÜCV¸źŇŕvZËGéÝźV.épDč—ŚšručácŠ|ÄŃi«í8(ľĆ*ćĄÇŐ/V¨’^ŕČp‘Q96D0†—(Ö>’M^_Ľö¨‚ŞAŔm†§|ÓFíVżşfY46·á ŃŮAĎłôýnď‹–ˇî$˘ł/ÄłÂl+½,śţh¨*řřB ‰n4ô6á®—Ä6ŤżĂ3&ű—‹¨ĄHé〠âTšúJí o@łJâGî¨gČSś üíí?3hFÉ\ÉŚăĺ6~h˘áÜÉ~Ü~zi·lŐ4őŹÁ’ÔOí–c‡Ť­–EjlęŹcmŁćŢ”Ö5uŮĐŤDůĆ[xé·Źd·hŰĽ <ëmÜâĺ]—ÓŮäóŰűÄ| M¶Ń‡žęlŢ ZęMź- ůéwŰĆ{ú«Á=¨cbŹţeâk9ż©±ńbQ`u®çáÉ{RőTMż†j=ŔĎbŚČÜ+C‰PÇŢjFR)Ň҇Ŕ?P5QZÝô¤uy cČ®á$ÇşŐ^!S¬ťđ•ë#ĘűŢFý=ˇ@,Ř"m”Â/čçźQYXBLŞŽxÂg |ť¬ÖL"éŢşKMŢa:$첬‡Ó¦ÂŃň$(…ĂÖzs´BeaŔFŃbř]ËG˘,id(Źâ{×W%‚5®>QÎkŞ{?ęĄ3ˇu­n\łm¦ß`ϸÔAľÜßĆi˛˝!⥤ZyJş¶R$c6Ř/©U}Ť4îBá°¤$7Ę«CäkŘ1k*•Ţ.1'<ę–čìJ G‰Ĺ`gé~ůb1?°îÄ‚Á cĆšĆÓŮ™—ď˙W+>ĎĚďt•eĎ6„Öŕ\Şćm•;3·ÚŮ-D%G– …ôfeĘ—YMS*t¨`2Ą>Ů˝¤[sk!iZÜ(`„jüÔ`!WĆőÎîaDAÖlBŞhĚb-Č ×±y·"“ví‘qąö_ó¸t}óŰĐa$t:đNâ'CWq¶UT&φr &M<łŹÉwÎą»r~FČΠ~dŕ~ľĎź‘yJ‡śˇtiе›chŐ^p! ěÄĺ¶ß.€»"fŔŠ.bž}Cą"§:¬ęŮ:®ěšÓőO”ű?ě$Z›HQúwggYv(‡ŻQ~†Ö¤ë±pĘţ_ÎĎ âu;ť¨ÜË”‰Š>Ź,™ 0ÇŬ.‰7ü37Úúß\cĆ1ߍ,ITK)[o{t»‰ŹŘ Ľ€ąęK]\ąĐĺ$ŞŇŔţ†ľE=NfMChšŔ8«(ŔĆE{ Ţ.8­jy/*őED8{PýhYIhSsAEŰ™€›‹­Y§ Ż6ÓP‰Ă{¤?żşôŃ$ů}zMď'ťç›p#řô1¤M­† űŁ3Α F)Ä ŤŤń1#"A•D™ŤV§w…»“%ősťĹҦ1´LǤ"ą=ĽPŔ/C"o=f…šĽâč뢪î-oµŹÉŻIř? 3řâňp~p°Ýę„u¶7 L|i] A”Z4šŹĄĎµ(nßđťE[¸utĄë÷RĹyĎ*Äc`x=Ů ď@ČěY­›%潝&uýr©aârë˙;”ţޱPĄJš+ÖĹJ•'µPŮŠV”;2ÉčÔč%꯸§Ô-—%Ň©dďĎőĎŮż „Çj?O ›H_ĺą˙}w<şW-ńmpăĂN)8+¨řłş‚QŇĽ0Ǧq´ˇ4 "öGęńá˛˙c sÍ’d :"‰#Ř\ ďüÚâ˝îŚž˛•Ś}çýpŠţzÝÎy‡Ń ł˛Ř5äĂšşÂBµ°PĽ §2ô+íMĘ9˛µz2xmĎž_R±QqőžhĆj„Sźu„B< }!5Ä)ĹɵNfŮäžV™)’üfË”ŽF:(SMsDŠý—]–@4BŽD“šŃ˝pť5»EŠ.lb?Ňo$4‘×C!ň >ďaDHô”ŮJcżrKÜ?®ÔJ"9)jk˙UčH Gę„SÇŻĚ‚P8N,Î]ÖŔ O‡ĄZ«—d»SAgJ_ nŠŰK˙ó|/ýŘ3A+î gŞB~ÔŽÉKęţlSN«ť k `{gĘk&¤ Ě Ěźĺń÷şĎŁ#űđa}ź˙ylthm®%ýcŃö oäDĽ™CöĘşBBˇńh|^|}…€čŰ­7ďulůB7đ«úŢ»‹@ĺ) H…OŐ;Ćé4 Uő¤$˘ÔAÇ9MmîG›'ţ"ĽĐöíŘč´ŰĎ.9A“G߆=MEŚĂąŐôBN}lV·ăÔ$şĆś˙|@J‰ţ7F‡B( 6ťćŹŽŁŹ%µ4JdMN]¬FéřO° łŃ·P Ćý«±­ńÍg_ ÜOÓI-ů˛ôö1űÉ]VŔçK©]{2¶u{÷˙5Úlµ­Fú“úFłą¤nŠŇź…>}®·ZÓ‘0âŢăFżí%Ú*ŃF–Ć7]Ś?ń`ŔBRá#ÜíxűKŤ)ś)ä8iĎn®c—®Ě@dx9G¨¬“IŕÝç̧ –á‚ŕ!A—3COoYKĽ}Ä3 1óGI&˘ĚóďłHřÔ=Ůx} Î>^źťŚ|€Yřśb˝%ÖÁČE}¨“9{H`¦DŮťű:Wď“RĽaŁf-ôŠbĆËô„˛d4Ú†?IÇĚú8ÎÇóFásŽZYő*şĐŃS–Ô“ÝP6ŚĆbîDzTý‚€Né,qČ€č×>C¨ź‹ëÝ8l8§Cű•óPXl&ĽÄMÔ% ÔłÔZktţxńîŰ^)Ô¨µm7E1ÇҸŔ˝?GąhítĄ(¸ťŰ±}4üW®ľśÖăUZ\Oiđ`>a&G˙Ů]h;.ß ÷qŠßP@s—Yłtj¤ˇg*`HBěĆ:A$ Ă®>ˇ6d5ëgDŽ |ÖąA–Coz›g´łť÷Kp  Ë­]#¬Ţ0[ČŢŽűÇ u?]”Îňúź@ö~>Óžbň “^cÎMbe›—˙#.J:Źuî(´ÖląŘÚy~ŽĘĚ1PI|Ěß(Cř^”L÷H{ÖűßAaďÖ¨łj7‚sŁáeÍžŹů `B"XwQďĄk҉‡©A|Ź6u[vĺQĚâaĆV5PÂŚĹk7/é2‡ÖZж—Tޤ.Dňăް¸§˙kg»ĄČ—ۦ«µíRć{ë ˬďŚY&¶”Ď·fŹĂ5ˇJrę –"|ďɰɎŢŮ“éű=DŕbŚU-0rŘ"×…óŐĘŕż´ÂWIlK폳’5ŤĚh†…}\V)őúęDqÁŁľ­ő›Á}~¶Ąćí|¦d*)ů쎪ćNç”Ě˙<(ť0şhVéş“Ż1CPqJŠ+TçűÓ{t}öc“Ą[:Ýů*)yĐd~´ČľŮc)ăĄAŮ Ę(aŮA&TĽD7ë­˙z˝35`zŽôłM;Çůľ<ś]"™ăÝ´ŃMJlpďqç–uŞA¨ęłöÔf”¸ µĽ®mČ,ס°qyp´fÇĘJަ¤Ô©¸őLéU©ě…;P‘iÂ΂-]ĚöO!ˇ0G‘ěýlh:äśbÁpńz^Fyy8¬ˇßx¬ĄëĚ’B&ż?lÂ?)ÜÍŚ¶“iń&fa$Ó…|úŹ áűËtł›ş"Ćvg—ş®@+\NÖRo“É ˙}»K›$©RSŻľc´s0”ťŃÖKßç)3ą©Ĺ¦ Öż ÉH}ş.ô骫žC` I‘[©3`Sr*$"GgLÁň؇Ď>(ţ(h×ű›˝/Ô{ŮŃ˝zËýŠ×_ŹV ń!Z‡ľ!ý0ź8şgPÚŕĆ^›ź6}.ÇG#WSj`Ňőě35¦}^55}>±DŇúzNbć&Č'~ˇÂ1*˙qăˇň_(ŔśpöÄŚ˘Ş.€šŰµ;]·ČqNŕbőÁµCpÓ ĹíÇcľ«2’x\˛Ů7"čĘnÚ˛ ?ę2ľÝŮ YLC‰Q wň,íO&u ˇůß8čgʆŞÔV=·ýc°ÍŰn ⬠0€ű*‹«¦#OŇ ÚP»+R<úŮněT ą;VogQę¨Ć@1•'ľ¶Éhr1<ę?„1ÎÜ)bcÝK˛b+$@ŁAL)!áŰ=†ćŃé‘Rc˛}†«xčF+ن\đ TIű9|yoÔE± SZAâxhˇÍ¨) bkČ h=0łá®¬Z’ĽS"řłčNŰé­ë‘łMLD×jeÍaë?ęMŘá°F‚KŽď0 ÷+}µ…V“ĄÍ—˝ …qd®Ý.`…§Éµš‘ŻĆ!¬NâTMRÍîęŽtÉyöşőÚCŘšR8íŮ]}ŐϰŔ3řx˙NÂőa§9Žtw¤ł¸vĺĹ_ÂP׳™†G™»¤Ólť`Ż˘Źt}Ć÷ý´†ÚmĚ üő%č~`ż”6Ž;ß᪖áDlŁ~¸XKĂôß ĽÚcíě’´«¸Íą*ĎB=ĘŹ(Ů6± ÝaUJI<ź*Šä©Š4X©¤oB••ÜŢÔ€±ě ő×%oąôe5Á‘Źi]3ť/)z -,ËúŰ×o…ŘăŰ9ű+oÍÄÉ@e3“ŃÄýé†ÝlJc^ŔŐ7ďKzéX”Iy_@˙}]@;}Ť“Ŕ—8É0Ť…PĽ”âŘl ü‰2˛łŕ'ľŞ÷ůŹk„iŐuťţë^ăÉKCn’CîF(ĐďćţĄł–Ă&\e:‡żb$@ŃČ"B8%3jeRs1ćżr;űqĽęůÁźµ›g6—‡÷ ±’a‘Âľ6šŇÄě箕ŃęBd'ń@Y˛pŮĽrťáa2Ą‘ýpŮ­}h;Ďş}¤Ľ•·”!Ń}Y„ŔhŤŽ’çŁ@µBV:ćnщ7ŕĂÚTť‡ ŃöŽş©$¸ ­Zń'I°şVQ2"ďŃ'č ĹD¶ĺ囎ĺ«H9'&ř(¤± D$Ŕ$â2´ÚY„ˇŚžŮVS0Ŕ14‹YzĂjŘOćµÉuĎŰǑߓ’ D¬JôźV•6?âŐ<óîYwĐp}Ý\<ë 1˘aĎÝBJŢJ=€·ŕá9#9‹ţ‚jŹČc]É ©‡DĽYřŞóęqL†şţ`”˙+蔢q;@)@]©ŢE+EH`3|;é‹7”AĆŽ\˙€ ^2O‘6fÖ}<¤pw'¬4KÉŐ`)”żźCšžÎŻ235•h’ Î?c3<-ęX†Ů†Á5Čvç˛â3Ćo/1.; ŽGŽŤ"ŮśślłńlĹYTWçčSĘ›%0ýr|¦™ÔO-&B¨Ěi}Qb44•Vö4ŠÔv%/ÄZ0U"°Slwšżâ*5Ź Ů‰źĐĂ"ˇ-¤őpśĎĹD\4€®Tmâťß10—°ĐĄëÓ§źf"BÇ{Z¤í ]~iK>C:óFoČUĘhCČľîşůˇ™ÔŢňřSŽśúŰç…Ę ×ř|µ,űyŻHązcÁhŤŁ¦J‰\ˇ:¸,Ń«.Bů)Ŕ+Ş­f<‰…‘ZOAU´|Ú©®aç«™ŠgôęŃ2ť™“ ;€=4B]ŻSLąÇr…WµâţŮJ–źĐt^ß‹šd!Ô‡ĐäŻňĽişÚĐć~^¦Ëę9xé UŚ­ăP×És=•cQ.µ°-qş¦Dbj¨Đ(źŮ%fI_íWî8řŔI°ÝwĐĎa˙mˇŚď(KŁÖ•¤eő$Őć+lH3ŕőú8'äĄ_Î;=Ct•Z#H>„Ë1:Y?CDn©1íyÂRO˝pĐ lG@jW#šîđű·ÜCóÉúâĺňhźC_Şa aqÜ,«ŘůkőfÔTaw뻨|Ëâsč»+ąt«NÄl üŠ.ç:gÓyÁ&jDirß‹ĺ‚KÓ˝ô +äŘô§{ym™żĺXŞc § v‘«?E‚k‚Ó„µ˛VěÜ$}ťB"žË‡u–Âľ§¸é@¸"6‘Q×BŚÜ·¬:–ShŘ•p ŠšˇŰ ‡x$çó@:YÇÉł±® bŇĂ]1jažŚ…Iąe6‚Č…­ąŹśYL‡oQ H»g`Kł&.%´IABŚÍö.1< _ú„ЎĐüĄăż/Ä!˝°]ˇ®“#>!ˇőI9:,TC<§Ş~ÍWUVŁ!#lËT ghQ«áˇť'Á ĹK*h T…sµ`bĎŞRFo6$ÎÓ;KÂţNđŰđ©řżrŃÓ#5·FŻŻG=®ń‘Ô€-ćĎ;"…rűĚ”!Ů„‘đ4ă FűŞ8ˇÇOvĹѨvŻŽn!¤GʏJĽ xňŚí^6ů™˛Ď!{’áĂ`^έ­9F6ě[3Éő‹Ł^îH±źž”a;,Rf“ęfŇy~C¶ł çĆM$ôÖ~UŽôWÔíŕwÄ9Űň¦W6˘ČÇGrbâ5žÖďV×~‡˝O®–ë)J9y"yęő«çh™7¤˘+̦‰ Ě ńÁą>7 #~`ţ,Ýt"ř‹Va¶$#ßÇ5fřňŘ ŇzÁ#CTýϨKú ÎÁSđŞüzę!§p~&J®†|ŔČ“![…ŽŽŻ@ý lRöQĎpȱěmílü™«=ŰnĎwÂú5 n łŤę&3Ţţ}Ăf@ş•Trą&b®t˙$ţŃĚ2Ćoęđü»ĄßŻuú5P¨ŮXÍcMÔWë} Vň¤§YaŚLN.†n˘„„'x7á·+•ž)łŞm…AýTĄ©1}!ľ*¦ÂđKĆ8jcž®ŻdKű¤ťJó 7ěn¬8R±eĂďxĄ7č3p)c¦Ů6!tľÔ_KŻÝ˘–gčZ‡ZÄG÷^:ú)#LF’űâyCR6ÇÓčHŤą0žrHŁN4$1açÝpÚăą’ćá‹Ä=T;#„!έ :W©!,˝‚‘+Ç"¨¦‘̡Şo ÄtżÇ$łţ%9†<`çĂK!9//»ŕ‹UÂzěÖ_Îd ”ü«8ŃîŁÓ1 üÁx˛úî‡?…\w¶Çs)q {¶ÜÔ”Ż›xk‹¤d:zŁŻ}dBąµÁ…Ňu^©N€éŢęŽđó †sŠ‚5]cÁIđíP€ˇŮI«ďQ·2;@Śv-W´¸ěÔxÎqËÖY/ř:šăkR„6Ř ŔÉeL$6ŹĺMSh:Ů™śŁfřXR0PQ”ş¸¦`pb8¨yű2-IŐĂűO¦ŤĚŢŹ'mŹ˝=0ŘŢ–Ęgo\‡ţř.7Žj¤Śoq»úR;¨µylA‡ÔçôrDněľ$x tĺÜÚT±|0®1•IměL./#‰? ÍdÓÔöb#e”ń\vâP¬Ţh¨M)B…\N^™!řE&HöÓn ›@&{ĂÚ4-Š«˝hqk wéq–D A±#€fRşÎ {۽٠Ôđ+!ŇńşćŇbś§˛7±PmÄm®aR’Ä'“Ą­Ćňoo:ărĂŻ@N|ű CÖI›x†l[LNT"¤wCÜÔĆÇŠ$ë”Ď„\·É;íĎíüż*Ł9.|†HžšUjŞ*Ć&ŻěEQü˘І2îJckÇŞç+ś őĄěáÚôÍ}gÁ…Î~–únů±ĄűÂćQ§Ś7©Äč/ÄuŁ(NüJ­PŻ9)Ą _–óŚ‹G%µĺí…ŻÄsł_' ľ$föž§Nů‡x˛ş2YZ.0…]¤ăČĄ”ć^BQŢ8âťÍ÷/PUŮźţěÉ gŤż± ¸R'Ńmk=ÁI W@ݦ"Š€3ěIvőĹ €wXădÖҤ*PÖéŇ1ÄÓ˝Dí“Ă Ěx¦uľ~×$/đdC±µů¤2óÚjŕZŃqFn6ôF:úâáa9Íţ&ˇyŰíŞja* °›<ĐÎ÷Ľ»©éĘäě¨R—÷ ö9 HüŕQ˘%ŐfqđM€ö?‰|ęähźĹĎćAËđfě¤ö›y̤°%óŁX>ßź†bő­QVž\NŐhq÷ u™¤Ě­ˇt§8ć¶çr>n–đ͢HhÜ(Mnjfͩ٠Ň\ÂJU»`‰µ´÷şsZ`),^aÍşż‹'Iw_Š^_˛?‘zçxµżpüřidˇš`SF ?öč‚|h€÷éŢw¸„=OZ#ÄRa’ôŁŔ…×®§Î4ĆQäßI ŻYC’k< ˛ŻęeŤŮÍ2·Ś uĽŹëd96¸˙N­S˝‰ĐV~G¶&>q™Äś–ŻŽé÷aŕeĺď¸M‹ÝˇŔđě̉ľťŚűśžş3ň{´ŇçxęxÝßŇF ˛¤Î–±,ăEžÜłźŤę¦ˇĆóDSł&oL/Ř˙w>©7·ó $*٧Áé´?ŕ©„óâŚCÓĎ>4É=ÎűW;fq„ÎéF)I(S,¨ËßÁW– d;–É•(h=ůŁçXr¬Đ q8~Ër^$Ě%j˙>Ořt|˝†âŕ-a”fđ*äťZř´SćíÉ#ôAđYmŠÎŢ ŕ÷ědĺ‡NůŢpĐűx)ZF,M]<śxgن,d’i^­‚Ěć(nZČ·źŕ3'â+,ĐöáOąĚżŰ¨űvˉ'ÎIçŹĘ> ^Űc43ڰRtBb5łó”>ţ-al®•¸ŕśŔFĹSüÜŞůŐőń@˙-Îď˝ů%ýUś’z‘ŻČ„˛Î—®ĘŻĘdÚbI\­ SŮźm] l~,×`éľÖg0Şú+~WĐjc•jÄLŧ#¤Ďň/a°†Ś§ďB *ąOĂ6®…ˇ(üłň]đÄÖ¤`™łUpużdÄ0(&“­?Őíµďvű:‘Ć2€›áÖ'µĐ´QÎŰś_sHµČoTö‘ŁÇzÁUąŤâ飡€šĆ÷gS“N <E -s [°K,1>[´’ľµ^)莤S ’9˙ 'nwöŚ?…­óŬӳĘĆDÄ:Ămrç´4=ťi‰$¨µţQe‡0¸?čľĐ® z!µŽÉîŹ|îůf!€k"1ĆvÎÁYÓËĆ؇“ŠB {ĺ" ‰Ĺ]-"Őłéž?n-ŚWÖÉ›¤”çNëźč8?ä6jźĐ q‡p‰clR|îu5üřQ<>/±Î­B:§ÚÇUűăˇ-54íč7ËŢë&đ»ÜM§2ýöł+ŘośÜ©€™—^M;pł‰¬»¬vÖ 2nËAhÎYô§Ě—:V ˛LĄ¦­YĐw ‹xZ8ó?GaFóY’šQĄjť^ťD‚]dŠLź}č–‹!“±úy,ĘÚǮ矧˝ÉqŹ źűBOZżq µĽaîcţëB)'‘ŁÁ¬Ç…ţrxwÜW»»Ş’~–Săcis§e›üŰÂŁ]°µtHhŘíŤYűĘń¶/…0B­Ýn&ÂÓęůc`oĘ+ ś`®Ż¶Î7ĽG˝ˇ‹}m«WUŇp†™PŢŁí zXŻĺćţ®öI«‰«Hˇ0l%j0ÁŰ2źˇIke<1PuđcĹĎ)ĚĹb^ŘßPň"ůŮĚÎ}(őX¸|*ĐŻK˘< čĘgţřŁ'QŚ“ţţ.®ěÓĺ#˝×2ÝŠDbźĆ;č)l¬ń*ŹEßyž…•Ú3`ś¶›aQą…^šÍ.’°ť¶-é<ţeÍ`°\ąíčϵá}ađöuq·xO{ÔĹç8m´!ľxł2„‚’Ď.·>pbÇęJ[uĚÝ>{ h-P"'ÜU*tĺ:«őO!Ż‘öĄŹ'CçOĘHĐnRM*Ubň˝çÓ¤ÇMzÎÜçE^´ÔA¸˘j[e©ÉŁ˘š‘ĽĹ­sË@T]Vjţ‚|ǰ̚OۆŐn%*L?âú´Łöôy'«(ů=Oâ|ý&ý˝BÇÉëÚ|ţÇp_?K?WP×Ďě|žľŔô"1Öś:áŻÇ×Ő¸ŁŘŰç]— ϰ*ÁjČ˙69 î¸ÄrÉX ŤŚÄĐ÷‰ËŐŤj•ę…­îo¨Ű eV_ZY&HěeĎ­ýejĄA žć„’±!mPáQ`Ľç}O xÔ†zŻĹŠy <µ÷Ŕu±úI}顰MqŇÁçëxlË®#ń쮼'ô `D˛Pĺsž‡śi޶ú*T…3 w±GYžqöÂK )«MQĹËěrÍÓÁíČťÎQŐ-ôŹ3˝”Ždi˘Ú(Lč$HłZ’XÚŢRĹë}(ń§Źgv´.ą@q%` ‹F ë{i( ¬ Ű–…or%Ä #=źĘ¨ł,ÎĐĆ+•T®O'äţ+ĚŽů“&kć5ë¨g?)Äż1 ”vXJĹŇľxó ă “9rZĆĘXF^ýJ¦\őp×|d¬.ŔŹ ĽÎ¬«Ć}Úł;E¨±Z$Âbö&ŃcNŤÁNqŔčÔáşďƲůČčK sďľ˙w”rLßôţ‰PcÂÎJ–ĺRމ\D™t]ĆK1‹ĆŞ'Tś‹A”9ÚŁyëŇÚŠQĘ,đ@‡gC/',Fyl¦ŻŃ‘ý*aŢMőaýđŐ†Y©/+ˇT+ä×j%߼{Ї˘ë¸žĽŞůX ŮgŠOę)j‹ÜĚt Őˇ"_Kß: .•ş`ÜŰ‚ô¤s\ëĆ(ař]AဗumůRłiGqË-/Ć^óyÉűěťÔřH»Ôľ' ˙K…ŚŚ9/ş ŐUŃo”ź.‘čzą{$DĘ˙6ew'(č?° ᙵ´?rĎĚ#xt6‚ʆIž@˘Ř.Ą •–zšÖ(_ÜA:RÎëLZ"Y\÷â˛Ý} ˆGÖčv‘Đ5¦""7׼q•9 ”ç܉Npř…Ďź®Ă»»ÁĂF‰_†Ü!Ľ˛.ĘEĆżţC1`ůżóOB‘›Óű?&3~űpi¨jMůŢ–żUÍ™XúŚ(& éäžű=B•lšáÖ{2AçĆ·_EBHgĄ‡żĎGŐŇN±6e!Vät]癹ZqÜKs‰„´Pč¤őŤGř+3ü MKz=(2„Ô‹OĚ7:!mµµšđwľ(¸¸ü·Ń%5ť]Z¬8¶8żA?ŘNX˝u9î1ěP!6 ů#·×Gý2a¸ř­JÍK®˘ZH ŐlF¦‡ë«ăXŁDąŔ(ÄČýňě÷˝:şŻ˘íß>cúµ=O°ôť9QźčµóhÄÎm\Űę›t9<ýŃĘťŃ÷ą$XXĺ‹t”ͱäď*Mµ:Ą‡G̢ęHMy`zLşUóÔ¬W=D+Öś†ř¦Ć Šů¸ş+çá;yčr9ď’mŔ äé]>ů—}Ŕ÷ěR´)/’ymAćoźŤç"Źĺ#ýz3±„šĆZ“:ô>[ĺ-zYđšŕ H3ť&S·KÝ In śwL ÖQ­RÇa뎾b–ßĚââ!Ľ|‡î‚ rňMN[ß®ŕÇ·ÄŚKľŢÖĚŚ÷ą¶7Äż`XµtD¬¤Jí~–4] ő'ŃSQřW­;|Vý±ĘÄŘ!JÁÁŻ-Ś@Î #9ÖqobÔ­áJÚćőşĎ…ŃŮşmůµĚžLŰ" Ě m°q…Ł‹_Y'ˇ‘FnÖ7ďţ>h{‘ńIÓ’ĚőDÜü Bµi0™ŃĄč|a]őI~ÇpŽ-6Z˙ŐđOá˝”±ţjxnń‹dK6]˘_ľ¦mĽż“š™ÝW´?Ă(fdëňŚ™65-0KĐ.ŞNĐ€fm"ŁÎÚ{Ufí/†6ă¤ţ2OÜlÔkű“Sĺŕ}ě˘d,ÜÝŰ7yžX ŽţŃ&6‰Ů"‡-ĹF=\ ˇŻ©˙/-Gđµĺŕjé)Ä*Ëş2Ĺ|J…ťë1{đe\b6Ϋea‰ýż3j{źáŻŤWsb\â%ŕ×o6IpĺŁíÂY ŃFËÓ…H •uްĚ‘$Č…IçÔ4sŹUşhßšJŃë wĄŇ śľ­r_ďÇő8ÓĽŕčł%2UŚimiŽě÷éţäňâTĂW趢Şú”)“~ Őŕz^_8°ŰS?łŤ~±W?‘{·"owŕY’ärWO*6Ë“M9u°8tiĘ•ľ¶űRE~rą™éÜoĂ‚b¸@@ň’ľ1!`Ű!ŽEr€–bďxŚ­˘BĆ€óçc5áÍţ±cčZé¦ —á0ä-˘9ýŠń®BĺŚëČAĺůÂťľŇ„+"×Ô_·ÄĆiÄć+§śMEaćŢ:H«žá&ŕe\Âţłůéúč®Y~Y‹đ©ş‡O”çĂEBĎ/]ŹŐë!ŐÓľr†|RÁP@RrGϡÜňdĘCnŘkĚ’žoŐô+ _ŹźŇ˙8:^č\Ń˙ű›EęČ)ľź|ź“s§Ŕ'yGrĎ˙'§¤qÇÓř mŕły¬‚&siÁkĂÄře@ŐM{‘]Ăщ9~Ůí]t´l}Ç·ălN<ß$˝ŮݤąĺzÄ›Ŕ;Űąᤞ˘Ţ›‹_źw…Oň ŕĺA,lIű(»EXT„G–¤[‡ľ[ýńFvÁ»=V| kÖ ĘFNűE´ŇŃTëß<~®5Ś0áTŻT×f‹ŤR3žű6ł($­Š…\gĘZäŽKúUE\Ó”–E}D]Ě­ŮđRśđ0Vŕ™Ô™ĽµŐv—ľ)ö%322éăâó#¤őĂ0‚±#‚âĘß@s^,żińćxbť•şĘµaw#nÎ8ďd'KFćÓÄč!Ör¤”Ä_ëޙݚjT/á¶ě1hú ™"Ť{íw¶O7ëÓŘÜ ~;ýąě’ŽoÍÁ­L#©»+ă”S¦SRô=kłÔPÄ©,ىAYĄî;ů"T=I5IB qÍňá#E ˨€ Öه^Ű´-ĐŁOĽdGŁs*k,đý)V߲ ×NßołĚ7ŐŠwŃŰśę?ö2†ćoţőí  Čz(ú‚°nŐ?¬Źf­ňŚ˙ ¨{˛x)KۆYŠ]Ż!/.ˇ ~,VcBěĽ{`*čů@0ŹaÔ–¦“Ě˙jc Ć$7¦[—ËńbŤÖąçŰĎĐ‘8đŘ)ÚC%©ŹĘ‡âŇ ‚€za„_Ą,ş–h/÷ť}ŕď ¨S– ĂźPY;ˇ#´qČs_w/8Jr€-Uţ7>™Ä>‚ŞçhÄ`všFŤ+Óجđ4<—٬ąÔiäŢ© YGDŔGG()öźÖ“Oyhhąň{áĎci 3Ŕ k/玕{MÚ¶qd<J§˙~}ßCú0ŻŚ…®›ŇÔşěCË^)ĽKĎÄä«—ź|GÇżŚ G—<¨LNĺ†{ůź‰pa~_¨Ż‘čŹz®Ęă#Ű›¸¸Pnř š»oź’ś?—á aŚ>wRËMŇq +0ĆĹCűĽÝ5U ť”v&ŽÇxĺŢġ]§ăěI ¬ĐžJ}“58Ţů25Ł‘J»…]8„ĽW˙5ćp—Ż T®čżT ±ŤnGôoĆ©Qó|󶤾^üV]mą˙Cá·ČKŹ«†1đú˝¤˘Ń8"ņR ă™ŰĂ_AĽeD=ᙦO–ڬ޷%Ýę€üĂą˙R»ëŁ…G+ÉCťúý÷—&ĆĹ4PĘŘ*Úg¸Ą*Só•ÁWÔ(ap( ôK˙ |çŠ}/{ąs\—Ř`nâ+Ě čŔ­ @T â”ňz—mgy=+XäPa“ÜrŚPÂ×^MąÜ#=Qâů;5łnlaG Ä~ś`t#“‰0ܰǍ6݆GíŽ0Ôůˇůwň\DřE~¨¬cé/™>Ĺ"fŞ[ŕ3—çÝZóYĚ5ęćFî»ŇŐňciE»ÎF eŁÉrÝĂÉm¤jb`éÍâL6ÝFÍYţͨăI6‡bů«ŐTs¤I®Á=±>đwJŇŢ+8jÍ„"ŇÝ:8­5Đňřó Şö„' Šmݢz–O_lĽxî{ť…č%WpŤĚÜIO'ň#‚2śĘ±Ý‘aPVťŇ3“ËÁ—\Ě7e¶še©:„{^É+z(Őő3B…I_÷ፂaçGěćN1} ¦–<Ŕ1° MŁcX@ě´Yv§ŢzŇ…ń;|ß|ë%‘“µ@Ţ0b°Q®ą±¤#۰âeş:ţşč2 úŞkýÓß–ź…\íŤ3«<´Üü¬–ům öţJř˝Ç{&$>SŘÎĐkaěŔ‘Żi Źlyű=§ë˘ä Ů˝ĽĚbMhš™«ŃM¨2÷߯ׄ(ďş×Č"S a†5ô«Ęj(ä­iŃb@z#çJYĽéĆ §Šq>Ě"C¦+™Éđ$A“{ě®âáâVĹ3 ńz·Pť™6ȶɏĺąńé4t|idÍM@‰Ě'đP`%ÉńÁĐlťMĽÚéLú*˘ĎŐYXŚb ńôV5ÝK EmŠ8ůĄHŢ—FŤxńDŤÚ_"pĆ×^Ş˛·Ç_Wş“Ş3žxĐNÖvIdŹľĽĆr×vŃ śĐŹńŹJ¦Çý@Ő*P)ç„×0#ÄĸRq­)ŽEjgc,udîÍQŐ·QĂü›Ç¶éúÄPËřq:\ÜĹöŁ T)VĐüŽtpÝ˙Nb-…öFí9R 6•­Âé´Ěq(ŻđAĎé3XŒĨ·(ş—|8s¸­Ă†^ň`2*ş—đ·ŕc‰z¦Ľo©´ Ź­_,˙?>-/hďË ´© šŔh Ň–ŤnńÉaĄ®…ě|Đĺ>ń`ßä T~ťůjc©&ÔŮ–^C‹µ.ż?(6Ć –Čâîr7*ť˙=’Ň—‚®€oL°˝ĘâJeł&cť­?qR*‚{öYcJŔÄ©€fš·;Ăţ—ů„T=őĐ‘ďfçµ$ ۸ °x2^0™‘Xűˇ9¶ýţŕťŰ^Řî>bΨh7÷¸©©JőŢŞ?űnÓÜ“‹ž?XQ†lE¤îč•ÖĽÇ˙ěÁ×q-·‹=ÝQ#†[_)mŤ¤­ÜyČČFő( Je}ŹŔ®pŻąßzQ1<:9˛Ĺ¸˘xqvO*gę˛)´ŚQ¦´*đşč°Ö¦ŹcS6L !ÎçD°G_”0ę*]QáÖŻË^Pěőň…´XĚ•öOŃ0 °n3]üÓěnÔ®2č)ť)>±é( aý_Éăn-|* s=˝#oŘĽš….¤‹Kd7Ş^X|ŚhĄöZŽž>Č/=.Ř0G~7â Ěo.µ¤(ÖXj#ĺd5śMD¦¸8Ą ŕx«·­#Çł“w¦ĽËgŔpäŇpG©,>3kÔ§rŃři+Őł]Z׏čĂŽ†őŇ)]ŹÂk"Ní|%ŚÓčě‚Îş÷ŘŠŚf¬bjLĹ#3f$+ęśă.Ą-">ä¨z®ÉYˇß%UľÁJć”Űo@€±Q0P 9®öőZ™omň—vŰ L_w¨4ŁE±xá2ŰL׍’\bFŰ‚ČW«ĂkkΰžíŤt~Ż\ @)0ďU}ńt?P§ű\äS—ĹwŮ›7ĐÄÁŘíŤčäÚćĆ9G´Ş‰‘ÝŘ84Ä.Ž–féőËg¶}†úüâ Zöł•ö âk—źîó´0éKiE,zč]í©Ŕ9??Ę+h)8Ţąä—'—ôńw%Ň ßúM (2S.Ä´#ĎgůĺĚÝÂGꞍćÄ&ř&§h ÷‚ęEqž,DymD•C¨BłČЖΞɴ_çţ+źÉ%Gć€v™ÍO_š5`gČĽGáń ¨Ĺ/•vÚ¨›JR~ŠUŃI߲a<€%ŽÔ¤¬iŐ?0ôŇ]2ŠpOę­Ä*Q.Ü.8#"`9[­]˙Ë´n$ş™·8Ľ÷Rą9‚ó OÉwß8± ŔKň-ŢÝJ`\XtŢ{¶ÄÔH&¤m”7ił Ţ;OyyDlgQfźWŤ¸˙P. î^łŇŽŐ¨ľő€KŁéo.EĚÚ[ „5·đp ř!®íô-©3*X]͢855îo‹ëd>ُý Ú{Ő†‘^!Ż´F iaČ™&ĺçéo“'Űhé_p$‡# ŕ|ř]Ăk]ńé b"Nň8G÷‹,jě“OĽź¸ńމŮî~ĺş"¶DŔĐy„ÜY=ÄL,QŚc6m)¸rîĆRÔnţź„C0"ßĺ÷ř–ć̆<ßaë"r“aś"Ľ$¤Ün›©o&;7pÔ u͵ĎLH=Öt*[» H%IľHÝ´é!)Ău¸˙^ÓĐpýëIIn ťżO!Í_”˛FVí ^Ş®ćµDXŚÉýä%É{îJBŠh9m`Á—Îf“5Á¤qµuôąQľg본UŤ<¤ŹÉM-r€}Š?ϬTłł•–Ń sż—ßoq•‰ň‚YĘŃ›˘†đš¤ÄËâ‡IĂŰT˘Ń§ «ômf2líÁ9)´‡Î2±zV8ĎTz‹şTfĄpígŰ÷š·áĐ׆ޅ#tď2iÖAÜ/,ŐşpQú±'Úš‘A¬#ë®·ŤšçZ;ßě9mY{­Ţt#?ŕŞ÷#ě—¶«±˛Ó0M‡dĆh­ĹŘŢ˙_G ÁžÖ Ş· z~ďÁjwůÓ‡Ý"3ÄÉ”¶ňÖE`úŢ/6żůÄŇéźű+ĄŚ(,mśI/"Đ{ĹÉŻfśá`¶< Ú;őXÇ[=µQ¬‡WŠÁiy–â´#Jîśzg¤ýĚÁů•÷˙† N®Ahi˛pbŽ?9;ÁŠ÷˘tLw(‹Ň íŃŮw`Vr±KŕőD‘SŽ3§ýĄâ#JtI©AĹW'$@ţ 8‰&—–1NŮŮ“Ţ+qvŢó…VíŔjŇx <őq^ÇZôöŁf¨ŁY¦[ WčsO†ŹV~•¨ľÂ2¦–ý9ŰVĆužůÓi盌.’5ˇ›Üú«86iu-41łLhŔWť<›÷ÔŇş>ŘNÂm4’Ueŕ:+€1Üz›Ďâúµöőű'މóű#Ĺőjwíěö|ţĂçĎď— óô·öőů>_SçöÚó€¸BCN!^`±níP›Ä«LsqňjÜĆ™ńř%ŽĂ¤QŇ·É©Üb¶w‚$őRWţáp·×Éx–Zě|ůŁŻpx­¸đ–K—6|Z[|RfµôÚ¤.CH ‰Ëiňţ!řNďÍÁ{ÁÚ]*jh±gîĹ˙U“ŞśĆrN ™<Čjˇ×—ů¨ ˝9$cŘ^¦śjyťěS»ŹîśÝÁiť”ÓĂĂ4MÇ^#SĆŕ-RŢ©řĺlµĂCTk[ő‹HR¨ëĄM×m |Ů ŁE™utĄó°RŁŕ)ŁĂW‘;NvKB<É㕞ŰćŤbáä?ЧÎJŘ3‚Ť©#(Äű„i`Ňč P5đ±ssĆďWó¶ j(@Źú:C”Q]ŰđÄ’ŁEżő;¸wgÉ‚Mëě&e>Ô=+íĺäśö<®,Ë]ŞÜ3`x[EעHfGę¦2^;x3°Ń¶8 Ź÷‰5VŁq5yóäjl؆ xGźv€ř™Şń!·˙ZDÇş~"`ë´TCôú ى§O’<Ě}–†;,ŕM®ťę7«ö4!0ż÷X5 čN 5ž® ásŁ,†X×ŕ*Zy"DçÔ@Č0ş⪬~‹7·Ś}͵N·…EXßÍ)Ԝ溍šžEcߥŮĆë„îrk«P!˘LuąăŚžöŕŐĆńťřQ™C€}>ŕ®ýÂZłM˝éę»{ě‰>Ä5} ĘĘ0˛¦č–ű]n» Ó—ĎB Vc9Ť‚®]«`@"ŢZ—/ŇEçŠ/bup PéĹÖÇé—Ŕ0jŔY0Ěr[űs ˙ ­ˇ 8´‰ĂÎFů 0Çk.uV#V5TŞĚs i]¸ž0&¨˛–e¤°\Áî©u6UNŚlT–÷G? KAĐMđźô|ȸI‘;ŁobŹ2ׇ%8I˛ßHĹ«‚ôÍOBŹf×˝±ÉQ6Šó¨šcd čs{ ÍwÂ9ńĹE# ˝U2ZŃv:Ó°'ćĂUP3z¨»qf!¤vL˝•Ö]±E[w„Zvx}ĐWÇë™çç;#6Żzč&\˛7(7âg,HźÍîÖz(ŹĚŹ;µO y±â»&¬TY×Ű3_ÜÚŔxÖ ˇ­ŞëĘáqÇGßčg"›„áCđţiô€5—ä>TZ`˙Z!‚!5hyô ©Ä“gďRöÁ‹BB=<|éś‘ćA€up%0Ń‚~ÂúsColă‘?Ş}ŤÇ;ˇŤ7->îhZXJ”üO'Łź_)ó ÓG+`kBąŇ" ;WČúĂ|odťSmz‘äŐýÜ…¨ Ű˝;%N“wß·—¸ZÚRŕ§¶,Jm˛ťßqH3qŃ…Ž`mgŃ‚¬Ěî¶%0'Ií—ÇÉßN Ż^ đh~Éé{1ąVź!ł¤`X»QĄ)ŕ*vĐ*÷C•ą‡’${uÇ@vm>Đń ˢµ/˝”/ĄIQ®í\)k™Ő~Sü®¸gÂ,,ŃkW¬˝˛Ě®z×r?({‰!Íd…Ó`eD‰…ýu=ô”ĆK­Ëdµ­H=ň§^  ÇěekĐâ˘Ô™uX^“qTŕ óR«±e¬C”¸¨€Lđjş—~?hQŞčzGW0Ö°'‚¤Z4´í6łS’ŹĐ›e=oŐ‚®Lyc®ŕ[ĄôvąK†Ďkȇ3·ďČŽąŮÍ ęu?ó›däKřđ0j‘ÍP¸x¬!N­HŔ-ęz"°ęnŻŮĆi‡EOĺ „b÷Ö“·˛×(IcĆÝĎ©ëä®&¸î^?üĂzŞ6űřŢwBC{kÇW‡J>䢚xéXnÚŚ*§Ĺäżey˝XŁ„[5 p…,±ëC7¬„¶ŤÖ2_ýls.m ąg:µnhî{ě}ŞäđUĄ»ŁËÄ$R$âű &=J[·cT¦#˛ł©š:°q$QŤs÷ `bz—)Ü‚Á†9ߚٱcrý„xś°]r&sóÍe’(˘™uÖ ž!­™Šiáä6÷’_C÷˛P·š?ĺő=ĽM&ö×˝šňť4ötĚ,’Oţ™ˇ Ęą _˛O± Ń:'Ňé»Ő$łĹß«U˝±CßM×[ Y‚š<TŚö‡hŘ®o)0TÉé^FmŔpÜ/LCHDË=+ 0É™9 —{ÁŔŤĄ#ŔáÝŞaoř7µ›ęâ<@ŁK&Čąôm:xů˘,ž)3ĺĽ4dň^:ĺ'éŐ#WÉ+ÜIq»rĄ–z|ŐHĺ–¤‘›3§™üžm/şF ‰hI(j4 i×{˛Š©šăĆwŤĚ˛ŻxpxúyfĎÁče†´âäŽĐ¨g„Ĺłˇ™ŠĆ†ÁVuBß›§0í«¦˛ćŞ˛ŞÄ8Ś‘Ű}|¬‡_ĎAA‚r”¶™ŘUľCŽ?!Ŕň÷%ŰÂtq™ü˘NěŃmËףJVß7C˘ßtĆŞňz…µľăŢÖY¨4«ÖűZw eö6{Ű’ď¦+®Ë¨Ň8Š.U2~ô¶őň’dVl˙7T«_>u„Ýăî(őR#sk· MĂ’$fŇ#áüÝÎí-Ł~PÔüűö ŔÉž…ÄOˇ\HH,.ť¸u饱µ&hkM$#TND›Ş¸ü Ě*Şžč‹«á~Ažľ7ż‡1‡,WŤçŮčˇÚ čŐ±RL˘¸< ń°G@·aŹd¤°HDUżNś†í z‘(…ů¨Ň 3ęv}"±*ÎüA0†Ä¸;l<1|Śjü#€ßˇ–6&b_+çĐF1¦räaÝ3gc6/Şô¬‰~řMÔ'Űe,řśEf¶±ľż 7QT‰Ę-maüß°će,ő6±Cm"~>ĘďŇ(P;Ú“ń.(Žüž˝Čşý¬=pę[lŚĽ"ŽrÔdůjnőÔÁ}t ’IÚîrŻýŚ·„ĽúčׄłÔȧF"ŚŇťi—˝HeÍÎču °ŻzIłîéŹÔŠÖn‘l±{MJ«ĄÓ7PĚŃQżĺ{ţÓŰĽ”Ó„‚]BWŤ ő$Gn_,.ţÔB˝˛9˛Zg'ľç]‚wAääń@ô¶ ˙d‘ĹH¬s-g:ňZ7¶ 2—Ť94YŐŠ]ż†żSăÝYaüŞy_ë˝tóőťż=ňđ‰Ő 3Äʢ•©Hh€ŇŠJyRŇ1X-‡ĆRw.2  yăŃťŠ ¦JŰđy˙yĂZC”˝ĺO¨‚G¶˙ÔM%}Ňđéü[ʬBͧ% ý;ŁżěB'öHÁG‚±ŕŻśŔ±Ę™ůEűŞIhöiÁżFÁü±sEęÔ¨µA"dyěŤéí]ß ÎˇűšüĘ‚š"zE= )¨> ¤çĄúF*a™<ťŞz˘šgjoëňÂ&› ş§}§ÔëŻg×^¶{ź‚lˇđźIŽŹ¤ab‘őťŹ-Řż=”ÁëjtŐ1O"Ř â˛i·ą±ßŘá˘Ę‡1¨«9WŠŢ‘-<Ş5YľW #źU¸ÂfđźQ`–őŹ?a ®>ęI š˝m&F}”‰čFwĚ'7¨]áő=Mř…¸.ç+łg.Ł:˙ĺóy”¦5éf´g˛“vîŃTŇĽ)Ĺ‚€fCٲͨI*ľK¶tX’ŻdÇęˇ1N]q7ČžĐ<5 ×ţÄWŕ´:«TφP¶Ŕ)ł÷Ý^ÔB ŢĄŢc!\ď8bű!GŠväýäŕŞjŠÁŘ;SŁš•ďRŃČgÁmHK=%·w›łA–¦ś.NĘ=×DGďlHčUż —X%Ţ.ęVHiÁĎŮń/Ž'„±š˘/•Ý긮ęZaYó‰kd©6hR!˛M›E8Už¶aa«¶ˇ~łbΛő®e’;űóč8_ü•:í˝`ć Ď$Eé>ç­†˘!™(Ż’ďŤ;ň°"Lůcެ†¶m +ť˙+nânľBDz ZW‹ 0r&2™]ľ ˘WbRŰý(î¦űipp Łűź‘MQKPL}=ŘC;¦ Ür·ŘcĘäiŹźšë&äÄa“@bçÎ,ťŹŃ+¶śŻN°–Éżü<%Lš>üď,TÓň9bĘ€yŐĐśý—Ň—O1 ä.ŘR çBÁµuÓ÷[Ű€îM;`ĺă&üĆ`"Í|˝Kg·?ÖŚ°˛’ďŹ'uŔE m|śľ˝7ĎŢăZ,Ż ÂZ'(ĹZgA—MÄş6O„Hń‘ćE~Ľ-CEţJ¨áT… 7]E©b­_+ŮŁg@µ/Ş‘uş3óĽ«J¶řXo—÷ómă#üĘö¬vLđď>Ůä;:cď‚Z;O܉—S]aČßÂÝcDzU«Ăoč>t"ë-ĐgŃ'÷h·’3ë†Ű8Q¨Î+2l¶µëąSckÍÎë=š7ÉůčÖË|%Gu"KÖG§Ĺk×.úŢqęĹŹP  ôJsľzr&źŕ‹7”k‰>4–‘ÖóítôÉňŞü»ü:&ŘWµůÚź˙F|*ýgü„ŕe8Ž‚^{=ÂUő‰Ânε6¬ŘkšTJSýe;Ü#af˘h|=ý¨Zd†>Nj©ÓnŐ0c]®·QĎ_H ŕ%®{%ń7(ş HëěUTPq—2ÁR"ϵ ]ó ‚lťC_z/ ©úá|™Ô@h*đ釾ybj+ś8:T°¸lďä%`WXęëčę.ŚCsx(á I Ůa}Łuv3΂Ëă…ß©@‡‰…©Ö´‡Űr.j'™; ţľRĆG' Áb<‡x/Áw«,l˛˘^Ű+ lŘáĺô€"·˙MMůĺwv – p§­9îŃÚŹůw?ó ń'A-‘ůŚŻb&g§¸éuŞ·Ś¬Ą§Pe¦đvę`ÄĚËđrÝë{=¶Á=¤±KPÚç`ś,¦é9zóďł“˛pŁôxç¸rGP6Mo¤˝^Ł…»ç=쯹DĘ2€x~«Vr flb:ůgw­0Ź·QůÔ»^G tčŽEôHq ·OAQ»®TčĂh …î¤ĚYu7‡ä¨.#/ß^Ő›@ĽŞËź#(Łĺ|«…UĚ‹4î­6µéN żĘµíHÝQÂ:\UDŕMV1‡ĺ$Ëd{‰4żđ÷×TÇx­í€JÜŕČv+a.±ĺ´.ë/ďąôΨ‘>{9[h~(Óvax;8ąWÂ0uď6ú«ČÁS$ZřŽ˘ű‰2cx·s(óâvwłUŘąĺSYŹ ö5 &X×űů}5~űŰi–_l'k>˵fĆH…6!Ř‘^îľŇwJęCßpâŕśç‘č}ú1ó¶ú™Vp[OÚ<o“^DŮ9˙( —Ď7„ă{¶ęĎŘÜŮ”u]~ Ŕ/LHŠI4rwů.hŽÁď{ٍ3*2°+ń-&/Ú}h٬ Ą$łěÄ«ýką]kÎ[¶qĽťN˘Č[m5%/Q›Ś˘KëÉΞîDé=”D™ŢAw‰8‹x·×3H塡‹Jţ¸Mż ń 8H@ňĺd˛lü%ëÉ 3˙ěâW¬Áűц¶!ëîŰ’-ú°xĹ“>×1^5µ0„Ó¦Ą:$ú&S‹Ç_ şö«ÇÖĆWC>ărϡ÷ľÄĄńÄ÷TWuNđ»äďűS^iźÇŐ†ż‰…4Ť)ô(Ęß…ˇ8®VţĄż‰¬ÝďćńőcŢ ­ú0"…ť‘Ś"–­• ĂI˙%6pť±ó dÔµx±ÝĆÝ{Žč’(â/ŕ`TĐ ĺű®”Č—3łc&µD0ĺ#ÓV¨xÄĚŇČIląţX$–OşýĐ-‹ˇ"ůö€ŢgŞ6ř‘ql"`,© ŐÔ‡^âŔ,K• ÷|.Ć„ăůq Ć.'IbńýФz+Čćë‡ÂÖPúŰŞUxv¤Ů9¸fěŁtţ5’%Đţ0"×€dçŻ'+^ę·–želÔ$ÇȰ%‰­GIľŕ]ńďj'Oş/ĹÚ'çľ;Ç*ďJR¶×Ĺ—”t<(ĘĚĚ]łĘž—÷{‰Łt¶—»ÎŤ*—,¸˙h59Ş=TF¬đAXmâx™ µ@gÔµiN^®‘»µÎŐ9"ÓÖŹĎG…¦TÖć˘`m°P™,ÉË”Îţď´Yáę?ú‘[)Š—B{]§]ű­ř§ł&Ič&iŻžŃČ52ąK?č,Ňü¤Ć~‘’Sű)<—íc¬Z/Śn ,óO˛˙hŁ´†ÝńM3ĄÎé%ĘĽš-uv3÷ŠG¸5Ľ¶]ŃČźż™=‡P†Ä̢˝×ŮýĄ>ô‡Ůą›7ÉŢĹ .›yůJ¦-ĂC ŕĚ1ďt,źŤ˙>´N*ĹW:!…â™ë#wŻËxNŘ«nů7šĎźáóďđĎjy°ČZ›ýsƵU FA»žŃú§±înA8ĄÎzNJř Ň‚Ąk)PĄńŮOĂ\ń€©@ó´ěŢűKžżęŘGMť?2N…PÓw®äH¶á`Ä„ÓAĽŞ•ć¸Ď­r‘Xr׉‚§“ •¤» —lä6žRŕ"§gŃĎ»BSŇíllěząÉ¨ŕh"§”łĽRlľţ­WO«I •>Kz8cË—ŔÇ–ż ^gî -Uç8}Ós8=…ŕ– ťě&˸ôł!‡{Čâ,:ÎŹCjč5ÉWĺŞúŢĎć"’w‰\ÇnFiM§Ľ–&ŁŢµ_–P5Žú“dĚčg!)íšĎŻHľ+­©jÄ8z]¸ŢÜRIlm)ůçCřFČLÉĺͲ şăyW2ŠX]¬¬“óŮ[•YĆ6źß<Č(wý˘„°R>0ń $:ŕÜ?뛑Šž5;˙a·îĎňöáč÷÷Sď+Ř%Ý0V61ÖdÖŕf˛ŐĹAŐáÁÚžˇV®ú«J†Üa6ËTfC--—…\IUE<ĚŰŰ;×a–Ž+\A3ˇ-Ɖ y+‚ěľźl$•5E}¤_bĚ8Ü ë)Dśł^`W-ć]6(R Ě)ĹѸ3j¦źăďXCţdüůEI Č9eß[vá' ëäBG Ćâ+ž: ÚŇe‡< Qbc§óüß}{tM{PŇ}–UvÔj56dĂiĹý˝€C»ů‰¶XÄžˇüßHY5ĺo[‘Ž‹ J˙SřŁ>D.Ů€r’ěűN%Ó˝ŽË3wŘwU†˝¸~٧?†ľÍ4y%Lß:|̾޸Ö^-`ú?O \­y1źŐĄőÁk‚,ŻRMńLA§J˙çď|ýď?ĂH†gď}ýě˙a©١Xýę˙^ü4/ř[Ŕć¤1L:Mę ü8b“šPŁÉRC–U×SG3ăA˙ë);˛Gz–¨łXha˙`±”ŘĘk‘ ˙m>Éś;&(ş*žP¶\_đářťć;YÓláĎlŁü““,ó×GŻ&˘rőQÖŐŮĘÖ(KţK2WĂWOçÚPŽ^Ą˙^ţĺj˝|Ž­ÁBCěŕy!FDI– ˘čăä?ü4 f“Y†oa±#r-ŞĎ&!JëküU1´.ŽÜzç4omyyyyyyyyqůY4Ź”ůRn¦G————————‡"8Ĺë´eĺĺĺĺĺĺĺĺżě7an;3-Ƕl”üšŐĘCOÔĂ`oîăr·Ş±Qyß}“ú*\¦!YČ‘ ŞÔ?ÄMb Ö`é˘Ů÷ž>›â‚Đ —îăuĂ|¤[ó|šëČ”ŃĹ+qvW!©Fí|'¦ą@Ă[šyá¬íĽ)ě?»ĽG Âů(%+ůÓšbŞzËäđ0ťśŚČ—áP—ęɢOę“ÓX6,&µđß ˝AŻ»ł.ߨ:ě°ózŻzcP2ÄĹ{,Üd(˙1O‡ţŤ‘¸Ťźw';cdoy$żŻ– ٰXkÜ ŁX‡čL!Ü®ú¦ć óƬŞvÁÔOŚ-pĎQVŁęĺ'¤dLř7™“AĚĎ­lŕańznŽéÇ Ű…äє蝛nďćXŢXy Ź@€‘śiW/ÂŽż|5n´g˛Rą~ąµ˝[1%µŁř·w–!‚”Ô O˛3´ý裹uwał>Ädĺ|]ŤŮ‹—~ęücydY@jXyai„q»›ĂŐkú,Í+‚ |2Oéşůľo•ł3 Č© ^PĆnđô(±™ń0µđ„„CË.W‚=1]¨€?´LQwďÍó|ó1{ążj~U›_$¸Đ‹g«;±‰ý>\4É SĹ\·í‘wĚAĘF´+8,äŔrg´żţiŰÄÉ—äáś,ČfÖżÝ ďyXSŃĺĺuuÓ ű'¸4u^~_SÖbßT0ĂůZ\Ěí‘kĘ—ö09pęŐLt»ÝóČüH;a7B1훸k(IO9wr[żÜe­źD‡N[™#˝ĘÚ&GöZ(ś…IŰMAšYŘŠşä¤ě7]8žĹÔ¸g=ĹcůAŇĆȨ]$4«‹Ňűú°E6ËŽYÎ.}vĽ<z_Ç©®ÇćĘjŻKÓŹ˙xČÉ{Ł/ĺŕÓm5ŰłP˙vúĹÎyĹđ´hĹ2G çí6…žQ wߢ(Hڱ–["]jż¤ŞK•«`Ł#hÜ% «¬„˙pÂŮ<żPŕt9j˛^ţ°·đsloÜĹŕłěFl^ĺ‚[ĬּGÜ‚„ë?P,Z,ůŚó& §$E}M¤Hkôúv^•cź2zÁ 48ď F©7#H„i ŮďÎTö_›Mˢ{6O`9»9 ţäŻă÷©T·ŹßŘ©®ŕµcÖšD=‹ęj¸ăÜ<ňWâ\Ŕ$pbśáŽ6i DMŔ%—ęyˇ•ńo|7oĎçď›ßů•Ť~nrĚ&ě=?eŻšG” §Ń·óËT˛PE˛/űv)3r~ŞĄăö„¨םŕeŘŠôŔ0ÄqPÎźâś3 ě„h®ł~dHď»÷UÎ='ů_[§ey\‰Ň3®k'­úÍAaŹ%ś˛Y%ÄüÁ^Á86î.nĎ\ŻźlÚ˝%żC%" “Ac7R¬6Y4>ϵô˛Ü?îYoNĺ-›¬Ô'ëYÄú^äŞűŔ«ď›PÂH×ÚEô—ş É3eCăÇă+[ˇGŚÝŕ"PÇ:8Ľ=0–x¤ľzI‰* >ëQÔĎĽý=nĽróÇU~öĚWHĚ MQÁ“±ŇĄćáĚIM‹0Žľř´ŕg)™ťŃ¬i 3D•¶#$Ő•˘¸\möŻN?Á™/y č’ĺη_‰Ł»řÜş,EÔ2’@©(¤˙:?ĺÁvD$[ů»§AŽ IŻ3p-K«vÂEM€I'·LÓ ň±‹Ú“é›_Ö•Ć=3o‡F™ů°páŃ"ýč VíŽëaIź˙Fţndí (ź g3LĐž<ľR)%ËąÉu8*Î"ńˇőąßÚ¤FË|(ó˝JŰń] Rbp 7Óöôs-“sČT}ý y’3-śˇĘwéq÷úmçš®Ę\4“<±Ů@«›ŁV^SOI]ďŘŞ‡ŹŐ±tĘH–ж8§Ů%Ž_=ęťQYr÷fý8^ç¨1ŚČěŨ¬öű\Gę.ż¸•Á‰„W%Pó.ó.ˇ6˙x•óŹä‰?7¨&Á?äX_ěŞÇzžF”k/ÓěoR€)ôkZ}µ‚łC«?/˘°^o•:”BîÉů…"ŕ]Ć”o«n]žęz|ŻŐAţĂÚř.:#bÔbsX)ĆRĺhe1±µŐ–髌F,˛×˝–®˝?­ÍD śó— ÷~âokb–EĄúŤ Ä®SźŃř>†č„Ű˝ˇşîş)äµ…éŘ?éÍfś\µÓŹ7áO ňém°XfÝíf|Ö™ž ŚgcËý |ëdOüÓPŔRçM =Ý2řKLđ<^ÓN6QSk‘­ŕj«‚YAßó}©Ă};íéúűzlľÖáę[ü=Ż/·Ł?řvS}ľ˘[öúţßFKíë}]TÇÉéGöő«ĎďGţ9wŰÜ/đë2űP‡¦Dú˝¤çŐŇü:đľßR.ű}zo·ŃÂűzîľŢç˙Cş«ííëŹď8ţKĎ«Ą?áĐ„úŚŻ·Đľ}^ŻóöoţO«ŃóźW˘wđîSřuí>®¶Łçő/}˝t€ô…Đ:§‚3梫Ťď}3vĽÜ6.mamżh›Ď¤{Đ&J%ŚNu(ŞÉ[¶adyĺnŕ­DnY65&’ ?qçę!6Jă4W—é»¶‹\ďAK|P®U·¸‹ńxîN“Î,í}•˙ W/ä"říĄÉ(/nRVsć¨dDv)“/RÁóT–Áńpąd#¬J'NŻĺ=?6ů©wÇ÷ëAđWŤUq“€t_ŰV‹‘v O#ąŚD>>đžoy©íÄ}§ł ăó ţ~¬ž3îK* Pl­U° ĺą1­şËç9QxUëÚŻĽäÓ ój—Ôí›1{”ÔÁ•Ĺ)ŽŚč€AhžHëD,IC‹$ËľtĆŮ}¶1÷DcŚ( !·B<˝şPť&ňĆšgÍZąWbůŞ4,˛ÄŐŰAŰţ89[†±*ąĘ]€{{rfś3p‘çS ëŢ”• Üß“Sz)1„mä ćv Î]379 °ʵEÁč ´µŽ7…-đ2Îţ®_'V÷t©,Ú˘ú"]®2ÄŤďJIn ~.^Ú ÷GŻ+˘PzźŠąTŽc˘~Ŕiđ/šÜEhől3AŔŁH*©a_©Ź*H·ä:!QÓ`22Iíą»Í#‘ŰýŚ–ŹPŹ-@ž?YMĐô ™|YʇGéfś’Ź 4 Ę/ţfżl[·G&á伞e®?Č3ňĎ€e§Q/u´µ“yŔ=I$6-»QöŹPŮçůF N$Öüč3Ţ÷ń"ŘnőmÎwÚ…âëřÝą÷ć˘HÜ‹1Hgsc1O¶ŤuYÇő=ořľˇÁMąWŠOů4ĘáRP+PPŚ´ĽaްH(­îü"wÝ/Ľ— ™(ŕjř˙e,ŕ+vˇ=_ë„¶˙BpĄ=yĽfKŃ<¦ˇö€•T#Ä ü3 Âř1ĎRA÷l¶Ő`W ˛íósÜÓ?*‘úy'¨7Üđ_ćRÄüßŔć.«]])G!ĹgŁÝyź•žö›í„3Lĺ%Ď'ÇŘ+ŮđůN–GŤnç÷QŘ€+]RqâřÇnWqŹ/ł¤C®G.măXfł`™ĎmĂşd{tĽíŔ˙#Wp—+CÂ?âG„_«%ËůUý-VöĚ;‘AUŕ2 ­{;˛6+÷‚1ÇűAĘŘôÚ =)]†˙oRmĄ›żäUÓĽ]ť†ÚV"öx>˛O4]jÝd´…îiĺăŐ9­]˝ńÇ}>¬Ď8µß®óŽ„ ©Ă#vC`<ŞHPöF™ŮĆÉâ¨ęX…"*Ż|k mßÂxŽáxČÖ7ŇÔ|}ţžÔ}…é’(Ú—äxůM)1G\⟪ Ď[šüˡs鼡ҔRĆÖJ©Đ{­lS˝‹PüŔß&Šyň|3Wd´,2?Ą[’­ŇJĄŃÄ ,*ÍĚŠ¦7§ä§¦h~f»‚ÉîD˘ř|T‹H'ޞ0Ş…‰l˝ÝA›×_" 'ťÎkÜşüÜś:ĄaŚ.¬Ôń:&ípĎ/Î`HíŞŽ7aĽŚ Ą©vŮűúIŤäܨ÷[ÚL'áâ#Wxcš"sj´°˘óţgęŤ'úGa˘ë˙zâţbÂÓŇËS…ąI3._jZ7˝;6ëćůľrc)RÂę!hŢŽ2ŚÂyL>č2ú´ 7//i…Ş–ŰßFý:‡w[n2ĹHŔ˝‚TVé ąí!üˇQ°ßrĘß‘l˘@đp‘¶gbľ]y"{{bŘŕۢťmq)Äđâ\ÉKµ 3,X“ÔĎ'ë!xK“S°ěNGىb•ăr­’Ľ`CRą<»śuźäe#;ĺüĂ%€dAkŰ™˛(>×DĐP‚"`«ŻËć—'×ŃëĂ:X¨=onI¤‹Sšú%~2㌛DÖ+ËŠ!‘C ň0·˝Ád^ tpIBŃ”Ą?jY hٲÂ˙t˘ôě:†Ű<ŁÇPߦ=ô%Ţ=J·ö ‡T釪e'kˇ­©!Çš¦;ŞFsľ¸{B©˛y%O^¨»‹1_ćcŻoh ukGí¬_ ąa1oĆQěFoaGŰqIyOdIeŚ'qCOŔä˛gVOŐiáw)ĚşB&üŃš€­#ܧ«ş™Ówé˘Řé÷×óěyPA#ŐFWÄ—?}3ş°¤® ÝFŐ—ű-ó^Uő'…RLççÉŘÇŐиj`ĐÚ[Ý«&=Â7'Zď›äĺ+/Í 4§Aőwş/‰c6Äĺäý{6@K9iWŘ›IŽ•ĘΤKabŘ…mRDÄW^*6ň ęď6H[/Cg#Ż+ďäáńîClÜëÇwä9MYZ±–_ż’¬^4¬EZźŔ但ÎÇ{ Śsaâ…NŘ*Ŕyöţ_íw†+YMt)ë{Č(xбaZ=Lę6ôđ3Ľ’ś]|ŤÝ˙P˘>}·¤§oCˇâđ{ÎiłĚ»y׫誓ň« –í ^NF’‚µ®őŽx "•ʲĆK)$ VŢ»‡ŕoy˝®ă|€ +ľµĘ YMλ¦ôIóËÝ}źo#Q„ 'ż3pz+:pžü¸|™ÎYźÎŃ:˘čAôµ‰Ł«iÂa˙Z‹×ÝhĹĄěiß ´ ˙kí•#4·>ˇ2ŤÔ‰*ÂQŽÖ[~:XógÁĆáźG»É7ń•ŻÖb`ŢqcÍăD„.Ś.÷äĺ}ňaWŮ{ŇĚu ±P( ÔÁŹü€&-·Í¬rQíňŚrk]¨I”Öđ.“°gÂc· ÜůηňcX˙`ńćěŘ/cŔ!43 §ŻÖ0˝i] o…@%ZËő…ÂÜ˙qĘ[ R­ýŰ7MLíÜŁ‚łůŘRř”QÁżŻB–OĹ`ä‚ÜĆÍĺů‘ IIäňÁ¤r¸*Ěw:÷weO$C›WÎKď›câ4V¨tKĄÔ<ó´UOj0cšSřť×Š đ;şTKN‚0›©3ÍÇbă’«6 ß3îŽ×QßżţUm×K&tRÖ‘XŮľ"Ű·ŽźĽ9¶îŰ8ÁŰőş Ä4§‚Čž•DkŔ^QÂ1%7˛kęqWRZ1@ďýÓĺĘő— ş· ţüi›÷ý±łń-č&WťkÝ@˝PĄťŠfF´üŻöź–s®sÜCtßaË˛Ş U®˝×—Nâ É,®hsxŠ%Čß–ľpE\^Ńź<ę5zů®3±‡ńąĄ2XÔćâăb?§Ě' P•6żđŕ!-ň as| ŰŐN»°“š I(ϲ&¦1§8_ bt˝t‚ŃŢćtÉőTÉĎ—,ŁŚđçŕí¬í° w÷żđßżŽP5ÄŐ˙QđĘbç‹ŮS!ťWýfćxŔŤ <—%Ň źUăÁČ{uÇÍe–éŕ‡2Ü(1m±ćP˙p: nÜguZŕë0)rąjß­(0Ę—¶Ů´>(©¸ŮśÁ(ę6Ĺę †Ëž¬M°"ÚöÖ%}˙‰hń臼١ƽa/Ă-R„o¦WźÜ@ß«zÔËžc9ŞĂ­HoHŮ©j¦MâiNFÎČ:w¦‡ "9q˘éU*ďLĚ˙I9Ž ?aő’KÉĚ‘áÇ}VM}@…ů‰Ś2E,šzÖX7|ë‹ó é¬nűEy-ĆŢ깸E¸Ś47ý‹€GÍ\ÔŤO2ŇZĆ—z€/AZvĄ8šĂe…f\@j#ĐG«ó˘ł~+\ pÇ8WEîÇŐ;řůýÁ‡íŤC°łµş°‡żŹŘ Ś9EŤJ+Ç9Ň/exÖ6÷©Ną€hrBŔI0¬bř[ůj XÁ;DهU»¶•%ťé6ča®]‚aLPłř?$Ĺ'”S¨Ye¬u9c;oV,”¬k ŘM®Áßş¸~ Úµ őB=5$p >ČFIłTh]P2”ú‰h»SŐqÄűúŰŐ§v‚Vjź5ľŤ¸ý}#źŘ$Ž+ÁŚKx‚đÄČfV·NŠmÚ«jYk~f¸&č‚\áÚH4,Ľ~^wäŠ ¦­ů.ĆŘoD¶´Á8đ«ćŃmş>ôáTö\ÓŹÚ• f,˘·ćÖ·#Ć!™čÚŞQű…^$ľrĎŔ:r»\¬u'&őDö`&ÂŢ]}ÍE\Ţ:w™ŢOË– ’H”ř·ćäp­ p4ÝhźAâlů×^d/bÔ‰ c D‚N4÷ĂNÖZ.R’‹Bl¶řS÷V $Ţpź”ĘIă :D·Wn]•ËŠÔě{Ęb·Hš żŔ9%2čľ  €ŕxőŢ ÔԳޝđ™Çć`Xt+• pěî™C‘O3:‘Ýű~䀵^7콝B[śŻÚóŢ)jU”ű„Ămńűś)»1!K_Ă›×uzJň.ëvĚŞ€Ľ†őâôMâ%K–@SÍšJŘ;%N ţ3ÝTBĺ¬A-ău;őAR\] `lCönďˇĐÔ ÂOuŔJÖę‘TóŽędýż§ÜY9şş·ďę(“šŔé´ŕQ˝b˝„-–ěĽYfŻ•K.Qđšţä±`\~Q´ÄMŹęč#!čäěîţţ"âŮ«Hő4Ť!?«˙>ŁDM窥ÄăőđŔűđ©mŤŽłŤ!Gü 1řa¬üW6n=-^¸wĎiO3RŁ®„—4tĐJäwk=Đ’hÓ^bDy“–SŇ ôľRf˙& j3/°~uńíŕđ®ßG٢äéŞN/ŻžŽÍŹPաݮHőT0ĎСűçi Ő\D]xÓ*C\'}ʵjŔąĆ@ŠڶBąćĹŠ˙,SXpinň2»N¦ňöĚŮĄUfĺ…oť“âiśĄ§Â•äŕ(‰]ÖAŇ^%Ü %†ÎB/+ô‹ô‘ßć}J,ř€}Ý„ZŇ-3ĂĽV‚KKµ¶şď,xýCóŇúÖ fŕ­ĎO&09”“üc‚ĺĂ*ył w2©n}*é[$+b–®)EˇřoŮ?»ŤS“µZÓŠž&čæ‘ú˝çŚćmÔĘ™µ˙z=zŻIĹ#¬µT\žđ€\žö{(ÜÍTLĽá }3Ź˙vP ¤POŽFâfÎäĹtZ}G ~şŐt®Ł=É<72÷Ć–Q°Ö}TňëШ·äş?xlź°Jz±=< ÉĺÓ·Wýn[öŚŇcw—‚(ˇŇ]Ěij4×Á™ ęĂZ"—wĘäBČű-ďë|ő[C˙MîAüëţ­oĘű‚-đ‘乯>ß©ń}Măúnř"A|es.¬jmJ| ›•?{Ş˘˘Ăă*w7uýSްPHŞńާŃ=˛1˝,Ał"ľtß9ÂÜhś«rÝ?ěń“č XJŽ~ňĆ4ýr˝‚o‘ÜÔ”öŔž®Í8 ,]5…÷LżBŇ· á5(K޵Cë§ĺ4„ß#ĺ•…ŃĄ,#\źĺźŹŽcb™‰Čn|L”˛¶^>ô&1žŮůvâý`?Ł!Ŕdŕ 0ţ–…ˇ(Rô^Ą×˘˘âxÚXĚy/źT@îzĐIŻs9ĘY ÝWçŰd(0 ĆÚsÜŘÍ˝VÉęô„!Ď^eĎÜÚ@đ..Ń ű˙~ő3†úż˘VPŠË3‚îŹsmĺUşČżGRĹ’ńfU—§Ť3l­Ç®IĹăÔS‰jŻűi`u¸–Z0ď¦f•T Q'—źŮSŚ%5°‘ ›üŐnĚ9°_MË 5şB»ścÓŤEÜAq‘:ËÖÚŇr5ąjĂ™FN ‘ŇÓtí›f_—ÉÂ`9‚~đgŔuÎ§Łł˙vw ńxWǰ۝ˇ Zbńőű¦dśn¤w6Ú#U…ţR_q.hŃܡtT`G–ýĽS>!Ś3r"˛(ćÜ-ĂѡŘ[9U“^™éÚďTűÔŇ}-*HĄŃďPózñ‘pő!R7gćÄěÓ•Śm“t.óŽÄ-Çž‰«‘«Y ®sQ:ÉúśčŘ•ů”†C8°q´ÍţŠ˝Ćݮƕ\ VMd-ŰíŻ« ĽA:ęxwťX†řÄ&¸)ĄVüÔŠťp*Ţ›=ĄÁäw;óĄđŃŽm&˘ëŮsD0µđ¤Ńăťv¬őęs2ÎcČD©V5‡=бřVK¤ĐOÝsÍź*Rq®xT@r-Ă[Ňôˇ©ŞöŹIQÉŰď­•Ş%‚súäĐĬ XĐIŠŕc¤ţ!&2\¤+¨WaË„8÷4Ôę‚?# “¦ĚXR2ň2?đLČ}5ITX3 x¦ŁĽ űíŁ@÷éřUĄfÁŢÔâCÔbnĽĆŤ’€Đ;Şô!Vŕřä3ŐŻ<ľ¬!Ž©÷Kâ†÷^jHŠŁž„XvٵóŮ–˘Ä[Y"2AXÍJÁ´ŐĎą:ľÁôS˝Ł4Č\٠ꢟöWąĚĎeźµ!¸>¬ŻĄÔ(Îď=#L<]°ÄsÄ[$#hżz弚ăşî¸śó4v”±0»çg wtYŽŻŠŇ#|ŇWëŁ_ôĘIţÚÉ'‚[H¤Ô›Ľ8@™8'=´+ŞëĎݢPăľ§äľÚ@lS˙92ÇŞCô`¤é™»Źëĺ´§®”ýzŽ­ ”¸U}ź×ČŽ‰Rpw)-ň¨AŚŮI8ď9ŁCĄ{ľ±E†é&l8ąŻż˘WîwĐ‹mî>¦‹A(€fÓÚwŐ2‘:źL­ý=ëľúďńŃ$ ů¶Ó󢟬Tó°,ĽNłBbSű‰fŇksđP Mlg<ž@ŢőŹOÁŤNÍŠť7˝ˇĆÔąŽ+AVAřk".€3éKşúG#âĂJGٍ®ę˙ˇů'nůpŇśÓÔ˘šńÝ"}šH¶äčP†éŁśăN‡úźÂŚ ş\Ć^ÉiA‚”ćHaˇ#ĹkË#Řň‘P&§Ç9_Feh?Aaí†ó—•X^˝|Ô»†îĹ?Ł#˘_LćWţkŕ(ďôcäQ.«•ţő˙.Dőäv6?łĚőÇ2íŚ5™ü)•żß¸ güXô&(y‚¬ńĘ©Ëŕ?ÍŇZ×)Ä×)Đý剭N+z1źWEi1Hu©*Ó|ďÓOĆţEjŢY85Ąs˛ÓíC%î¬yr>Tż™.śŕđ ×t§gţę=Ž‹N÷˙÷Ş<Ňa4š*E ¸®Ó>ěúßZ%ĂźŔ éčxR6 ˝xą"vđŹ ‘Ný¬ž7 BŽČéüN/MŮË“›⎠—z]ËĆZĆiŰvă’dX>myuąŃΙQ-ľŤß4}ĺp–Žň¤^ɑٙ“Íô|ćd‰™\őRe Mľ$ěóÁ= ň2]H˝ĺ4e~Ô–Łß±K˝řuu±ö´CxĐRꀔÓjĽÚ­ţ»TaOg—ą$Sč´4•ŘýÇ’HţAűŞđ.-ęÖh!m‹’x ·[LîŘ´18"y]±9zľaďO `Ś‚*ňéd”^§ÔϦÍ61YZh•7Îń7Ľ)­2±śRS›µĽ úmYü°.đ™DÁŞL(LFHŠ4@R©őBsĆ”ź[ŐRştK‚(můă;y]FÄśăŔ¤ţj†<śGYt2čťm2+ýB€@†5ÔÉyČţVČ^>źdiRŤŞ¬Ŕyk¬/dŐ(ö =Î1Ě©ZkVÍĄ]޵0}•ž¸l B5çalÄ*oZ“IŇŤ7Í_ "Ŕ˙ă7ë߼r*úy€(Ô8˝›żű>{Jč^»ó(J(wϧĆtß;쌕v‹ä€ŮDJyąřřy§đ+‡rg%y -…JÄŢݦmq ˝Q°Ű‚MŚg¶“q+˛˙‡ŐQ`tę(ýXÜ4&Z4wJSE›ÜçčÔ„ŰKîî­ńć$˘LĂöś_ôÜťd$\ý$öé*Ő&@Ćl đAęőŕ{Ü2f<ŹĄ#wS€0Łg‰Só–='šzHŠ“•p"˝łÇ@ɨô4üE¶bRyö8Ä ”“C䕲Ů='lą’>K G´¸;Ł'CŕÎNš`D†Ę_U¨öň`1y»dňq!”Ó4ťÜ3šSóŽ.ńŐđäČáń°ŐšB§…ćP6ŐůĂ.Ş[‘"Ţż\˝^%ţqJ,'ýň›ëí…Xâ@ÝLÔ1cĺZI%2áJŘ<Ů–NĐ}Ç»­Ć^âRt bu“0=i+|HŮT·ĆÎăV¸2Ą/ÁÓ%Ýt;~N˝‡dÄÇäqe&ËÎîžß§ŮQĘ5#kS&brlVĐz%E‡ÚDéy­ę®Ş§’Ű&öŃgQËúýč˘eť¤§eŕKµş8×~GŤrö‰fgŁ©U8çÁGđdę ůÉSô‡ĎăwˇDz†*ľZ.Vu*ÄJRiŮ`KÝ˝ßJš§kxÚ<ČNŇŰ’±NfAóĽRšĘÍZú\LËŻö“]0wÔIg‡™8([Śž‡•"śgČ:ϤĹ/šGÜ.!»Y#ŇJúýŔ—Ę%]Ěź%xéoőî‡Ë¶ŐwŻÔy`P┵6hškĘúw®3éáŁőî5ŕ6f ÂYüJşöKéÖ!{ó— îŘ.;‘L‹§DwmyśĚ`Y·ˇ‚«+2•€öǨá€čżvšHV.\ĐŰ}L€J޵x™ę [é,ôÖ(ÚĚŚnŤ•BŞ‘E]yľdwh`2G˛ë"Ké¤|+ľ[Ö÷?H~wóŮ Ď0W ŻÎ.LŮŽë• ¶Ď&ťĽÝ'†›X±ËĂ,%c+rľáĆu4vdoü@Üg<ővÉűĘőę{JĆjIłÚÂç2Ăpc¤ň T;)+K„ľLvŐ w¶űł #m˝]®MiÎP|łX… ˘Á4G9'˘ ´u%… 6k.đ#Ć\'żvĂŤôL΢0öśs8ŞE¶ n¤±Ü<šžSĹW‹Rž4ůÎý¸P’°fÔđĂ›^xź®$Ą•aNnrr‡4Š  ,…ĺ×ţęů|˝j1˛H€[ńühßČ€Iă†Tűbwťp/ĘŃ ŢßoT5™żwDM şű>@`ńüŐ@tnŐŃĹ# Ş1Ú"ćđóî2­Űď»UüáĘ}{Îyp4Ż7Ř´fím†e,ťŹ/Ă´”· ĎxZ&DĺŻ ćCţ^ECT7í&ĹúÔHGÝ‚*@`‡“cďěçUŁ•GĽiŰů‡á(*dŇ”»3] Ó†˙2±ÖI\4ŞčgĎ”3E5ON!‘ö‰ůą{š2ÔŇ Ů˙‡!ĺéëL µHéň˛§·IŤôććoLa ŤďRűIN›´xăßŔcüŕݎ %¸UgŠű­·úŐ+Ź)°cή˄ÚY[ś ¶ô“î†6_9śŰ8ťą(‘™ ͡ĐtLG˝ÎN»_ěâó6'íމëírľË®¸şĽbŞDĐč6>¬XÄ"ř(DĚÖŹőËWML ˘ĚP ŃĺFřjAŽíž€~ăJ-ĚžŹ¬+Éŕ•>ţt’§ŁhóUnщ,°DÝ•d¶˙[\şö7vgę„íŻé e\UÇMęĽÇ”ëŻ4ŘV›vç5ÇÉÖ‡™ňiL”ňN y‡/źĐc1U·DýŰ2QŘ tX…'Ei[˛ëĄAŘ­‚ebšäý3ŕ˝­@ } r;N.ňpËú—1 Z¸Oî+R¬i+ 7ĽŢęë<Jč™*_­őăčÇ(f.á_·|ÖŰ’Á˘XU8YlżŃXËh×Ö ˙L ůifDL§Ř--%çr.5'äÖ*™^éŽZ:¶qŻĄ¶áú)'ąäÇă’Eő|÷ÜŰĐĘŃľďa «Y:ş•ý8TęŁďŮA—çN)Ęq1ihQ5#Ääżú›ŔŹFćňŚžŰ¸Ě˝'´ĂyĐńá{\ęt?@űŠ%™Ž6ąŕß鼲ř\'˙wuVr¶˘…˙pË›Ăd^}‡ź*ąá@0I»a´UaUUçVÓ{îŰ‹‚$XŔâ}g®plíťT'ßLrf©˘š@©wň”kGű0V»żSę'oQJŹČdŚuŃS É°ŤÚš€Xń|Ę˙ŰŁź­íëwťś† $Óš@ď‚émtôS‚Ĺ+!¶ 1Ć[F…D/ óźčQa*$ĂŠIú’Ôvě¸/8’m(pÇěú©Č áôdŐ3ŕ)’¨Ý'béÁiɦýbŤŞ´·+Ć-€Îř^ňÇíŔá\ëSĄóăóˇójIbŕS]Dë:(+3 V17 9ňhs/Vév»ŕ˙Â0Ö| ®şmü©'ŻËâ'Ôbî—čf’††ô3^1|đ<Ôń‘9ÎĚšőßóťŽË‘Ţ:ź‰(xU“3ëŃ<ÄöčÔŁVUk”ÄĚh“Íđ*a@3tzÓą3 µ5tł°şpü‚Öľ~@ăAĎ>H–~Šwż  :/‹e‰ő©VĄí –iĽQ ˙lĘółż!ü8+Ł_Ŕ­çŠ+˘6ĺ}sŕŠ6ŢFýxÜXbÉa¨ţB 's*¦BK ľĆţK¶xôp™'ŚbÜ R8ň†¨f†áAX2Űą:©/ŚŽŤő×ú€ Ŕk$ qřoČörˇî č<řÝp@Ë·7ŠŻdzyO@ˇ‹$'5·W‡t \śrě bj+Ř6%´R–dđŽ‹hě9ľVťüx‚Ńz”ůŁL^8ăů)0¬ţä‚ őH'%ß”\+2¸ ‚ÎRwpqJçb-( Ą řPO , Ă´Í˙@p|ŮpcŰďč|öAĂ:/# ž–ŢKYt†ÜOľbšÂ°_˙}P˛š‚–ÖhŤ|p^vťÝß 3/ŚďđĎ&–!ŻlżÇÍ8Ç™ř b?%a(í¶ṵ́çeÍÍ1Á¨ĄÄ:¶… îěgI ý^JűeŁlüůť)öm‘čô˛‡ëďOµ;ěŠCĂáV ZX” Čk’ąGŰ«äE¦ňuńßFy×—s¬Î&<ľĂďuর Żp»1Ç(›Ľ6í y>0Ó1ż{Y(Ř çŽé,Ö.đľqG},ěÄ%¸Ű Żg+2{'Öď+Xí\¶TN=ÓżľâČČUÖě¬÷˛Ä챬'xé âUŤqĂ,ĺXN>Mc˘"ę1Đ8‡ sß]N%,ŢËmŕXŢoíń ĂÁq,6çź#Y–;‚Ô+ł^‘ ď+W–®č ĆÂJBčÁÁlí!ů±9¤VÖ}}Jűśa?‚T-´¨ĂýŤ„:J×iÇĚÍ3ógž"ć‚Ęt9bMí0·+ÚřshşŰ aa©aş?‰b&¶Ń _MMŤwmŰ«éÜĐ"î#­=:vüSËé)\ĺ×ŃŔµ-ý§hL¶L™ă  ĺ,|ÚÜN›Ń6•Ćnč/·UîʉP;„Y­´7ŚVtŚ’Pĺ®f¬= ™:ď„$Î@.sú!óńËôŰ—lÁ©˘bĂG7¬nF+W‹ „ęî^#Ô ě)ŮÚ–XdŔ•śUńą— yPľˇ>ëíˇôa-¨ŢŢG[ÎŹ…ýÜMO/íČßOˇ‰q©k•L"^KÄÍÖ d¶—|Ľá<Áľ á ź§ö‰kµmÍ6ÜyŰő&#RKa:”§ľ›âŰ™0 ÖË`IŮöz^[´ĹŘC€ŽšMJlŔŢ“$’I$ żĎE6c*ߏ ´Jµâ‹šŐ)äÂĆ–‰á°ŁéAŕăˇ$EMČŃ0ż]‚ý)…ҡ7ęHórx „<ŮuG†Á)ˇ/ýÂô±Ř0łŰ!Ó­çÎ5µ0ń7ńqˇ#WĹAµ¨ĚWîDbV]S¨d7ůîď° ×Ƶ8LdÜ1ćW;$«zäáţaůĎÉGٞ:2´^Hß4˛Gt„–şżÝS.E <°ĺdű'ňÄ„Ou‚7ŮoMÇ©¤S«CLdčŽß8Ň-¨%&.Ż4ąŇ›Ń)VĹ.ËćŇ`mĘ'Cł7ęÍ[Ćn$!ůíúÝM®°_3žH»yP¶†îM\~ćě¤áxYÂBţŹů~˙ť?E|@N3’š•ž3Ň“%t!(ۋٗćŚÓĐ,oVŹKDB,š±vŤ9§˙ÄĚč'?JőcPŞ›c‘?'€s¨pU{H’3ަťČěĐÂ}É1 †Ăč‘Ôő‚’! Ž§čó.%˙>I‚MĹ!:Ť#”i€l,eńu¨ŔöŃXńxÔźŠX ĎŻ-3©÷¦ă!#˘Ţ2rZď: ‹-h¬«.bK,o|đęŹ)¬‘]U' µđvXż«ů—ńA Ç^‹¤\ťă#‰Ý@“ř!†ô)݆ýWĆ•ˇ¤GĽ‹‹zíCÄ;‚BµçÇä“„¶/ÚŮĚŚ ŠČʤöv€<ň1TÍW‡rjĂlą¶ř/@{ śô ŁÄdŰůM©˝^ŹFÍĂnˇÁł ÄźÓ…ć‰o˙,pl16emÝ΢äĐgwĚ `Ň!UG/ŇśŻ÷*J™oĎÖfܬ§ć,ů4ň )9ßń/† 8ÔȤx‚ÍěÎ#•›ÎˇN\îBsRDxwSr,äˇoŠj2–Ń©ÂÔ…ŃugĎŁö’N‰ţŠű瞣&a»TÜ"Áţv T)”nlÚS:Ěüp Ďř^×XłÍŇ”ŠGŹ+źŘ®ŇCů®yŁ:)LÜŞC@i˙©/xĐ#Ż©Ťµ »’Ń_Ţ˧̙cN‚Ý.Ę.IŐˇt­Ě-#-ńB‹°(›S,íH™oçÖ,nżĘ >[ą/ěI˝?/Ív&[]„‚ˇÎĂ›•Zg”5“čĘM-:íĂ¦Ś±żČG'ÁŇZ‘çX“ÜĄH÷0÷“Ě·5/ĎśÄ ¦Đa#˝řWśkŤđBěÓ´µ6‘™}šżýAߣ×ú§J"Ü' Ϧ[¦¦…Ň"ČRp«˙†ZrŤ;'ËŠ’v˝ýGşďésľÎؽυ;­ S:÷ţ µ<8”šNÍ‹$7|ĽÂn 8owöpE(őZ"_A"1^ß×ß±»-č2fő =>*¸żÔ­ÍvtMč°ô,4ânXőw`#ÝČ|jŠí I›¤Ă,~.o]= Jtžô|ľbŹ*¬ăqAB“(Á]˘†rcúo-őY)Te¨Tđ0[ĺÜOęI¶á-H™µUŃVÜ1ĽŚG;pH‰‘´Eg"ÖgÚî2ŹJź8_Ŕ¬ř {kS‰ô VI4¬ô÷±ăUî4¬Dťaăn‘¸µČú62§O:éśm"™ÔÓiŚO±›Ď!žĹ@4§&ćěăöD)Déó@˙=X"ěŻÓ xş3{w”eU„v'¶Ď¬şO±Éž8cYŕ—L™Č»ô]?fY댗˝SF^¤ľqZGÇgZGá=ÖÖö‘\Q[%đźrµ}™ŢäŐ>‡ŘäIŠN/¤»‘ž)±š•„^KT%XOö%E"8˘~`<˛NÍl‰¶p§Mˇ„ŕ,áxnÎďZc„Zd‰—°˛tsi˘ĘäţÄdLĺÖŰ5–őöüˇ{˝Y;M»\%¨bDźöşŘz:«îŁou¨Ěß4˝ĐhlěËÓuM°č'2čd@Âi…™Ľ2@ÇúH{0ˇŘcőeĐ,ÎbµŢÖ"lĘĎ2J7a¶TŘ&đKJ xLd$ά;q«P]ěBÇŞÖVçÝäXí‰vˇ•’˝!«*€kScz4©fÂ(şů–!¬w•‹nîÔSľţčŐ€ßzčTŚtďČŮĹůČä °Ł“@•$UĆáWŚÚP?Ŕ“ôXnŘ㝤.V’¶PRN†ZŢiś\mzůčhs±ä6H˛µ™x~Y›T„:đ´hX é{†{Ę­Ŕůö#Ą×eË&m÷ĄMť ÎŽŔőťúͧódĚ%#ŮÚ¦®äxÂŘă :čťxăj’/j^·–€ÇZ*Éłf6ă*ŕqcólĐč6˝ČjŤÜ ;Ť”-Ü—,láţTŢä!J6´eýôť* ­·ź: 3&VľŻÚčB‹eĎ› ’Šy‚Yň›8Żmł«ˇQ;\o§j–™Üěä•ÂÜOëëá)]łżÎůDqÝÜňó¸HzŐ3©äʦÔݲE±±ńH Ł ęť†ÔůEéÍDĎÜHjĽ)řYŠđ†ňowHۇ@±Š'ŕ=o#ČXč,°Ń’m<*ňů´Úťcř´ŹsżM´°oĎ&Q_ŻÝ’ąŃÄ‚ćXŻ  "ôvŚůń`sMŮw»LN.µ¬ąf.*Xée‘ĺÔá×anÁăN&•EzŔȲŢĆytJ6ëŘ ÓáinC«.Śł Ď˝ÉLíŮo ±@ü†ÓjM ŰÔ’žQč©}`łd n§ŽĚQ&[üĽIł…NŁČdĐ>çfiâdĚQ ĺë‘K˙TÔHý3tV[BÎç EZ1O…üËGOîÇŤú@ŕĽ[\2ü:!m âĂbOď1M@…ő"Dl íé6XĽ±ÝSÄ„í ‹ľ64Pđ6ÓÜ˝L k±‘,ß©ěá„ňqĂÓ4%vôŰ í蓏žźÂĽ­ ĐťěTgŘ÷Ů[µtfP˘Ź·§›Ľi(.&n/S9ĐPV]:ŤŚ#zfˇî!šwŔČ#hÔÉŔ, ŔĂv“ˇK˙wWGý`ŽX4¨Jö˙DĹT€Á˙O\úPm“,ÝęzHÖ9C%¸Äţ„Cš”§ßňń¦ ¸42S_:h”>ç§âąÚĽ{)Ĺ…kX¸ŢzĘ.$J*°ń˘!ŘE1Yz…’Đďčö˝ ô Uú¨¦®qk~fő z,×&IŰŇěp°2üÖ_Ç?đŞĄA˘‹w™‰c?¬:aĚaÂŻ¦ ¦«\¸o3ŐĄ™d$´4ě”üw`äő=$)ŃÖ‘•ńéŔ ôč„!Tě&iüěZďDýl\_¶Żĺ…¸˛ÄÓzëejHôVy))dµ)…(9±D˙oô:tdŤ1ö˘ {Ĺ~×N¤B|Cö&Ys€ľ“Ř"TĄ‚q ź{KĐKŞ?EÄŽ‚ť´oµĚ”µ `#ý­ŘţLs'RĐÖí*¸“==j{°F“׾Z2aö™O¤VMÁ÷™śA’ÍέËČú¶™(ٍC-%ŽOU{ĚdLŞŢ] ŃŤ™š¸đw,Ô29íGŹwW\:ř ~iu 'ëbĆymN5ę&ľďĂcŁ5(›˙\]¦;Í,m1ga «:/°v“UŞ™ ßssRćĽ5 śšÎÉ;}¤‹đxŃyéŘŞ4oł`]ľíí¤igľ$jSäÂlé“#ä„ę#ĹëÜ”_ˇI㌆®şëŔĂ–ßľý×ďu?ľłxpö®Őť<ŹrnÉ n g ^|l®őÂ52.±÷–?ÓvâĐP 9:¨Ů{‰)b š ô†~^o{Ă®|o´ş‡“̮ű7âçő3Z,2Äe őţoÄ PWŠe¦,;yíT?v,ŹŁůWçÓu¨:,Ý#FíeI Rű®¸Če_wpĄQ—ĂĂbh¶XŔĎNG˘ň•±>+Phčćý…ś°ćÝ%V}µ 8(±ń®Űhĺ ŚÖţ’pÂ&'č~<˝«+‚Č˙,ĂŰŹŃ˝kóç;jÄ‘ÜQ °3iµ˝ŘÜ^0[O±ZúoHž2ÍG“˘­łéŽ”jlŮŞć„˙oo—ô×te ţP=2UŘ#Đq +Wî)„,©X˘JőţbJçOÔZ$P«iyV!żľ¨ižĎÚ{<‘Ú¤ÖÜţ–˛XÂ÷čŢjfúkNäžíĽCžĄpBśßRř­ĘÉŚ’UĎ˝˛›§‚­`Îş0ÓHÎv&gÍ|ž,ču€˛)FűźúěÄjżçzŐhbź t%s>ě}qďoóҤJŻW)`ő:ߎ5 Ľ–9Ăí®ŘR3vôŤ›$Ş7V×Rçód0"f&źv·ôŠŹn„˝oä\§†lSŚwÚŘlaé}5zb”ß,Ôôٍ0›;ßB(G7ĎĺŘ®ŰH{WlDńäô_™ś˝k.yeá9ꕇ9W˘˝Š¦h %ЬŽ]śÜ«á29Ö+JX¤€ňőĄ(×TU{ţC Ęs"X ě'‚w¨2j<élď!ľ\†ŞĐiŻ—0@aň#‰î,y#ŘëüWíň“ěť3ui¤ŰĂ µŕo‰ötŠŢĺčТš5ĆVÝ|bą…:¶585*ˇśYźŁ öw3ś°Î¨:“Ďń&Lă\"‰jŚ5yňDMů>éˇGFW-$Ľ<Íe©Ć&×MMgúŻ őV¬I‚cFăanh›Ą7FY D&'ů …`]ü<ĎoŢ}Lř¸S5şdt­fkp$‘sŐz–ý—ĹĎÄ»k^˘ĎqşÍKeI›Ńűś"Ďj˝XoRٵ{Ü.‘”©µ%É휉yšQ¬†-đh˝ ŇQĹ9oÜ®ŁYÍcÎ5)ÎŃşYˇŚ0‰Â¬5*QTëůÖ—†mpŘ%s–ŕçĺuÂ#^+ęQĄjÄÓÄ Y:2jHń0™ť›ôŃ8žźt>â)ÁoiEáXżž‚_‰čPŔ8šľźG·´˘Y/IH•«÷®óŚĄd|ę•(¤ě袉j UęŁEµgě@?÷Ďlvl6Ť/&ýż¸ÝIąŻřís§źé «¤±d/*҉–,ÍWÓßsŤŢg˘¨Óit=`cŘM’©@vŤRĐÔĺ4§> CďŻ=cÍ97ÎřˇgÔź1P®E˛ž‰>PSŚţ"×jĄ:Ľ«żĽq‹ŃsÄč3“’µö6lĚjľśQCŔĺifëÚgÜtJůWż€&ř|š{6”î9OXîâ’ŠÄ‚řqřD!“:ĚM8žUKP%ţ«¤ď° ÝŻÁ€A—‹r.”8Ď)dw:¤V;NAn<ý8zôn‘P¨*y¨SĎt YË/őT•EŽSŚ€'ŮěU_ř`hš˙<|ĽÇŤ$Ŕ¦[j/(fs¸€GÄÍ]µźKI›Ő}U'çŁ_R‡©Łö¶Xza‚|׹jRKś#űÎ ąYrĐ·ľ6{ †üPJ‰‡čם9r®WRaů˙!ČÉĚĆšÎa_©a—l ɉ„MŢ=żłÔ¦fŁ÷Y"Hµ˛'ý±¤ Au?Çĺů¬,ť€«SéKIŁ$ťŠž Łz«čVŻ\-rś,íÚŁë´îł ÓkQ …" _1Čâ‹€Ńf«E!Ăf‘ér»ďÚÇ˝$á8ŠCᎠwňFqďíV·Ô•nX2YLl§ŕĽ–Ů×̸QFHI€¸öú`˘ŃĎYş…•‡95_üŚJ,Źt– H2úkřhuÇÂQż–IFᇺyíą¤«)sŐŇßJM*'íçnÜŁťí-ť‹Žcá´`…±)łŕîh2~ó0ń;7 „*CB]XLołZ)‚ńKÇëáATĐó`V‘®ĚÜ*ZdŢÎJ ŰŮ[(r”q¸ŰĚć}Sq‹űF‡_ÉMpě3/‹‚Q?”ŻsÁEŻLˇCs˙+Vx•—ăGŢ ĘĚŕ‘ž¬ŕ°Ç`ŢGż|şřpŘť#„ŔhP÷qţašÄĚ7ŚôŁ'Q +‘ň0Äj“s™Y©źkcR3b]ś]‡ŰGěüpGJź—8‡ÎĽxĽâß8?ÎI–9°&‹»R0t®ňÝ•> k/Áw;''ŔÝŽđTókŹEoŻă2n‹¸źP‚w ůôé'@ă°Y l·}r_dß…ٵBň:±(ĄuçčGl૎Ľ°&`”o~÷€& ŐvubFMnĘŃ1[Ťů‚L¨ćč›b>¬P đqóW yeYe¨mŰ}?űbSD\9?‹ŕšćÂy7ó „BB9B NI©Q}|;ARTr·ë)ăĐŰ@)‡=  ‰ĚBdżttj•r^2Š^Íc€Kěún5}_ăÖ¬1±Š»Ý`bCő00ŠT<Ş!¦ßśUQµś+} źěE•Wľ±Ę7ËĂđŢnLlr”Ö`ü×˝—w©©VâµU!ZŕPxj¶ŮtŻh&6* Žq‹Ô+ ŘÜ "Őu~Í·űX•TťTQÓoUÖ|ič/¬ÚŇDIÓĐűhJýu{ĐkĎĄ$9îwe}8´ŤŇW’nÄÂŘš0ěÝX ëńŹ|5¸ť¸ľäÁ­8vńU­–{Äŕ IEkôÇÄßëuę¶Ló“4Ă~I@>ÄG±+r告“Ý -v•3Tan¬ÝŚ_^ŚQá"\č˙~ńżěbé¸ü mĺ`çŹŢ>«R” y0n]ş%Ć”e/íˇ$˙rKţŹA~)Źg%ÎoZ2·w]'ËŞ5¨9ä2zţ2/RşŇŁęĹW]ÜâęN㻤Lp‰ÝX(†°Éi;¤ExQ¬\ę´WťJő‰@âĺ číĂëŢ®ŁçpĺHËZ-1&×R{•Đzŕâç„â?Ňmp&o Ţ&^`„Sŕ´X©š2ž6FŰgá KśÉ®ćLpČöBĂýŽzFЍš”ü«ßĆćľ3‰h:E`ÍÜŁBx‡řŹG“ž« Ë˙Čwçą?µˇ0T-aksđ?A˘€ŘŚWÖĄ$@„)>Š‹®źĐÝ®ť®|Á8 ȇg.,QđbŽfEn\op'ť€PÎSßďŢŁ¦>Ó5ŁřâT—ĺŕ+§˙:ˇy|ĎQ`Üěźžy׸5Ć~ID‡“ĘDnČ70t®yň´€GŻŞa4‘“Ç‚‡ëF¦†ŻrxL#îÚäŕ kŇóKÔEëăéWʍ1ç?Üz\-’D\$mŹNmŃMĆHµa÷ŃÖîŇ雫týt×XPem fhµ˛±ÚĽ\©ië#Q­ś\ĎQG?ůqš2ű2b ŔYŹÍņٍ́“ř7 —pĹLB|ŞĘi)Č@Ő~˘ ]Íg\5ϰ‹ĐÄÖ:€fűó1ά!GęĚÓbúŃS"ÇŚÄČq)9•ĺMŢEĄ–ă×ď©vek?0Â,ť4…̧^ě~‰PB"¦lÝ+Î-©ŰgcMW”4ąCö#mŁţ©ńŚ8mgN§¬±©ŮąČĄů9ęcrňąWi1—€cM˙aę ÝO¤ű:ż<h©ŃZäH•ŇeÇB»/ ŮjµÚ.ŹQŞöČ›JM‡·R 7Č#ó_Bx7ů€÷Mˇ”«÷Ňg5Qg6ÁŁĆă8°ç)BŞY0 ĐŰ•w‰›Š7Ĺ÷bB±ü±ŇS4ů•(¸"Ő0€®¶ć?7*©IňUY”—“ߣ˘¶”$])0ź^ČÎ:Ží`ů™ĘąžţbiÚĆĺLÄ7 5iČłw-Ńö×T'„ŘŽS ţŃ…pĹknź ig*ôť Íçp>0ÖxăÄŐ$:ů˛ÄIDÎ^ń} ’c˙˙SţžayRÂŽ xBÖ’WîµM4#/säUcő/đ†j÷zë}î'Nš/¶ŹĄÂ©Ą‚Gx[ôŤ €1Ůlí‹xi1ŰŢůĂ#2­€âZyIŮެMr‹U»/‰Íł¤”TĎîľu^QľŚďkă2莵€\VZk|ůŃUŠáÄꉢŘm§CJ‰k?tůsá"&Ë]‹¶•/±Qž«JŚ©HĽŐ¬ĺ°hq`ŮCHK‚Ás+ĺ© Ľ˝ňúËS*z4O!c‚‹Źä_öŞ;# XFdşÎűťďo”ö][·ńąQ…I裸—}HJoń'FČč#őźć÷E;«´@Bi‡s^c’}ŹżŔçý%ő0ÔăĘ9ÂľĽÜKWőýZ°J[*¨ÖžŔ_<‚U›ŻÁ$‹ĄůQ⬅ë÷SŔÚިfď Ż¨hm±ö›:bő ć—Z0¦Męl{NĘJéѰaßś˝dL”nç)Jµ’EíqÁúé”N6É?5^üŃ~Ü|ZčwđFëĐ÷‡oÚS•–ęCrđZ˝BĎÁ»ľÇńë=ňśěLŞk&żşHÝ“Ůç˘ÓÇmĆť=©weňŞP@2’Ŕ˛«O0Ű9yuk«=ßl§myĆH›řE¬Żś+÷ÎA.TIË\Sä™í±áb‰R|D3÷ĆâăOO”§ć˙⎣â31¨_lüÖ‰ŐqŔ‰Š‘CU`Ě{S®wZŠLy ňźJbŁ-™’1őq– ™NJtdĎČUä—·eE˘č•=˘ű–đĺ˛;Ó ¤Dy˙;Ý;ZŞž]zt­OŠžK!‹EůXtĐeá‡5/÷t@‹@%äˇ}­5‘Äqf$Ĺ+gÓqqÉ&l?ŃZK_oć\N¬~ Bć‘iµčWŹ6‹ĘçłćsląÍ-öŇôŚşFŚŰQŇHWŢW‚ČË„»Űx0„ŮÍžçh«p®R¬çĂk{F+Cv(Üü@y"[Ůé5mˇŚH ýć$Ü‚y…[ȢˇúGĎç€ r×ň‡w"üţgMGQrń 4ö˙iÝ,”y7¤~2= ¨ćŐRŃĐb irŽa$*9e(w˛73q-!߇ț;!,ëi]Ąă:®ÜR‡Or–A‚C-SŐVĚŘ"řDíAY{=2µ¬Byź›,ź#á©ŘQ&<č’|ÓVoP’¶M„o¬ 'ÇĄ™|ĹQ#Lüuţž:Ph|…şGk†wĐ[µT]sřÉzQÔq8[áß–m>Ă6aOLŐĽrJ? cK[ xşJxVd !ľ‚;řcŘÜ +t®ęÄđrĐ6Šť‹ĐÂbîË4#ęď«z(°÷Fh‡m!ËMµčyŕ…tR mOŰ€a1Ζű ®‘űŐŐ;śYZź“ß?罀ËæO[ôą±¶5ŘëÓ37V*JǧéBěŽgcŰNŹćl‰ĂÄG‰Çé_ľla«J• dá5±ďa&âî-˙˛yŚŁ›?ÔţşÂćÚőV S©Şp<‚‰ÜłŇ÷~~C#`ź++ †pTŽŇôF¦]hjÖH©Ő[Ş“Zţť¬y®>Ü7Ą¨Đ(1ë˝w"[D,8ngG>ť6ąľ" 9Ë[O–í#KŐ}Ěgˇ‡ÖI¦ŘÓöŚË@UŐsČöĐ©*`L<¸Rüłé>+˝G¦őtEĚáą.‡RjŃ[ŚĆĂ]đ,ˇö/ÎwR|K߿܀cě =Űâ«·ĄSÖEę”_–®›łh)XŔľ$üe†<Ö„śTüňČP‡­‡–žö®)e1Ţş÷g§0ŻŹo˙{šLÎ3¦*ŻĘÄΓö• ťŇV«¶v[{€¦«ÁnżŇV…©éËvŃů;>Pł Î^…—5÷¶Op˝ú :W(r‰J~ĺZ~Ž+şQ˙9V{ ż)ĹĂŹíň(ŮY¦× đ Ä3ë+‡«¬qŻřś•3U5@SŕD‚cBęb†kűm€¶“ýĆiűx÷S—‘Ż« Ó zq­ůŇx˛ťqĂĂţä"Ú0á·Ňr‰Óí—ůąŢÚçeËj(®ťÜV]ŰŁľięŁŢúöŁ5`*¬SFT›v"c9}UYëÔGa~îyjéjëyßѡ;^§ŹiQ*®[TJëvš9• ç#ÔžÔpĹĘ@(ň±…DBT(ß$8úwzy‚Iëť{‰·le󵾙­IÓV‡˛;Ŕ&˛ÜŽp˘´ľ»}Ż•ÎFýéČľ%X€ńUđÄ·qhĄrRőö÷­»*ŢÂŽÚÂ(xPĺLşű”ˉ×FË•ý%-@ąş´ň 3†ě’]´®Ýá}ą&ýó7óř]jS–ýyĹ´˝p ŤvÉÝÁ™tN}„|§Möüę&Q쵉er+î!–žn1_®_šUńRŞ.]ŹO/¶¨Ĺ•çfŮ'¦6/y9xfňpŽxNČôťđĽ†űkîďfżŢ µ>a`f‘N¦ţ~ţúyzŰ¨Łˇě ŠěD8 É 1˘‚Ö—đ(vś˙|dď¬GŃ´ĆÓ—íŹ+ł“ő˘ĺÁ‹®—Q Nć"‹Ť‡ŕ˘Ţ€Î%‰CýřYú'Ë{XĎú…Öą´äzz(6ú˝cTńˇóý^« GÖz§ě¤…LÁydŚY ł?đäńѬAÖg˙z°#µ~!”Ô‚ßäÉ' +Ä“’!+ĐG9Pî‰j9NŤČň,ę žŕ^Ů XíŐIpÂlŞŰâ#őČ5žB2Áŕ ŢbcÓ]‚UY@ ´˛¶N÷ŹCŔ?^“S]OwbuťDQŁ>P_ŇÍĘ0űŽňÖ#Ö°´Ž˙A¤šŹĆ-Ék  Ně”w”Ľ†Ú™ű˝)ź-î˝.ÖżÓýE<¨‰¶ëč÷ËY#’ŔĽJf†ś‡L®HŮĎÜ ÎtĄ˛®v˘.w:ZDuřzm‰ŻŐBab¦gÜłgÄ’2Q\L@•{ k%|kvó2% ,ďľSý5uĎŞ®±­"Á÷ţČy†SËŁG€đĆb^Úš5ż^Ń&Sžs/ÝOęź…ł_:>ʧýX%|¸ â.šv _®Ę0tc&k ě^ż’kŐş/ŠÔÁF"+'8E4ĆŤśq+!Ź€üq<… Şă˙ i#]ö.?K÷Ź(Żxŕ#öÖÓ/ŹľÂ7 űz[ŢYťp5ö92é#Đ…Ń‚ľ~5Qx©+Ít” AćjÝ ‹›RućŘ[čAöÁ[<Đůy`YA=ĆRb˛\ýJÄ×đŘ>bxŕ‡…űşÔčh÷áÉl~ ňö˝ÜYcŰ÷˘ŔFWŹŰd/M,f~jęR{§fÇňizPŽ_†Ü*QVĺĐ‚=¦s‘™3}ń©¸¬É˝ŃŇ:Ű4l<Ď(Ő•ÜE‡ř)Ç«ü;Č{ö2ţ4íNnźvr[ŔĂą3ş7‚Ë2-éŐ.ąTŕ]k ­sf gĚŮ›łŐŰ?z±Üú)ţ8Üp2; “JŇń#ËĄ”2Ă]u °Űl%¨Qfp[&ŮŢO~h…ý?ć1¦5Ăű`·äP¦Ĺ:Ô”¶ ýe,ĆC?żś”m™Ő±äa·…‚yÁěý®˙2<”ă¶˙B`ą‡Č›˘.Rž)iŐ±,µ¨Ň++s^nl‡yy_{’3 8ׂ ťJŠaËŻ°ťt–ŞY‚–˛oŁMł:ŞtoÖ ő_1m˛ #šRr^KPˇf3¸3‘ÇýÔűEeˇ,€[á•\Hł”Fa<•xÝÜU5Ő´C):±“ĎEđ'ó¶PůQĽQn«”˛©á0Ä<¶*Ű,ÍĹ"çSf8Bdćh±ÁeĎĹŢĽ(•őoÎţ’wň8˝=»‚X!§¦Ć®] /O_ťâxC,y|‹ICŢ8  *©fô ű( ü Ě÷ŹkĂŇ,cßřP§ĂřG|z˘űućO6Ă»îďŇüŇđť‡o€CB?ĺ7î[¦â @Ç•dôć%…QâpŠöÚ<äŃr\şŔWć‰u:í]muÜm§>bm’öG溺:ź‡ž»źd±"ćť±ö_#Q(ĂÁbzą$)Í}ş w(sFP6NŔ_;Í‹˘ĹăĎ6{ĺM(žĎţa™-N!âŇÖJBá›E6,‹”ůI(„ —ďţ)ŤGĐ“m ˇs"‰«žc·şË<»YŢCšęëö.M|'QkYUe 'LSô@r@´3«CJçË^ö«H'€ńt`OHzRş×˙Žlů`Ľť˙|ŮůUVŕ‘㕱řŕ%\Ąz]pFlKrR8śŞíĄ?ŐZż— …ÖËőÍRŐ÷}Łm«ŰE+ݧ˙†ÓMíj±H/RwęÄâ¨ßl?“a—‘ŞßIáXÜĽfYŮXB.ý;ř°ľ\§5{Ű<ÄóĐFCGŽľzűČU¶â pęjq«Ëş]±ż‡ÄŘnŤrUľ^—·Gľo‹޵–,˝ˇ\GKt”$2žz®´ŕ’Ú@2đ^Í©n©vaJŃf^~˝\>Ň.uUbmYZ;Ü(»F˘Łś=ĽhýQ]źâ¦6páqy>°¤ ż%‰JĺĹM˝ĺÇüqZĂP.÷ţÁHŠŁç ­ŕŚÍÜ-¬j™ťö0Eä~b—@o­“Ëé㬲^¤SĤJ.€ĂŞˇ€myŕwd{$…´¸%ŤL¸ÖËođ”K˝2ĆůyÇÉJô,óB´¸Ě)ťđF†ł‡XËŰ4-Î&@EúqŚâd§®›Đ/^ŃŮJ„YŽŤ×űmđQ2¤!–{Ě9ţďÍęöí¦śËˇ:Ǹm­Ł"ĽÔÝăO”˘ŕm ĐZ˙-Ó±,ݦö™Ş~ču6| i#ÝYő“Ű-˛Đ¦ •¤Ě%Ô„`„r¬‡ăÖ~AH=y¨0š˙K[f0H¨×›ű|LĽó ĽîÖŤ î¶ň {âuvţÇxńybÍy_>¨ Č™“cä4šBĘł×tA(ÎĹ^%7~QËüąřţő0€ź¶`u2ę®ůĎGř_Ţ5đc®–ŚiĄ–Wk)g¦8IĽ%`zoź/CMO˙Ă%IŁ…¬=ŢaÓ-ň˙)cNÓł/ÉW(rÔŽ»$ůn˘´ŕ¦Ŕ,ýLrßL"éHĐŵj=„n4Ž:™§~ g®uů”M€¸zB¸sĽÇj‹őÔFXă¬Ööýôt<¶ŐŃ‹Zť{ŔëyŃÖx›Ą»äüe )iĂXŰDyŇGzŁŰ*†© ĹI•đÓč1VZ”ĺę@ópÉŇŤLěěďClGíO‚űŕ"¤š@ýéűż 3Í썪x–oÔÝę s!/ýe<33™ř„é=e˝{Âý˝ŃŰďż«QO•Łž(™ú­ĺj&µO=E9đ…UÚí|U/şü-AűäÁ©/l˘ÇćÖ{äRg¤ĺ«z ­:¤%d"(‰‰p]&ČGţCg×Mz†ę›č°żşE¦›űáÁ@-Ů…wÝÄorc=´>Ą|@wG÷ۦ:M—” µ ˛öą'~Pą7Fd6m,ĽĂ%eć™Ă⓾†oÝB>ţěSÚ ] ľĆ˙s˙UQČÎkx®ĺČőë)űWCűĘÚ—WűÍ4v­=)Ź“!¶TÔ&;ő”',RŐě*â®`ĺwş„ ë†"â×:^’O*ćŰ=KÉŘ:<«ë(˙†2H6µ ám嚣Ű.e&ůĆ2ó~4q‡UZ+íŻVÜ&’˙ H¦ ^`lwŤźż9{čó-:­ŮTcjeĐsˇ±Ţ}çLď\@´ m˘HĂŞÜ®91°˘kPýű‘Ô"`yżç$)‰×µť8bÇ©qú)!öâMĂc´Ć ĄĹĺΡÍÖX¶áÝ*ý«Î#D=‘żiJi嬝kú7[X¬Ü;–ţ‡ĎÄĐ™c4/ ł{nRÇ^W$íăŔqűęőVu{‚ľ<ëŠĹ‘IÎ!#YÓŚ˙fŔe;IŮLáűk@©^ q¨¶FSMű×qYôÍ»’I´p ÎsKľň4?ô‡:@0Ő†ňŽ­f SĚůćTÁoôw†Z˙€”P:#…LôQĂoţ ŔĎY· …óG†±’őMżćo®ŚKz ™0÷•¸öas#«‰ óP´aSSÂE`˛W۬h|g“Z a¤xo: n ¤; ńŚ-käŢŮň]ĹÂź*°6ąä‹¦Č2â|µ>‘.]őEä×ÄôĂÔ:S…_ /ąlz €íw˝ő0'XMŐ3î2ÄLĐÍ —Ňąámv$+ÜR›ŮWĺ˙ ±2 ó´'š‚]TCP¦eĐĎ­ÇŚ…Îa€íÂz„úAýµľ»şl»uřâpo°*ńVŁnR·ăz•Q쯉už:6L(e€í…)mçÚĄBJ/TKřŰv„dî Ă)Á*€OEŇśĽĐIë™Ë¨ĄF|§˘â=ÁÉmzŘ$Ú„žeWČÝ”7ö“Ú1ôţTB+/ŐyÖÔYí“\ľcŠ­Ş3Ů—o-ÉË­b}ş'¸VwĽ­ÁOŰ'#›lŰtYÁÁŤo˛ÚŘç IßnŹ7„z@Dn“öČlP{9Q¬ŐˇĆč!V­ĄA%Ýäݱ4zn~Ú Pdćýµ°&^CČßľ#}ů0ä© ŞĽwŞ˘2j¤Ţ˛Pă_ů*ŻüŚĽr§łźBu GîÓˇśX’n Ŕ8|u-ÓŰFéöUl(#G{x~ ľ˘ÇźZGŞC¶/řëtŘě C›[)ŻóMÂrEݶş·ĐG€şNĄ±SA˛W?S§Cb˛A+`‰ő GŃÝp9M.džGI•Ł˘YNWɰZ1¤ŐđŰÁ”N)¦*v'ŔVZĄŠ\«‰¦B:‹geÔ–˝l"škĽ^Z2µÇnJĘ9ұ״·ż}°ˇPţŹŤ˛˙_«éöÄkâŢÜ/¦€ęî)“ňă§ĂŤ˘ÜščtŽv B^óZ;‘úÁÖ0wLÁaŰk˝#–1˛Š¨ťTÔ^”±ˇťg×Ĺ3˝…—'Čtá@ó_JU#´Ű-T$–Ž%ŤJ` °»™˙A¦sö¤ďďrÔ@şą„…KtŹAeÓ¦”ĺťIŢ5†şˇ)’|sŐIAÍËóÝ{q5v¬±! ͉ Ç&ĺÍŇ« M–©mH¸0vV_äÔ˝@wśyŻÚ_˙~řČ®“x,řÁľ®@×çäM23éžh=äP˝Š˦ź|Y2ř&§9Y†9OÝĐŕ‚O -`@¸ˇŞ]Ť´b[=g‘ŕGşEsޏJťéá¤3ţqXbŹüĆ85 &Ë¢­O"$žq] 5k=«›¦éÎx¶RĄźb]P¤ňÖö€—PXŽ˙đ»_ jč,íĎ_]đ°€+s´ËÂĺuss^ Ş^¸ë”ŐÇŇŞ·™ě0U„ĹKWö˛Ć*•î‹ICťŮĂ—•×(±qĺ„D—M ·}ĎŽ$?`(č8VłDŚČI$ ö°zĆ pč=¦ůZü†Nâ(é)ę ¬Ĺĺ–ŢJŮň¦WŽu{‰DŮTÜ\AfiJµN©&`&Ý:dň.ťQ–ĺG±´ĐŐŰtÂo4ćÓé•p ¦ţçóĺ…WKţ—Iđ?NŁ`+‰ŕçg{ĺ#öIăAó3ÍD_BóŮĄŘxX[ß9‹xu4ĚŻFë¤q ep›ŔwűHPĽÖz‘VL˝˙R¬^G–ôUŃ+í¬‡pNjĐ—Ą©ŚŘăS­(AŘ4»ŃŢp5¬††{čŻ0«áß""ÂP”ô„Łą˙xX9)®}řqš¸q^xvŔ!ŇZjąŘÜJn%*âGţĽ˝ł^ľâxôľ¦ŻŮc‚ÍÂźB†ťzD$V ąČŠC ­ľhłţÄ+ĺ=ň9”ŐĘ…ł<3őM”`ťtČ‹mF˙hÍëüFfňOşČôE&Ďľä0®‡MÂü5ôćuö—䍄"·´ĘŚSkŕC‚­úĆö!tKđ3“2Ň™‚ę9 ÁŁŁđôŠ»Řű'“ŠćłBaś¦ŽüŃ}# 2«ďe®YŽ3E« űOÍžWţ%ަˇWiůÓëDJ· ÇHîÎ[/<ŹfB•(˘(§»ńyÉÚthj+O­ř0ÓˇJ ,÷ý¨á-–ÁĽŁ­5čýYż;¦€K»2áP"ţ‰G $Ľůĺl°7LÔQËyÖ Ĺ÷;VË9›BŻ[kT}Ž@!O(kĺv 4AúµĽźRWËoŚ&4n «A«lĹşź6đ'€}şGsâ<˛Fŕ0źNÄ•pÝ6¦ÚČ"0ÖNŘ“őŘsdf—é§g»…f¦=·cç1@-¬ĚŮ ˇ0WŽăj}ťcÇz—ćlřŃkawĎí=ńrĂ‹Zűó ©ŐĆO€¤őćV0qdضBÂJO}ßt›înŹ<·µ ÷ “>˘¤Ň„ń;]úTµźŘ“ŰŐĎ3+±±Ĺ‚kęBvWŚŽ(熖«AôŰ}_‰ç&=RTPęuŠJ¨y1’_ř3E.K­“/uß+’§óŽ¡~ąč[n)Ş.ŕČ­•*ęťU,…Đ]7®A#ËŕmŇÓ7‘uĹpđl?"Ýá5‡”4©â¬Šç~-Bsb8“Ý”˙ń¨·tÜě Sgýł÷fsľDĐ+t—(Äś"ąô1=ěvŢ5îCaXcvKîoß< i&úK3§űĐg-Kż¶4I3ňNݨ¤‚!ż%eęĽ/h… } dMuö™B«üh¶8‡Ú?P5zQ€«Ôă1@&ČNĺćúĆ-L:ҵń+ż3łÉH‰“Ú+g{çVąŻo˛;­ Ľa|؄̫ŞŮ»¶§bÂ`]⸪¶0#µ;…\X/Ŕ(JâŽHD"»CcŇH¶żGH]ڬëć/Ůlů]úµ‹đáČ3­{îĄ ENŘ- mHÁůź÷ë„\P˛ł#+F_ŻźÇfŘ@â)µ˝ęč%¦É*7 6ClĄ´ăKoĹÂáF§z$Ú;ţ´Ľ‘tĄţŽ”5ŃĽn‡ŕÚŐ”z:¤F<ëťZ#n¨o˝cT´É@*ŤFćě¦CnŔ5 ‰ĺţýšůu/ěăçAÇ:wŁ YŮ’VV«É§Weľ?ś‚·Tzw»$äňgf )7,•´>劳u÷ą },$2dA=©Ş2kLd9‡’0*¤<˛Ë$^¸+ő içťưîIСÇŘÜŚq4qÁň˛ë?3˛¦jÉu2>4ÂR%®ÔQéhŚ'č#ő!W­šzîm—óXF)NK´ß8ľw[dŚă¡ Ť(xÄCPĚ a<_Ş4 \.VÉą?Uď6É{Í]ę ˙}îvźK«‹ý«×Z"úßdćţ<°`𤇠5MUőµŕVź–ŽR湲“JÓÍ& ý°ą43˝’˙QŠ˝lü22BŽ–j …˙a Bm\˝o8 â°P/·ăśEřwYVÚ„4éĎ«ĂvS©3hU?ݶťŘŕÔ6” @ ď]hN®Ä<ŚÄiÄ哊Ú0Ţ@W„ŻܶĄ^ńQ›»<­ż­ KüĂČF±ń5*/‰îxpćĚŰť­r~Ü>đŘ0ć’gÖ•…QvKÎĎlmsĺkeź`Ş ¤/Ć:ĽWúţÚvî¦íć¦eů/׏â®g3Ůú5yb#ގâvľk——|/s*ďÔH3&Ő'ţ߉tIŃţŐďÚ±(°âj [ć·ßJSű3Zű©Ă—ˇýh49hÚ0é´¶ŐŘn;OćCK¤&1~#µűɰ%°Q¬>ż»XJlĂ4ĺTrbuče8 xî‹ýň”ߍ čÍšöLŚđцͧa©ĘqÁţY Ö1hóE€äźČ ýűŢŔ*aĂ‹ 5/XŁ}dĆ ˙d*EBv7c´"X‡ŕNGT‹?w§śbŰ»Ő ž •Ż4ÎMqâöĂÉOďFH1«cq䛋pggaÄ4µź©×Č‚¶° ŠÉĄ;7n?QP´|Ý©őbyŻĆ©Ő=—xN9¶IđlJ»cEśoęë!’ őśĘ§ÍŻ1ŘŚ5‹t}ó­…Š‚ ő¤WłPH©ŁDSd ř»fż+9”bTÇČ—ý§°ZR›îd2ýÝ=)ÎŤG˙w´h‘7+d Eîh·ŕ)˙o{XmJ*î[‡†P €ůN#19Nţ.®BwNa·Ë‡­&=÷H8nęgö#LKN[»G`DÖ@ž@ üĄCř˘c“)?µÜjX |ľ¸ ~`W‡UŁăŹj°ľĄ­9ată%:“&móÝlUîĹk™›ĎÓ¸WŠÄ€€+}|O~ęsŃţ”ôŞ0ŤśS Ęi·¤—ÂćJ_ ź…gd9• ßýEţ™%y‘ç~›ç‚Ň `x’p(Ř@Š"ů¶~-¶ ÄŢW”U>ŮŇKüyÂČ®d"€ůbó"Ľ©^gy°ůˉ«2đ)ô’*¨gÇÇzÓ5ËŤ†3•Ĺ8÷˙9íőš ćj8qď8« ß8}˙sGÁc( ßśq#‹¦ĹÉsËÁE-Ý-2iŁÚ¸"Ń1p+¦í®K7âÍ7“ĺYĘč$I¬Źĺ°9¶ăKެj‰ë^n)ÚĹć®>"-Öן)@˙l%J‘ę›yH€ÁEŞô9G)žŹ„±ďß„ąF*şĄ #0t´]mrćd ¨}yĄ®m‡’1Łq¤„víBzÉŔ? đăS8äEčŤ&COD,"§íh÷‡§eÔ"p.”hÜ)čŁ)Şšvě5QZ + č¶Ř5|™×űő8í`śÉĐ,ôŽ%¸ľ˛F$˘ÖQ$Ň'˝ŞCcň±ç¦ŕ_¸^:ÂîSěđú‰ž÷sęVĐ'ŞsµđjŞ<:Ŕ)±˙aáj‰o*$WNww×MŔăűH‘žÚ0š˘Ôş;Á"±Ş= éßh(€Rúúéľ´ĐzoÇn(>‰˙ÝGűĹţö˝wĄo;—÷fçë­±îQϬČ?1ζćĘůŹ*¤ń=w‘Çײg0>|ˇ×v‹Č2 Pv"’;oŇ Ű;Ăx׎Ł”č.éă{ëZŕ–Ú)Ń#A¶†6Ů©Ů'Zn2ß0´®˝ň‚ś<ÉŮ/›i´s’y]RĂ­ďéúAg‚ ľŚ¶ŘŻţć#5™Ó„˙+t@8˘1żöw lŽ!ŃŞŻ3°jШě$ÇĹp ÷,OX›W+Ă!đÁI¬ŰÚ1ľW·Ž´4ÇůŞřuoŕ¦oé  F›×|NdŃřs×.Îh˛^řźcĚîrŻ©"A-˛]9$ňŞgmúY Z`mő}´Î:˛ÍcËE¦ŘŘ­tŰ`ľcŰĚ‘Gó2`,%ńÍ<™V¤5}ţĘ‘P±çOa0żH@b}ö:m* ó–-.«Ů`0·ć¨çĚ›ńcě91nÓ;D%ó ĚA•Ň_O€Żőz|óžăŘŽŽůĽČóÉŁĚSI-EŕtÖ\I‘G–C»–¶"Ą)ŢÎL­b¤Ý¶9ěD`y6K3‹ Ź3â˝d&ł Ç%Ő]ž ¤śeŢ„,¶’" }¸[RIFvh˘Ë#‰řb„ŁoČťµ6w^P;n .. °J÷­Ř¸*ôC 0CŁ oěw}¸ %“»bÖr«Už:ű ¨uŐ1Gźŕ’tâß4‹čź¨<ážđŰÂŮA3¶Aě#—Ó”á#˙+oÝUńBĽBU@2ާ&$ Z51zó8ěQ^8UÍ=ÍÖV.řă’Ç2oy™ýi:±Ă¨ť'Bŕs2˛ŰG“ ¶>r_§QhbDÉ&" ć”Ťś††b¨ÄÚFjT$©č!č«ĂÍűLžë{u…ôL†·|ôе¬ńËuŞ.]Ł­u±›LÂć›ظ">ÄćÓµĺöS٬˙Hř’ľlÜ7zqqfęšÝ2<Ĺ‚Ęצ»ăň톷ÓěTňÚřl&”kHnň#'Üř°yÔă üT䪞änúŻ–n–Ľ×‹H©éh}˘ ÜKQ›˙0˝ZŘf7<·’Ť2$3”ćTJëfŹw¸ĄX†ÁÜđ¨ö bău61Š®Rb׹*Ď‘ůPú/z.-nkŃÔť&Ůż“‹v8Ú§Šę»"R뼽JP;&Ůďŕ@ ,ľx şí™\(»vNžA{¨zĺty놾 pdMýŤí˙*ÓĹĘÓ’©RyÖŤ3⍽çG]žÜ;ń,:§)h]…şÁ^qŐ”rŽeQ^­ďŠ HłĽ…ýAârĂ"Ú0†4ł…/ę¸ Ăw[ĐZމÔUZ8a˝(J•5euč)V‘PPÝú_öÁŃ&zčţž˛E˝Ľ…&Ą&– Žvç1#ň_Ç(Rµ›´÷/Ú’ó«žOěŹýH„ŇÔ„°L‰—Ú*Utw¨taÉĺ,ŰľySNźT]÷_̉^—ěNÚ„Ý «ż Îăq‰‰zýŐAß’a?ćűĘ`J·ŚţšŞß^éÍpg#|%9âŽ6¸wg”ďĹ~·´Ź,xß<¶!čzÖKi":čÖ7–†Śh˝&®Ö¸‹A!ńĺU‡ß±Ă|śžÓˇ–†‰ZiĄćÝnďŐnú]św˙oúȬźG‚FRď î´îGö*©îfăßqköF\XôLŹ'1¬ë1ó–-@Ę(|’k¶q°“ŘÁuČ 5<â&`{±Ě©ńŇęĘ– [’›ŹßЏG¨‰Šhb/eŔCÂů)¦ł /1¬÷Łw`ÿؓýS2 űe7­řbę|«MkNVʧ…)Š•‰Ů±3„¸Zdbc›q,ÖŢ@<˛Ăq°ď–¦T_&$fd“IßΆŐÂY]âP;D2ąuÁ†ĆĄ`KM”2ĄqĆJWvÉ® G’ô™[2-TD Ü–Ąô)©‰ dX-TjrĆďT“34ôŢżß~ONAűĂG´ťąžĘž^° `M|Ů]˙Ł«;ô^űé#(Pněń"ó¨Čˇ›Ĺ^ŻxÁ]ľZ¤ŢŤ–`śLőWť˙|€'`ĽbcMp :Űö›‰·'wöPaŐ‡Éňxez#ö„ ä;r¬35âżvŔ×rÉş•2¨<Ů1±Ć6â`ţŹWĎd6©,Zšúí¨:ĄŁž;€  řŔ!ĄKgdOSwŽÄä6"‹ÍËŇ•/löá5’¨1Ř;$É_ű»ł +ZşvhR…zqř \PŇŚĄEb¸;zą¸†ŮĆ>||ÁřţRDËÎo2ĽŻlg×^Ę­Ńă%;1EWµđŐ §Ń“CN}"µŃ󌌱źĆ,7q4Ľ¤ÔÎiü˙Pń3ěçżŔěĆŞĽËĽí˘DĚÇŰ‚{• Y>%ĐĹ‚8z0hgś^€÷ľ¤Ç|(…[>-ŕG˝mĹE«`HřŔlă&âeś™¦ Ş­%”t3¦źf /giĎU÷LýĢЋAí]_ť9ZMy>nůY_ÜŇ/sݰ÷®%nJ@c6v+˛ÇÜIöÖZ:Ʀ#€ËŹ»!b ź8QW襨SĂ.¤dqPµĄˇ€Ů0Żß xEňéĺvž˘`ŠÓęŕ+BŢ\ÔĎB6;Ôň°§ŞäźQL–ďq÷•Qß|,ŤŘŞŠÁŻ`uňŞexîEjIčÎ%ˇ@î Łý¦Ł‹ŚĐ bő‰ÝA(TâhrşĹAtÔËY-sła_ä®kv~2› ÂĘČź…EűŹXv-–W·[ógn˘źű¤Zwµ?m̢řpîŘß:”ŹŔ°źwż±§Uşßxʱ¤Tl¦ßŽp¨‰¶ŠÂČĚŢÂSĎ·«ôf K‹Ţ®KÔÓ#N  ôˇŻ­ m©—0•˘§r˘I\GP8¤$ř<[+Ď?`C,5»ÚĽâůNÚ® ŚjiΙˇtĚŕoý5Ýď»6 ±Đô\ úöŮ Ť„IGłçAâč0+Ŕâ+{Ţî_Ěž(ăIßч˘Á…îŕČ«n`Qfň Ží}Aűl‡)g=–Ńj ř+6-‡GűH5’g˝UNwnŔĚźJR™&’€Ë=ëý‹ŰöűS†őĎDă±Ň5§ťü€(ńîÚ0úX÷Â?3‹bx@Ă—ČÖĺ´1Łź÷MOËb­ü"AýtŁ—Ö”>éGćŹ×«&śÚ˝úNS©Ď˘€ŘĄqę>iÚk!ík‡Ż)Ě·€őąwe'ôł×;ÎŁ„ó™ňź9P6˛"uúś– 4‰ýY·›=ŞAýČIOb <doj‚#8˝…¤´śčR€¸â^Ę*MŞć´K«5~•­,Ď˙A<9Ó‘<ß’ľ‹ßÄš"€X?A¦×˝b_Ťd&đç˝˝a·Ă‰îĺ» Č‚~s„¸Í›^:jv‘ŕď ú6|‘9ˇ=6m™®I—Âҟš-¸ŠBřó‚vs0š‡Ó›YůúĂ#±`5I ­ăú—¬¨@ę¨%§+}öŮËňmĽŘ›ŤOßH5î~Çŕ4ˇsŢb"@łşşk€„÷ 0±ŃŚ"óĆ”žm]´î«|uźj÷s ŠďĂ»äî1PG·ˇbÚźUFÝKRĽúW޵/ńÂö¶şă =k`ş-ÍTúŃŽ]»Ď® ĄPÚ˝@.t"ମđ,śŤcŐ‡8ŃźĐ.ý ź¸My“Ť/”ń€Š·‘0C+řEp^b<ű©‘¶ťYÄ8ÍŁ>Şč ›"€ÇOhSóÄv/ÔZ/Đŕ„;ď~†™HËÁ!Ĺ?¬+1í]·Ć-SôŘPDňp­8ÚĂáŃ~üO°ô /l|ŔŹĺć}”:?ńć˘KFš Ħ¨ŁýS$zŠŔΧďĎiÉíđč|‚ut˘…G&bpąşŇë9zźPR…4iá)éÝxJ5fđd ؆¨îXe§Ł7ŽĎOWĹ޷|aÉuéťaí|÷’Řem^qŚs?틸Ĺ€µÁ¦ü˛ zâ|¦(q”@‚^)Ă~ŘŹT›ŐgóOÖćąGéĺĆâSűöďžgűSěëłPk¸|+# ęfYÇxî3˛zR‚6řß á%_Zfˇęgx<ŞR É ·Ě^ÖÓŚ3ß'ž©ąnƶ‰˝ś$›¨GHe,1ń•gůšŞĘĐ…źët6Ťéi©ĹEŁ] ¸rţ×)Á”4ýŃÜD›%vöö™Ă‹¸eśLÖó°g™Ţ`ČuÁ{äšC4ĎyçRŃVˇ–hÎV3Q§ÇH~΢j‡ :ß\;J›)ő]ů0‚– ¬®'“ÇyŘäže¶jo˝ű ÄĹK1y\ůŐ,%âĹżŽżű—#t ky+Ž#Íĺš§Rrč­q‹$}.žt–ç `Ö{gće“„„ť´uJ;%¸®<,ÄĽDĐ3ëMw‘SjWîG Ząç&›cgň ©ćâ}×h»Cß= ŹöyţĚŻDt«×z‚űÂ;ń­ä%ť¸O(p5óÍď¦×ţşĚĹ,ˇ S€hwőRu•Ű~{ň+(AýhîôF=…-EXŃ|Śv7zŻŠ´Ś»‹Ćë†ciÂXíŞk%LĆźŘCţ¶8éî±ŐäWş…@”ěĎƵŰ%÷{„$~TŽŹç†é~‰ç¤—bqŔ’µ'ó-ŐĽd9=–ŵŮň6]´ÄÇ4ٲ/źÁ—rTŘŔŹšĹŘ“~´AźE'—”’†# ™öMČR©gX$Ý‹Y$M žťÎöššőSMŽ!8gö)°f˵C°*°‹Z52•ÉĂśŁs'÷ţß÷cÁ bX±ř¦Bß—ČŤůʆăiŚ"űöÔ@‹Qóäꍌ©ĎD/߈šßڵúE·żájúR8jzĂć_¶ˇ‘÷Ć[”V.dâ2ŚGď ă˝CÔľ5r ¶?źşáqüŘLĆŃČ*y˛üVS mÎÂ>42-,Ś’K1 P3¸Â@!ÔĺV%m˘*ČÍă° ţxµúŇ®cV˙CâBłĘzÝ!ť˘'ájjŹţ×ZŠ6ŮXâŕPŐÍl!ŻÝq¬FÄčQޤăáőÇőW™—çő>O|Ńđúűż?sď“֟ۗçôM>no“Ň|wčR|>ÍhSáęž>j˙*öüĆż?©yň}Łáú"˙+yçÉëO‡í®|?GŃđűÁ>OYźźÖ/çîÖ‚NőÖźµ_źrţB˙Ięň|?˘¤ř}›˙+ˇ ň{ÓáűĽüţ#á÷ţ>«IđýLχŢ@ôEpčĹM¦č¬B<đĚ~@KĹâxĎH›şX޸DŘ9ţĽbůlbčMkť§ť6?ßz.âÇąvďáČ vű&®D ”V÷šż`PÖSzF̰k*§vFĚ’ 2™›ď0°PFý— ä‰×y;!šëÚÇ™1ӖݲżgfüR‰#¬j$ćPLŕÄŮ_éażÍ<W7ěÜÄ}ßÇ×±ŮsŽ‹±Žóżp ť1žWěĐó1ź5ÔEô@Ét¶—¨R|§ŹýEžĽ΢tÚh@‚D ěý,—F%öűí™—Môu÷°›V@~Ăěăs|oS”đ(G »ßS˝×ąa×Gt¬čÜy{@ŁçwŹ)U<0ŚYě56exIH÷¤ŔîűŰ›¤©Ř^ÔŢĽ`&điz»M+ŞĽÂŃSĘĎpY?8±ó>B»0R"Éč“.ě˝Ag>Žh7@ŽKZORÖý .ŠâѤV(ĘçPŔ}!ŽřyÉNi\¤LźPžÇ?PĄ’`ťânńÁĹĤş¤ż‡H|Ďđ}Îş5ą3zl.4fxTOńăŹëL_–fˇđĘáAďóţŤHŢvŇ€zôTN¸±T*dË˵´Řd?Ö/.¤*–Ňíˇ#iPáo¬˘uŢęÍĹüË51=úÚŞúr"›ŤPßšA|aćš¶·Ăqc{ď _ ö†ńh(¦2 wńn¦ý­;#|pČpŹ NŔěřwî÷ŁríRĺ™ 1 ,Nâ¤k~®ĐଠC;3©ŽE.2Ť( í¶ctĺŞń˘ż{úe=—ŰŁB{Ęľ_ąŠL#;SŰYŞöÖ/w®A­łLč,źZýń4 ]üz#­˙2ÖëĂ™b¬ČĎÎ&ü˙+€ąR"<‚3Q Ms¤ý"đć°4Ź`żć[¶h €iau1®Ń­Núµ˛aL Ňĺ­öNĘ•_e=ł@ĂĺUř`Oľ‘]¸<8Ë'Ď3oÓu$ÁßŢ,ŇVŢĆî wş‘ŕŐ.Ę,ئšŢu˝ĎˇŘ‰ŕVGW”G±¶ +D_‡hvžMfÜ„’˙m4”ěçÂJ[‰s°„34Ęű#d>qĺ0^Ő–EůjnR‚..äđxČ@`6┬Ď65bFŚż¸©řŞĚSďżĆ„…UTS“>4]˙‚ţ¶MxŔĐ,Äß”äŰé`ĽGžśu”˙ZCş“®uĎމw=gĂ•‚FĹŽpu×Ěv}”繥„ë%ĹkM‘ÚΛrç Ěłu‡ ˝řM0ÁŕÇR;k‚ü‚úw ]Šč3Ý˝@ŠÄ}{ý:9fĽŃß»śżń©€ńjĆę±őb_Ý´ĘŁçsć•»ˇŠđy5VÔéhś&ly°čŠ)¬Ľžš»{ą:‡±kB„ő¤±É˛›ÚďM;·t’gš6ŹÎRĹFZÂŁ~ůÉ}h'Ą Č.iŽçZkGôݦÜ·`ĹŠ•ĹĐ?Î2xî 0_\sćHŔŔˇâZG)’cM•†x™óJ¤‡JîeQ Žŕ uőâćÍý˛n¤ł—VUśĘ`ÄJ&ć÷çđ{ Đ o[ç@ýÇ?^î}ÚuĐŘu+É'ĆkÄżl UqŁ Ňć|‚2ŘQ]ĺxuă—\ËT_ŃP˙.™ŕé¤ég+Î/L—!h@˛Ű!ĺ|„ô¦ĐŢŤťĹ롪ŻĺśDÂŚ–żőî‚Ű…ĹúÝ#nŐ຀‰ĺ˝|OQ ĽĹ»ňś‘Â…ukňôÉF™~ŚőÜ$ Rćű&Ë 2ŚâϢůňdCâHÁ‰Î)ŮĐÍČb˘]ÝţďUýŘÔŚH¸sÓţb*AŞÇÉŤÂÁ„­”PŹaÓáű1NEŰś¨¸X{)«š%N«„hR%ěŠ"ľ×{ŹąŽÉú5Żą«çú#-şxśÎĄ¸˙C˛z–Íř¶°ąZ»ŃšîůQĽ¬:—ıľń 'ďI #’ÄC!sÄ‹žüć†Dž&ÚaÉÉöúw_r´˛~${™lţÚ¬Lz &şh¤ŠöÉK”Ń}ŰžüN{ć¤óYh|ÖĹ ÚY ŕMŤ5ŕ.\:y~ŁoĹR é÷‰X\*Ľ 8|ţ™ç *O‡xěpwwŻűGŁ ů©Ďŕ5x¶ áT‡ů`g*k›xQ˛sr–č°h‡ŐĽ¨®\\ŐŮÖIn)żľ÷ü0$fîß©® ľh0I)â~řĎ}$Ţ"XŐI C^ߝƴ ˛feueWţVž>îŐ˛ő€ş p·«‡Š^Uoť”1\;®9řI˝ ĹëĐ?Ź56 –Żě:„ÂŤ-H|+jc­¨Y|‹ďĆ©Ôv¨\JfUď xX?|"Wç%ĆÔ ĽN¶óFÄé#9†Éü=k@„ŕ&FK˛®•e÷…× âčOűx5•±ĂVż'r| ·=€ýýU‹N\-Öq棌:ŮÇ»2¸üÁmź#&ÖÖJ¶ZŰ ˝eȸgʧm‰3Ŕ8Đ"…Pü]śnÇv~'55Ŕh,ßŐŠ­­ŇHťJ+ĘI›ç"‹Ü=7µ»ôa\®uaÁ(§ö®…aí¬ĂśQÚ¤ŰČE¨ŮĚż# ĺÍÍú>BîÄtU!>¸T2Jń™>·„¨C4Er&Xß'˛ümľ”ďkˇÓ.ŘB…F|ÔGËşż”1FŨž'Ďă—©ÂZ{­(JUTś-m¸ôŘçé}GĽę«Ît×55AqÚÓí˙<ŇMš{ |~^8®1Ö â]×ţEç™¶±+^µc>.Lřhݧ/´5e»˝c§‚¸ŤV‘Jő‰ű©Va­ŚiĹűM™lTc~{őŞ…ëęubšôCaŠĐ OÚe3›=NĎMI ˙ŤnIĚ@Ń8GWŚĐ$]‡č̦:a…kAšĽŚÜëép(PMŚí˝†ĐzŔü|EomCÉ˝›~EHíŞ}#5él˙l­ßîĎm»kć_µŕ¤a޶ř‡JŞí9ő űö˘I~6‚¬c%|ął<NĄÝ…ö´‡ż_ńL“4ĺË0Ů©LÚçM­ĺĂđ{őţΛ°¤¤úŕč15AEEb¤âÂ-|g#&˛|÷C›Č.Ě •şöŽřÔ˛R€CŚÜôéűËé1V;´^xXޏ@Îü!3"’mÄUxěÁŻo™°v}.T=Îjgߏ *XČŐ9ŹoČ0„‘ ź@Ü•··ďrző.Ý}¨‹{N<Ä­= ŕ~ŤŃS[ŞĺčůřăLEŞĎNQ¶˘•2ŁÓ`UyT9ťĄÉÇn÷7ů5¦ Ř$OłďrŘĹě'ş†qEŚ`Ç4DI¤Tfúň‘8s Ěý¤ąÂ •§„ÓxžÖűóţ€—A<<ë¤rÇüĎyśx‘Ž›Îó‰ţ¸—’ęřo)íŮߥ®q-„ĐIű}Ŕnţ=rśí†-äukřśń¸e;GúN IÉf°\°Ţ”8ş5»†î ™Qµ„wüîÚáMĐR¶žâ€2nR ‘A¤i¬jGr-ýö $â ß߼T„>8ЧB>-ˇçÇ—Ž »yű‚üO›ksIŃ“P'ÍŤ÷tŚr?qŐÂ÷É3Gç µŁ1P}C+čďę7€đŠB˙e(G,Mg»BU!č®~+r—© TYł»#i©-řx„˝U÷Ą·÷č8OˇĐ‚ůŢŻiPŚÁFS %éçŠOM”X)wĎšúCmʨ(ĺ(ĹQ„sPFá´Ĺ-® &á¦E#mĘ8ď5(Í_«;J›bE™Ág!ÔH˛ĹV}Ń•°Tc˝źĺÚřW}W˝ÁđŤ#Š.´Ô(ëŃĐwX+Ľ9-ŔâŇ…K´ĆLć{o Ě—"ÖóX7ٶˇ3yRPË&}]U*±5Un¸(ł’„gƨ7Z˝z ˙~!2Ȧ)Iua5š<@í¶5¦¨e€”J= ‹Şěű„}¤ügF§Ú­íŢ ?•úŘĽĎű8đku4ČE^.`(M „ů#Ť"rsąoqechř$ŐÄÖ?ř'Í~E •ż„”?ă®čg‡b<ź¬Ďë-űGM°›˙'PcR`1ňŔď첝t_:Î-**.÷dҨßá×ćň`âµDüŔ˝ë©®«Ó)IéĂÝ‚čaW~[ęrݬţ;yvł#—i¤ÔËĆÍciPh*Cĺ ě-!aÓĹJzńfćÉ›z–Ü×áU\éČT¸·F+ÓŔşr¨öDą7¸f¨] ˘Ó.¦ŤŮđč(ç“©{iËó·ĂŃŮÂDđ[9/nkÁ˝ş}ę÷Nň„y\ľ\~>t‚dš¬Żřn>!iÁ` ŁM‹Őć<’™¸Ő™ÉÝëń‹ah­˘dJdŕ˛ű¦^”ëϡ(&ëMc†Ü–ť˛îa'Čôř3É®öPJ:KŐ˙UWŔéę\Ň0­ĐTDg ¬ĂGÎů˙!÷y”ń+ mĚłÍK§Í"dEĽ#§‚ô­+ň­R=ţžH<šśV/ľÎ„ÉÎő§ęü÷bžŞŠ8›>PkRĂc śÚŤW2Äi¬´ęXOَôçŇľ(S” $©­E:ŻŮ-h/_kyŮLŽCéí?ĆĄóWă8V©‹é …;¤ŹčWM'%_ť6‡~Š×wN»|‹ÜŠľ<™ü)¬8bs¸J´cĄŽ—^á»AńäŇ:©˙žîUvîťcÔđ«pÄ.ËWŇ·­ Uóç2¦öa6őšÜ›ĂÖxT>KŘ—®źP¬C}˛ńpîŢ‹ô¤đĘ5/úĽćÄ~@NÖDtjýŞz€d˘Ž óĄ=z^îdq}«óa™ľ;$ĚĺÂÜuďÔ™w7kĆTµů:fiĂŃ­0ËB{3¶?‰¶".ÍîÓXůÎÂđ›‹Ŕ@’N˘¤Ţj_KBbŐa_ŮČ䲷cü;ľržŰáÔy×r)0Îťß˙řJ&Ą¤JüÓÁA€CĽXß< ©ç:žív–QŞL#pU›ÄՀ͌e…˝Ą=Î"ü=W7 :]va$NćHqÉ­żdV^8»Sżl_®%1zuľujv`ĂÝŞĆ9D-0(·µXR`I¸l”»(6[8TâJ•*$E—&ę%hĎaß"ČłěňyęâŚĐź[Éy(‰t ÓX{NşĹ<‚Ć__ĐÁ÷ Đ'O—ż–ŁňFJŠ)…ŠŻŇżşAt …“˛Ű‰¬âŠÍ'ű˘s¤YQŠŚz1c<]`ěĘłöűí'4¤“úJ"Ň7Hťmžt b\uT<$)Wn·ăäÍDŇÜ‘fZ&C÷!·Z‹C]¨É™ţŐˇMŮ€p¬ßś”f„ řIââů–’(ť;ŕ Ő[ť«űPPAĽ¬kć×3hŞăĘ <;ÚŠ§e2˝36d{Cf'C¤ZŘ Č›× ß^2d~ôÓîťâBć1ĄĹ'îą,Ô}ç˝ţ6Ą ó8A¶0§ÄoQm\xę¤5ŽŇĘv >É·v9EĐťżyU!+«F®b¬´Ŕ˘öî/)ł ˝ŹWpő9µ88»IŹ«ÓGĐ0“Űţ=$béÇ"V¤‰đv*ˇé) ‹¸{›ĎN1>¶ŕ•ΧA±©Ú†ž"^w«ŻĽÔ9!Ë„Ŕ»5ÉűpîČىx=T> i»ÇřŃ ŕłŔŽauG+D‡+®ĎVĄ­K`™â¸Ű.ţ­3ÇT%FöďüŤgŢbuŕȲ÷­Şż&ŕ Jáć ;,Č÷’w9>ˇÂż×1Ą%čĂPg%!ť-íÍ;‘wá=Ú±L± Z l¤ĎlŃ@<\âl'¬CŠçoO.W WTĘ Vz83(1a#ű|a›ß”2ŽŹĺątËęÝúíWVL}u‚Ro»±¤â4ľz±*ę¸Oâ쓹$[$a|ěD†0ŔNE„t¤űä;z6|YÜĆ7ç8<˙%˙b¬Ńq ĺ,ć?‹Ďžx*­Çó1ě‚’ČýŠŠ˛ŮF“ŢZĺ­ŁÁŮ ígĹ‚ł®«9l—_©4–h \‹Ń`ÚW †âW@ÓŢ)¸ŹíÍ˝ÍE-p–ˢ‡ż-RUÖ‹śr䇗É0~[ö ;0}¸RSWÂ[IJNú+{xŚ&Yž<Ţź;Źk_uĽ©ĐúśĄaM/żí3Ĺ…¸ńYŐšGHţC',«ĎÖI?—J)䣌ꤰtă 0Ľ®Ë †‡l]č[ÜÂŇîâ$ĂoĆČďüéÎĘ}Z.ꏅfT^&*_6ŔÜ ŔËăóľ'ĽÜdω@~ÜXÇĐčc@7a;*25ÂřžĄf3ĺ©*m‘ ĽJ(´Đ승ČI¬=/{ě0F@Aë˝ů X4ąéT„+ěš DťX€Ü‰_ľ‹Ĺńqf–˘AĹj77‹|dë» Ôőc—]yáćnÔ}Ű6wĽ«ąrOć%Đ>ŽŠӽѼý>˝ ąź(f‹š‰‹MąEž‚‚;;iTŞ·Rý‚5řFKĘGľ'„MńşĹËÓŞ™qé= 4.gĂžŻI…úťýž¸ĐŮŮ0ma[˛äP Ň0GÁŃG É!š›)kˇŐ©G–ěT…eÎť;nüh^Ö Č{ž*6ި`kE)+śăśh] Mi‰T5 `HŽďfW׿4Ź‘Ú¦éćCâBw!"ĽYOĘÚD}1n0đÎč–r塖ß;w6EýűX*_ﯙ1÷U–ur–<˘b Ëôş ’6Q늝Ŕ7řŁÎ¦ŃĽç1Ąű<¶â†}5*ŁU—}bĎ:Ň1őJIĺM ’ ôí2|Ę$’ÁL¸ŽµŔ„G ‹őEŢĂ |ŮX ůý-ąĽŤ3ZٸŢŐť*ĹůeŚů¶KÚ@˛•5i>L`pîR+ ž¦ ÖŃÖ”ö˝ycŹ{=[ŐŞő]QäQ¦¬ĽĚN´Ňç’·˛]ŞöµôÂ…Ç»zŚţü÷r¦*UEKúľÎá§OúKPPËí×卪ź=o'Ĺ€€J6‰‡FŰÎ;´^ůúÓ/uô‰•ôAŽá+—Ű•äQČ(ީʵ×÷¨lOx«űu¤’xž1ż…5ő‰—áţ~ÄŽüYúYg4yű’,[)o6ßÉőßs×(lĹqˇUa·ćd\ăgińxĂě@z…uźY¸dA7·`!ŕ|ăÜůG7ě"—gčü»©3ăz?nŻ÷©´LŤ5”Evjz(ÜÎb°¸óÜ“˙INX©ÇöR4śRéĺ™LpCŤŤßU_Ë98hŰľRˇuaaŹĚ ęö«F–ő.‹ŘO«:KXq$˘ř±EGIyt­ ľg2ţp^ St…9ýŚ.ěč%č4ŃÄ–gÚ¨ŕfűÍ â»Ů1Tďçč¨÷—ŃW2U.ŐřţżĂ—í©Í}[]$Řę͵¨KóV&S焟®lÄ&rCa«‹·wp—hÔ+3®8 KľÂ$ fiÎkW˙KwĆşúĹ€ő­Eš]Ć=ĶS°ů»JQą bĐă~–8’׿ˇçfž›Ç~u—hȬ6Ţ®Cx=ŰđÜţ6‹ÎJ‡‰âŔDzĽŤ0f[éőŽť- ťÖ7€{|ęż»¶3ÉG˝"CŰwŇ^ͤDżĽ0úňţ—]Ţ:;€ŹU"$ŕ2öŤŮ=KąyXe?ŁětRMŻÜ‰Yâö\T§;˙™Y=pIňÇ-ł:+›ZčˇWiM ĽźścY€ifÖS÷HÔ5pmÝQŕŃrŃŕ°x†#ąöWH«ľR1U@Ý<ŻVT?ř™üNÚc:»ŕsăí~g G{w©ЧÓÄĺ¶íĆ«¨d.Žj™TTýB‚—mĘHćJü(’j•`"ʲGű-¶ľU=ď‘Iź†&čŮMđŻv y{l¸5ÚKoäbÜž™7„<î7놷ŽTp’łô?~éăx ѧ2}4롓Óaü?ĺ+śîďŰŠźŃnŕS'‚BBďăÄX"ó‰i č°wJ§y\(X›WŠS],/Ś\P˛˛­}ş/öL‘’&N5µýČS|Ó¬=P”xĂ ř7ô%]bňŔ˝^RR€-P Î _—)7("ą¸‹„őťń7R÷ëmZ¦řjŽ—őÚ¸ő{’|m†p Ű ®9Š«çw¸LÍ!¸Âή߸>ű\ Ń 4Sd“¤ë0A]ňZ¶ÓéĆő‘vÍ7qΡFŘ Ű/y6o$|Ô˝zżu;•ňôLĹ ÎŚ†K‘Y6Eűx%Ň/iDőŤ‘«č°ĘĄĺ”řk@' Gşj%vů*Ł*ô$¶ÂŚţ$M%Č…^k¸›‘őh\ÁV ć[ŕö oÁNhj ‰4ÜŻ°ĘÖ€ýĺżôÜĄÜŘ4íD÷@÷«ŤZJ Ł©‰Ř—6Q&]u˘!0c©ŽqOÉ(čÚŤ»'Ţ2ď˘]RÚ† – X>!9`Ô$~”Ĺj fźśAk DĐîŁ@ô^ÄďB®«2.±OŁ‘˙E+9RjV·ü×Ŕ6eůOĚ2×¶ d7jŃ˝ ¤Hŕt wÂXV¬´t ›ČŃŹj"†jMţ_µf„@4i … )G?lˇp†•…@ ˙EôĎłJPuŕkg‹;ZER{%g(ëkgN2”Ȣę.Ë{°9Ć,}kG†ţ@¨ŘË9I<Žő+Ý`ʬÚhk‹×Žx›¶toW`†o!{¬4¸€´¸gK~ŔWîÍOÄ&aAŹĹ¨\ߝℚ–\ÍĄH)…’–&ă•vŠ…nq‚ů5z¦ř|G›ůűĆŽäuD±âSëéĹŞ/;&¤šsŕČ˙~$·öÚăěś]¬¸łŇ¶˘ŠUw~řG+¶4ďŐYB ¨·\BüA=í x´îÝoK‘łHR·ŕQB!É8Üq,B NわtűF’CÍ«€ –«l„Q%¦3^ÉŤş3ţ‚É#P­ut+ác”ąxźĄ6óp=|áé#‚ŤL׼đ\ xçŘĐ×`µZ—A3;éXôů~ŕĺë>dąJšŢ (Ť¶¸čŘŹdˇW+Ś*­‡}>Án bł7p‚ŢČ楒âČAë‹Ä ˝˙oNF¨ÂëînŢZ|ż°kç—qŘŤzh,•°kĚţuÇB35dđŇTŠbcD:ë§ÖŔÎĎ1öŞŢŐPĂsGf°0Ž2ś6NŤ@·t–˝ôsč~Óń.űuÓG(ĄálʲEA:ŁÇ\-Vˇ`…ż)tWo'‚đö^3Ů/3ÄSqXůyę{×ňsŃśżLâ:«ŇA÷Á‰˘Ő[ůqŁ›mž^f•}ą{$SĹ(čhéčÔmAÍs/-$¶ â Śr­T(©1bnĹąµ–Z3WÇŽiĹbÉ2§D:ł{c6Đáşk?î™ ş>·PĄń\ ľÄ˛qj<óá žüŰ[ÉĚ*)§žf~<ź7Óˇ qv€éÖ#¦•—¤źj×Ëu˙Q\:SÄŃč[GŻyÉןě/W8,ý¶ß$±ŕ4ĆÝĚtM4 -Ănf5 LÖ>Ëobde3v|×űŤEŻçĸ*b=‡ŃíŠ˙|(† xlő¬~@ĺŃŘŃ.Żă\?:ü|0Ĺ3Í™I3Šh†AČĹ–e6Rşŕ$Ł«Ôu©őÁĂąáµ»‘Đ änÇÉŔŮů•šŔ,ÝgÄ÷[,uHd^ăh“'<Ťţ!׌ăpƟݬ™šçf4€­*HÓ,a ’Sk°U0ŔĐ'XýG’ňlë课üqł©yŕlĂa™Ł{Ď÷ŢňťYëS…eu:ť{pzĚc‹Jgĺ·ˇ$IÜ® eżHĺaŔl˘3ęT†ôŕŔ «¶Ĺ …‡üGÝ!d’Ü&!÷˘đâ"žŤ>ȉ ĺëpŽ™¬-cÚ0l¬÷4 …Ô§d>Źŕ§çd ´řŠóva¨XĘľŘ_Äy(ΙĽ54Ëĺ°'/Ëá,Vá3pµ{škţnë%gĺ[«)ŚŢüŘúč[»ařá UŠĘĆnűfVÍ$[óŹ`–] )ÄŚ!&h8©´űL›u_dYZô0‰E~3,ě[e*mä ”j:(bĺČ0e¨ r[§őɢÝńS ÄE“HSíŮ)YĘ2`đžĐÔź»Ł*•ŕ5ĘJ:.u#wWÓ´mq¨ züĄ!UĘ[çÄłlÝ– ÄĂ_FźÝ6cÓĚü ^č&oyČĎ)†ÂŰýÚČŘĚr_qL3((3B·ć˘±9ţdńccš ĄX)Ŕ^ńŻŻ“-°ňźô†súÎ˙4Ź~ŤgQ¦ź´_ Q{őOü^Ě„,D#‹PÓ‰WĂjdŃ`Ö_ë±Pź ¤a…w3Ä’ç4Íľ!úé$ť>BXĺ+ąňË®u/ô)°˛ťâ¬!ń˙†'µţ2–‚5r`şř·!¨´ńĄcá/ŮĹj˙;ćVŃ“‹‡Ř ›z`v#JĆ@ng]ąČEŰ@n÷ů{5o Q†° M§(‡‚­?ŹXk‹ó5S+M›ýVéG)HNO(-®Gb<Ďń…Pe’”§1ÉčîríR a2}óÎţf_sÜzŽ1ë źHî3-·˘wü Űß ůÉGn&ŁŤ_¤0ĐĺxÇ1ÄńłŐřĽčĐ‹Š´äfQ72ă;ˇS.÷´ŰĄ`‹cŢ»ľ{ăŇW6±Ľ´’jĺ '€8ú@íHş~0ŞÝí[âŕ[Čw–R=f7 Š”‚TßNJ[ţŇ&YÄ^JÍżOĂ]Ä«=řˇ!wŕäÇwX轚”ţO˘ĂŔC…«ÍAz`Ňîk©Čr3.¨ŻÜüUť7e*­ÓNÖŘŽň B’Óé…Fgiá˝…wƶ5Z¸x†i*ŐÚ4ˇÄÚŢ0çüKŕOwCłIqŢxö) ;dGŹä Ął*RëC€ąŘ(QV2z?Vf…4“ľŠY-Ť:¤R­ňĆg•`–E±\éLwÎű7ŰLLaůJ Ŕó%ĄÔ°‚h‚şç¤©ň,ZŘßšk©˛?.ÔŢ´<ękŻxIxrŃ"xĹŇJ´ĺH“_l ÉÚ­ÁeíC ÍÁĚZ¤ĐéW}̲Ré-Îuąđ›R$`ĄĽÜôyÚO9đáRQ}@·¸ťŕkC,ŇZÂбÜóęŠuLGglýó8N`g@5sŃňŇęşj}»UPIő âü×ÝÁ˝Ö”'č(‚°&Vý<+´–˛‚§ŽHőműŢą Źô#ϵ‘lŤ)¦“5¨ŔVTrŕăěB·59"¦7"Tę…śWęw?Ľá‘čŐĎą›đÄŠŽ>š•śÓLě 8 „«w< CgČń†ńJaÖ™A« mŠĺQö˝|`ŕ0ďI‘BžqjŁÄ µ!ěżtJíZ±˛×ýU•OÓŤ¶]réâńKŚůą­őżu”žłĺICdá“]eö»Ę¶tťhĐ«tćĆá{ýöă˘ÄuSÔÔ¤™Y‘P/W?ä!nbnŔCK‰9·.~ˇ«Ń6±RlÎĺMâŇű…‡v®8 Ú榥ޯ€.mJ4|©Có+\Y–oťK‡\-˘’ŔĺdNV\É÷!'0;šu-™pěÔ2l+ZqąËE˙5' <Ó˛(Ţ‘¤^g? çG¦•SpËfě¶|‹)Ň%rĚ>ę[)ďÖö‰Ł>9J†ŮńÎDZr…5Çś˛-Y=čhB4Ee0Ź–ůÝzžô eĂEŞxZEy,É­°ĚHŞ}…`ąË\+@dKą5ŐJfµwľţc‡×R»5•JJĘxťÇ»Ż„2ó¨=ĐŰ e}dR+d'Éűě\ěÉŇ#M1řQ{[ć-łiŹCסeĺ‡i )YŽpî9PŃ…‹řĆó*ÄYeNŢ,ßgé®G­ŕXôß: čtběúK öXZ[\)×8PŁčŰXqM ćč1ęҡ¸ĐŤŇŁF ßO}’ý1`Ż—ăęM°)Y……ÂAč¶€(”˙+÷€ÚăŇCź_ˇ^Áf¤Ő‡Î׆‚é—Tâ=čďM\^K—bů€RĘeݦđ°;–©Ľó‡ˇÓë9°sq}¶\vq•ž…ą>ZńýŘ|–î=PÍ~Lúđ”äDTÝź“ ĺŮÂöňŚ2…éĺ7%„¤—ńH1ĚźI ‰H—ĽŰ Śő_YHZ|SˇtÔ=®ŇąnmgvWţ†çűlĐ{XTëß>™s§Šׄ%ú…brÝČ s6‚žS˙ u´†Ż‘_<ř!×Ö‘´oÖ°ű…>$Ż«TŽ/ĘyxľŠC°j b@˛ —›­¨e°$7ĽâÁCĺGšPá=ř´!*pËŁ_ ĐŽ#ŤM ąÁR±ć˝÷o1ů}ýé«Zż 1ąřjŇ”G2‹"@^ ÉŰçD¤J/¨¨»ĎD«~.TŠ“Š@«9¶ĺ?m7L(Á­ n‰ň褳-é:±˙^˝ Rë7Ţ5‘š.)"•ŐĽ0éŚ5]Ä}·–zk’´27Đş¨…! 8ÍýY¤o@ąŰţ†ô>Â] Ł©Ô¤ů˛8׸•E¶đMjÎçŤI{üŰŇľęăî/±ř°b3úĄ5vlL_tnq†D¬wŻeu@B9\ĚľR°uńžýÜał I—óáŃÖ‹×úd7ו z®Ö¬—ü©Ŕ PĽżÔÜŃh˝™˘mí`Ç’fkś8JÖů ;2†' Á”#°ö…ó4gÍ2Ľí^"čé:u§o‚bRĹ’1 Ş#bßwf_”^((G®wo{ń­q€?ŞŃ"ç켝CoŚűQžÍăgźŤ¤'˛ĹŤ}wÜ—vCpŁż )-:âä°VŽáĆťŚQzçő»u“Rűc{0¨GĘŔ˛粽ĆD‚Ą_că%—–ńtň_ńÁl[óßŮh‹ ¬ nä®ĎÜ7’oAqfżŞ¤iQdŐô%˝,t}x~udu|´’mW°Ţ¦)vĄlQŞŞ¶ ~#Ľmś;Ź-y˝´zq‘ŹiV1Ľ±ő"j“ú hÖQ.íŕxŘż­8˝ŢDf»ab Dt~Ĺ_ĐŹÖężÍŚR.~=^˛?dÄÝŰ] ©5M}Nô^ĎęF8üŞđC]fŇĺťOŠ-ä‰Cüča†)‘müŰŕ°÷b+Ő„ÎľŮü#äx•Ĺ—fŐšân™Ý”1)› Bz”>Ć Y&~yJ°.iç[Ä4A{äzPÁŕěD4؉Ü8ˇěˇ¸[$˛çFOšśˇZŢă×ő`¶ą×đź/a˛żďě>aKŠ —bňě–”†…½vŕěĺýŠÇÎłLÍ>ÇCw4ńă#r…ýŁ?l€ †h¨űH_ŕeĐzŹHşEHąëËnJ.(JřÁsŕ3î=†1 YJ[‘ž265Qč( .­MňA¨öţVꆏ™ĄGŚoŐ.A ŹöŠéA¦˙Ná13î7ÚKmĚ~»p ŃD}©ŘmőşŁŘbOZ‚ů-q4*jr==6ɤ‚AĽ‚ý0­ć\G bzäŘżh€s6›Ô8^ĚLŕÇÔŕń} ‘ż6 ßĺňÝWTăĆ_ł˝ĽŤűĘΗ •}őÖ.ÉôCÍŚú¤ŤHcq-ŹMÜhŃKIVŤD‹ůĚqĘ4ăB˛¶)ĆâÄ˙RPFe0Ű‹OĐ1s#ˇ\ǤçBŹ F?śÖ¶¶Z4î  DLč–FΓýşat€ĎɆđt]ű‘$C!eLhµŔŮ)Öm©‰MÁŇN÷k±9g;»¤×*‹ °&ŰŚ˙{ńr9«Ş˘č^fŮýďÚ ńĚÉą/ĺ0oęqJ$#x(w*ă—Ĺ$\yäŚÉ)?őG<łi™íR´¨¤ńٵGž­Ćź±b‹‹2.Ő­­9^‰©Ŕ¶hĹ˙ Š~MF^ÎľŔŠ ~“‡"ĆuiĽG0ő—ş!ó$8;đ™[A•I;Ş«­nd1 ¦^­LđJ€Śrש˘‹—Ě ζ¸ŻŠH(NËÔÉҵ%ub«Č/¨'Öń?PŞí¬KµÔÚ8ŤŻă§ÂBXÚT HÉRwŮh’G;Š?ň7»1;Žůˇčäľ>–slQFň-ĚńĽťxj…—ů?ý¶`qú˘ŠI—öŮp”«†ĆYťÚk9ŕő\F lÄň6Ůw9AMśĎfF™€çţkr"fZŕ@[)”P†-îY±h&¸˛ĽźčG¶:/9źµłî-=ńáÔ@HÎc__«§7 Yóxh*Ž. ˝t‹%š`4Ťߪßđdxó! ŃĎżD?sˇ«FÖ&ŇA>]8AĽě‘˘f#ť‘2 Äőku<ß˙†§ăM~'â?Ô:Éę…ä1¨C:˙n :ŤľŘ”ŞqÚš É  Ź$ď ‡FřŢräÉ0OĆ^fąţąş´®µG„LuLf=úQ™ [u°e®# ´yŘŐJ÷> čäöĚ ­<öD(ddÔ«÷>Os*6dY%P„ âpZÚbşĽŻAé9ţĺî¬÷R Ö:üě_'´-E|yXCţCĎvÓ#Ň3bO0ĺhR3”zRnďÇďO1Qńľ7]&ž=ŤĘL‘Ę M5b6€ˇ”ď‹0 ÓVP|€‘ÜŇŐNÇ\QřKł9ž?ĎóŢ­SOkňjĆĐ{ě  ­żŻbcÓ€ŽŔćC§ů·VŻíItS I h\vNVŇ@Ĺ,âYŠ˘łăM°ý¤–ţÜ“tî'Ô(ěrW w=«©é1ëÓYëąâh::¨“—‘î$é32żi•€÷¶›ŤI¬ÓďHűşč=”7Âú€g&]ýż]—€ćžćA€öČç݆l$bާř›s6őŽ5}‹‘‹“W­$Rd†Zč­vŔŕÝŚm¦-걎9‰ď^TËm $®Ź1*ŐOR§ęđĎ&|qĐŁ?ŚÉ/¸ą?ĹÇr[FÖ<şgÎň·7¶Fô¨Úîu1 ĐK4‘łućëŻ^¶5ťOé »űŁ•\…pOUC±ĘÁďŠ,Š ż ü2#śGŹ·zý\BµsnÔ‰˛h?§ů :h‘Ž}óůb—KőĹ›b•[Cř…ţm袶8X|ąR[ l'ŘÖ‹ýń‘í×$Ěl9 ‡´Ř?!¦‰›ôíüTíTý*>ň6Íe’0HzČďđ,ěŻ˙TDŇÚrlVY6ť íµxU2ż2jG…ąßĎ"‰źěŹeúcáĹłŢűŰŇhu][YT%ú§6SŕA(0Žü8Éę~áÂęĂŰŮ3Öh2Ň×ËŮ l EÂá9ĂđYîv%٤Ľ‡‰ŕ.ŃźUBŢe9‹ÚZµ–wŮ{__2™ĎůôÍś€Ůq«Ę]Ł ozĚWď+W ΞţSĆÂ%2yĂëíiŹůGW[ěĎöŞXwŐú,HZ‘Á)ľlŘXý4ňĽ× ůđÝ78Öv]¬ÓiCđ÷| Y¸b"ë ßÍ»uÂą-ę¬CţÝźÁWU*‡mż÷Źřd‘Ż áť;uńx¦â•*řVK '>{ҽԸ¶ö€šÓŃţeľ-Ů…îÄLŰî¦3¦Ş>ŕ[Řĺ"ľí·ËĘ˝ŚůüŚÂ–ç‘ ó—ôÚ ŇtuF‚OŁöÚŻ~Îů‚ĽlY/hŕ0{K[EI}•Đ$]Ét?4ť=xÖQź;†2Y´Ś0"H˛ĎLŐSř{eˇaÔůŐRN1tˇy0Č!ĺ€mz‡kj7š4rµ~ĎęŹţügľ8@ľ+ÚvĺĺÝm 0ĘUxÁ˛¶ř5NgőCăÝ9ąÚÜy1YçĂ1*Jnľ?'„'Ô˝ĽŹúŚN‰žĆ%g­|dĎđUiú‹žÝ9HR†1zćs`Qď–X¨"(»,¨ÉßS$ÄŞ4±Ąî9O ţxŰL‡1wś˝ȦíťfŃŃÎUÝhEŢ–VMÝR»Ź3úÜŮSiŤ»ą]'ź&oćµtđ¶ŹĚY— hi‰ÝŮBŕBCQ ¦±î>"É č Ü@AA÷±M7-â'°_ÇĆa?/)äÁKŞŘ¦BďPzwDÜż[C¦EC+yüŹ^ÁQU˝d˙ &dpÝ6TŇĆëÉľ/Î ź=-IȦľ¶™€Ű8Áăô§‹…qr/ Ęzď0ŐŚżš÷ÍĎ(‰TjˇŹUŕtśLÔ>Ś”D^Xîanaš;—“ ţ̶ćů.űQŘ8őł4ކËŇŢ•µĹŰh-"ĄyâśĎ}”ź©ĄťË?ľ-ĆxÇéAu»p‚׌:ą#óW=^""ä)73†mÍ*Łéy—¬”HdŞ!?Śăky]o(z53°ńÓ.VŻ˙H÷Îks;V+éÉ+B’'x?đ_©™főËqť˝S~jl]áý<ćRż_ ‡žCŔŤ’sňO}>ë•ü•°tźhÚwŁ˝ŕ>.ľĚQF¤e¸vŽČSěŻÔXöË’¨Ď¤loÔěńI¨Ëś¸T îścöx<,¤˘âĽČĂśQĆ ¦·Ý°ě}!.¸[ń‡˙˙?2sőş‹ĆŇäŘ[Ř­MáF)¶zŞŞśÔŘřĂ1ľČ2ěĽjÉŚć'Ô_š\úQ˝m`ĺŁC‹°÷1R%Ebĺ4ĺ^i?ů:1 *4ţ-˙PqJ€Ľ©F>em‘LdĺękEmŔh]nëÇÇtĎWM0VfQ-Đ`J±ŮXř­skü’żNř85ő_·TĐă"ŰÓ@(?#ßĘU©P|p:‚–e4ŕl@¨Ůp¸ťREłř˘–Őö ¤B´übşžÜĄĎ%ĎC§ĘŘOŻúÇ{Ĺ›šžxhPźô|Đ|l‹VT‚|ë˙•ÓˇŹčIugőr XŕőľJÎ˙ ăîłť¨|†kDc`oĐČ2höyF đĐ ¨Ú9»’*aś–ź’h!‹-T]kIIŕ'm5ônőj$ŕ66)öAvŕwáÎż^.»řI~Śý¶™B‘kŐîë˘YűđC–{ÁNEßŮzh®ŔĄww"_ęĎW}Í–Ůež‘ŕý,Č+O đ †q˛<Ŕ_úŹ ę¶Đ¦Tňččó*1ů ?<| ĂÉŇľŐŮÚzz 8Ě™](š¶Ś)óŰM‡KŠŰj׹“›ł3&"Řn€ýĽCŐDőrj’-$•řŢ·ŕ=ćŹcl•Ŕ8Ű[ŞĹíŃ&CP Ľ»Ďź¸dxlĂqĽRTÔjá/şk¶ešâŘe‚LT?€T€n¤·'IJńľóO&…%młŐ^MFg€€đ×/móuËKč”j­ą2 Ŕ ĆmýaîľĂÍůvýR#‹‚HÂ?EÄG[Ďdźçś–‡Š;VżŽő.)ď fż Ä˙=Ő_÷Á‹;"÷óâńˇŞp-6ćĆJéĹ?śŤŻ?hu‰ć–żűT‘ÍÖďA-VÎĂoP=żsóŇ#ÂÖ·–¦uăç-äÄh×YňELš+*cŮ^%„Ź"*áŇÓyÚĘKĆĐ´nřh%l¶Q@dc‘r6A¸w0W FŻŞËÖ]!‘¶Ŕ üHź%ŐTh`TEac–UeĚe»ä˝ŕů-ˇČí±ËBą·S‘4łţVźQIúgÁfOšwĆňhZ~¨XđѸŔçšoX9¤¤ÎŞ×Ď:ä‹ÜŹńű´ł$¨€°iMJsNĄ”x©b*ÉşT×o{­ Ŕî(Ďh*KudąEčŁ<ŰjIŮŔ:ß÷¤7n¦9Ţ2ÁŤŰHç`íş:ÄUłM%[ĺd–-hŕŘ/2ÍńauşŕDn0PE`„őĺçŃ·M0!]{}·.ÉRÂĐ•PČşNfС­ŚńgŔ*"Ź© Ž˝ŃjkŽJŁgCÇČłť»UqW‚Ď^ĽąťcІ3¶•EX.fڇíÓÓ ś!Ă]7NOѧu_Đwą@ VgśÉ\ó—'tH&)Ř”‚Ł OüŐą§»:$>«´g·{ŃŃ,űŇ™3Ďšę“``“!%‰oNĺĹĄ%™0±Hł(™Úήvő93TŽ5´SN!ĎLxüz31†%xÁ^ŰŻď¸dřěAƇ yŐŠ×çĽ •ßY đQFoް}ţľ¤1z3îQyŕ1N ýô‡ď}#4˘ŮmI‚YfŔÔ °|éŇwý}ľ˙'ĄČě`' M'źVËšňťĂc”áÎÇ\xĐő.mGšFj†Ťë(ňfÔ ®®p÷”g8€\łŁ­łK| :­mk"ß—Zăvz,ńB `˝ß2…qŽÍÜŃu%UĘáĚÓÜá8ôĂľŞżę»»×NŠ—J«ÉبҺöHĽXÚič=&˘ńÄÖHRĹ#€ż>g§VL5jΕ‹µ Ô{[Ŕ/­żKQ°DŻ/üwDĂŕIĎľĆô_JĂ~Jfdç¨C~‘JĐ%čQĹUüꇏjŤ+]1Ť÷÷ńˇoĐšĹT—í˘ˇ¦vvX6'lîX xqsüä…Ľ„±ąŞş8.&ÉaFo⬤GČo^ ±%ČľÓhNĂ2 ‡‡ái™7b’Ý;RUËe4ĆłkÂţBĆ`t +UTҡ«—xőčWę›±¤,#WÎ ™…ÜýfČá˝ę üätßľ×çWÄöe ŁÍµ>ßń¬ăab5U™‡™w6#¦äl"&㪋ĂQČňřQ%Î÷YaĎú‡„@Čű˝¶7AűţLkGK\a”RťNwĺ”™đŻzéźFC§S™;<ç1Qütň>â‚Óó˙}eăűCJŐ’«¬02LÄ1I& ˝ĽÜşú šŽmÄdÓ=V~‚éâ«D2‘S-ŐÂpňn-¬>átۢߍ­ŻŚ­X»đłzˇ1ˇV@ĉłXC›‡f·˘Ą¨qGj-i0‘ü<V=Yź^Ł5:1éĐxěŠqăxĂš'#®‡N…ś÷Zőcţóď«[2ËvCwj 6š~?ÉŐçÎ|ˇ“Љ>S"ĚÍďڔ۩%¸\ŃF¸•ůˇăŘż0âç[4‘k8â^5{稙ĚU4€˝ŽC†[:k?ŇgŚQES{?2C~ÄôO©AѤ'§de·Ĺb «,Q—Ôa8 |©"Ç˙TßČeoŰTÓŮ˝eDĺó7¤c…"âëé ¦łÍ%IKŁp#»áĹ l \Kł…óg«e,m„ @ź>Y9ÉAľšĐú<«R˛1lľˇbDq^â•HxŔČÄ}čjľ€˛5€vÍČK[éÂ*…,žŞşě^ѱ¨ßşŻ€łŘ‰~`Y—,> ˙fý•¶ˇßű_° é(×+zý•ŞéC(1Z„WłŤL…Äô€…w‰JB5÷x`ŕVwćë ĎŞ š+Ű×]Ť­>\5ăOĎęI“ĆńA8Ü+gŁôí> ĺŠúŘ:p8_¨ŠQ>îčXęeqÇTęsŤ#“Ő3Ó©Ęřzé›;㲵ňŁ[Xb>ťýá©đŞ'ý­ďiíň`'”É 3wc­Âë˘Uřß<čs¬ăßĎG?ŰşĹč‰rÔá&Ęđ ĎŤ'¶,o!J”˙óî® xVr†0¬ř]ÍĘzúŃ‚sżËĺł/Z’€$@yŕŐ•ńÁ`Ü˝ş]\ÂM4Ť´q’^¬`©Óă5v¬¶ťŠŹSa[˝xÜŁW˘A°Ęy×ÜíôČ@ň‚o¬1 /l^OWĆšśQż¤m]*`Ô=Ř4tnšVu±vd2‹ô¦€ČA Ioŕ<ŠŞˇÍÇČ#‹żăŕăüM {`ĽQ›sc}YÝĺÂýÜióNĆç°hź<>>z~óiÁžQďt1nš&Kĺ+5SőŘž÷Î@ův]Kěkq"JWÔ€MC˛MŢ–»‚+-ůlČŞ…•@˛ßÖ N˙-ąJ(‚«L&_…5‹—™Ó¨ŁÁţz€šľđŃşg.k}é]Č€ fU'ţfNÁŞQPIŚŃyI«Ă=ŠiD‹˝hn]˙WŁČé¨1ŤVa­!ěj;*~ˇĐA~#á'żµi/j[ÎĐSkL}rí9LćHZ E¬Ţâk˛ýúš*šŇ€bst_ţ#ăČO!}W˛GΫÄkßL<2qšč8ôuwn"×Ň<;ćSčuđŇĹQ÷gDÁśMŽ7ţ|‡»ŚÔŮR¤„ŢŔ–|®3!¤¶,ĚT›Bú±ÉÉ]¦ÄbůL–ŇÔ»ĚčŃť×ÔĂ"µ‰F»lXnącĽ Đ(a±A8č:9/S Ec\+6.–®Đť-lĘęšs:opQSĽRŃ+›ŔPS+{ZiL†łşŻýž·cSŃéő8Şĺ¦Zß kÝ®›G,wů7xČĘß]ÇŤ'ˇŰ­ ĘŕE,&ł4\÷VŃ50ʎřčř"8~+żF6?Sj~5$_b_ʱî1@Rt´€çő:Ąi’˝äÖ ¸,:Ô]nv€OŁL7‚(äĺZ<ÖSpëÁ8Ş™˙n[šć5¨ęĄî(&MÔäDŐşŔ(x¨úžXŽăY(|ŞJ ÎWůőK4‚‘"Ľ4W˘đ&ĂÝ#$4˛ŁëΑň©Ü퓨”]Jű†pűĽąf 3ZKç˙u˛Ś|j­ëvǦ!hÚďż7mMýcöRO`¸Ë;˛‘QîHď\@1Bř­aëŐöřľĂ‹2Ĺäć»VŃÝ«U°®j«ˇü“j(ßY|ÔüŽĆ¶ä Ú_v AZ_b(Ŕ>D]˛´ĺiőÉfŹăeóŁŤĘ]Í6ĎAą¦w—@Śí —×Ŕл졿ixuO'Ýé<Ă÷©4˝€¸˛iT#ł%Źű‚ŕ˙-iÖR=Ůťľ˙B“}¤şyŠQ’ż>.0żyâ –™đ0ü0Ńś$ #3ŤŰ<ÔK§É&ĂŽ´Ó{ĺý‹ĹS6 Żu«Ą%˛Ő”™ő+|T…á¦ëM]\Î ~ĘËýex´Ě+ű+™ľz·ë ŕ·$±řZ?ąŮR˙{É“kö€˛ćĂŔW—Íč] š”O1ݭ殀Wď)OăÂf™‚ăÄÚxµ™o7`:aŔ¤ŘĚVţQ}¶gÜIiLí3”ŹX˝řÚŇoĐÁŠéד«ËgłIş +ÖfżńĐ‚\bf"tÉ|"Őΰ2•ŞĄ—çJZ}k‚âújÖeĎĎŕołć\‰‰f Íi’'˝e±­=˛ć#«ŘE-!Ś2ăŁô–‹’ůiŘ´Y®;O&G*lܤÓŢ^Ű&ňΰʄr6ŕ«3I±ŔzÂúÖWbaBq+ µX¦Ż#ŤNúđ•Ž0ĺUí‰nÝâô|µŻčňĘů |·N>—ŃŞNBډĆz?|Šď.bQýqŘł '%~Í<Člô6®ÁEÝ(žü@şî¤E$żôŠ~tOß·ćĘÂ#c7“€Ď4ÚW$—ň8Ěć¤Gý'— 9ÍËÎŔďO”k”ŮG¶ĎŠ m#ÜŮb5(©iä¶R®ľµÔł”T-ŮABg“ĂGoÖ‡ćędnŘú´m1p ®$ť× hžńŮ7ő— Ë΋S†Ţmě*;Ó˙0ßű=T®üOČz˛kŇŠhmZYxü.ĹB(«ŤÔîJ‹OtÜÄîIP2łobW›V·ţ“hú¨Ě•)ďë\ÍDi ćáv'Ž­ńnĽw«3súI”FdąÖŰ—O¶Đö~~ ft |ËȦřŹÓ[[g“¦F\‹%Z~tnRâ‡Ú„ĺUŃ…NŞî5QÜLÖtB±§„ę“ęQă¨P1şş$gSäËČD§eńńËř™Ł 5ö>…CŇře÷q$Ş}ţÁĺ3çĆC5öŘkÓ\&Ő1ćsŰ0:§+ʱ8ŁĂřË›S„m†Ćj  m -‘¤Örí ůëzŃ!ŕ†ůeÇ ¸)ünYŐŔČa=5~J–Ý~QłřîűŇyčtđwŕK&O˙$XN@†vqĐlĚUĎjŕÄ›౩Ýű‘t—ŽVAđę°§‡ ŹCţŤQŚĚ™j×Őňż­FÉ›‹ďÎXőjůË»l€Ć¸Y>5,qňťT´Ăĺ'łSݧ¬_É#€`@ĹEO;é'Ąz˙) ·ź45Ű5ŕÝ0ľ6mcq»j%úQa00jDîä?xĂÇ‹/JíĘ}Kgčęň„v\ĚA”`×ŇvţÚ7Ô´ť ůÖ†© V›Í_LĂJ×ç÷v¸{RyśÚ‡·öcGĽŁD-\U?DjTŠ`Í=Ű€VL§*ś¬ÁB×SGBâqűÖjněŐ}¨BÜyFŘ2lWľ%GkőLś ]ąQŐ¬Ń=ô+‰‹úđ'ĹA®Ć)čČ»F?…důÖ&®‰ąńm„Ý€Ž¸Ţ™śŰ=”°\\C©HjH˛żzÉĚ ZjŠh\őzŔ/(F<đŮN2LĂĹŠ"p€öŁ®%ŐO±&;äfáÎHŮ\¬~d”NąY1¬Ń´¨:oü˝0˝HX7DĂuÎń.ú-î΢ÚÓ>:iÄ»›ą˘€[>{L1„Y°só;§¸šěI/žÉ`xׇQ©'˛·lměóď5˙©*čNÂŞ}Üö˙Uw0cżčźźgóçíŻíŇ˙gMůýfţßI¨ů:ýźź¸?źÖn~y?źÓ˝ňv>ů=O‡č‚ů;›ˇ~}­ß?ˇżŐŞ?ßçő?ú˝,§ÉÝÍ|ťĎüţµ?Őče>OQWÉÚĎęÂůýnO“ŃV‚ľMźĎ“˝«K/·çő9ú˝-cáő»~~ú~Zűóýo“ŇĺňvŇů=AO‡ęBů=ö–śŹŁOoJę‚JS >†HŇçI.rĄ‡ňŇ<ÂrÓPĹwL{WTfHó†ŐćlĘ•´Óď Ń@ÝđíŽĚrSěř‘[§Š4 ]wđ¶®Ř×HR@úo%«%4X© ›Z\řXCąb^µ–&ĚĚĄŻÂIą„ĂČlŰŘW4<ëôÄŠ—¬6Tg*M«ţdA;w5毸}đüĹ#OÔÂžŕ‰śő5ev§˛5É€e]ůK[@UşÇŻ|0«Ýŕ$Ć»N,…÷ŁaŮhm ą >¬!Sz­őQoщ “_a÷ń[Ě÷©`~ŞĹ!gćŐl é­@ž›‰ëÜś»ďÓ„tŰšŇ9'8‰~ă–Ä´çRŇV~UĂ!˘żxŇĆedˇ›Ű;0JÄ\kÜü›|˘2ĐoäަĚé C€GŠď*–XBÜ·łą‚ef9é®?Ą8dSű˝ę·k„¤AŃŰyé>¨”%í]ZAĹxĚżÜ;ÝEEŦD’:@nxăČĹŽ[Af wÖěĎĆT™Á*‚‚“/GÚŤ˝gŠS´ó}-úĆś&WĹćłfÚĚ{Đpiv8~ÂV`É ů6ühH 5ľŁ}N›Lî›m`HşM¦ÝY©Ź˝2ľeż)03ń­ \«÷5ů~ŻJcH–h#ŠĹQOâ©Ë{ NjuušĽEŹ_`uFµŤŞőž\\b<ÁF0±ŻĘ"Ą_e>mĎď,1o@4}L,¤7žíźŞ‹$@„[9Ôb±=uV4¸ đájůÖĐk·°ZĽż¬b„ĺ,úQ•¶đăs|kě.ĺśřtKEľ¦$ᣠNmw†ďţW±Ţ?ŢKÂî--˝˙z61áËě˙%ar¬ˇĚßö˝BęŤ†ŹľÁ’ěîDěÂ-Ľç8Hr2˛Ę‘üűóĂ{3• R˘dĂâĘV ăžüÄ{ÚďŚc«A>5Đ3 ž6Ž÷~ş@‘7ëg¤)a~-Jxé† ýĐŃŮdşËjžWłŚĚGŕé¶śźtL‡1/W”“ÁÍřQśAôMüЬô¬ÔŃ fú(ŕB˛íÚ‡#ů.Ř!ĺ¦xڦ„\î!YUÚşf6†]¬Ń}˘Pßąá<×; ĐÍP·ţ9@ąZŐç|Ź”ŹÉń^“MD‘W|hśˇŔjkb:ÍÓ– Ŕś#ówr’ărĎĄÓÔáůż_Jń¨‚Ć#Ób/E/„ঢŁuVOs•ářH-2@źqĺ‚`KîĚ™ĄËf&©4܉ٮ®y7|lą]ô“űצ}  On°g[ @Ń7”"7¤j›¦íc%Łž&íCičµŘa%Ô1Íň9ţ¤“L¸ýĆZ™Ë‹ĂĘÖHpŤ„„˘ľë Í,‹¶B Ň řŚÍďÉşeՅ㥖Ją~Ď C¬őYŘąSÓď@W.†źÚˇĂŔ;ߏçr¶-ľ CrAĄ?†^A&㚨-ĎúĹ@Lý•> ĺ+X»üé?r5 Úu9ÔĎż±yňÔÚ ôoĘö­Á,f'+«ŕ˙yiÉY˝–ú A˙X!ĐÇp•+š»>›Ńb˛Ś1«Qŕ“ŕ†dQřM˘ą=2dÝY:Şë›˙)&(ĹÜÓötŢ(obőöÔŢ1Ő묦—X’ą+ČůZ.5č˙~NöÓÁ‰/ËÁ·błç`&Ű)ě·Çh’Á¶×g÷ ň”Tä@‡ęÂz׸Ó—˘ě±"uřOi¤ĄČ`ƯŨÝÂf‘I9řz뾉‡Ś~óýĆ+ĽM1¶vĘu|ŻX*Ů|n|ëK¤<­mü’oÂň#Nŕ8Ž>ŃK)ę°o‹F˛ë3ĂĽű&!:Ż(]ĂX'ZM©ăz±¢•„ˇ6ˇ‹K?Ąs® XJ­őPald$KÁ°Ü_qŠ|X7P5ĘžŰL%]đŹéřśľ»ý˘1Ő Rů€ O_Łúj줞yŰa×(đ±ĺ¸AůŇ•Ě"$›×˝&íäI_¨čR‡Ź¦tľĺŃYţ¸ó©żÉ!ŰŚü±śĽ•×ĺ Ë}WĐ"ő<ôQě‰=Ňčl„A*ž!='>ŹÍo†| áhżŘ5Ô]řýô3]‘TN°M1ÉĹMIîńôĘ u›˛ľÝ‚°Ů›j~%R"[–GQ+y¦.«őýŰ-Üěo3;“Á5M,u_ĺdüˇOJ§˙Ož}ŞT”Ă®ą‡FOná5˛˛ `YgeOxu` \J;Áˇ?šÔęnĚ†Ź¨‹—ÓťŘaÇŽrLЏţ;áŞjaGŠĘĄµ¨ž“Ô”˙+/(nĎ©ĆADUÎënbî6ńţÖaČbm´ř xć°b›mžľ'1_é* ĽČř™“NˇrV¸ ¤ďŤĚmstT€,oť ÎsÝ śEÔI<Öp¶ÉF MlĚË á3^čĄY˘é jN–“L¤–l÷M~ú±+…;řžřŻKţ1üv˝Í†ë™Q2IŻ3Í^Ç~QRÓ†?čv°LD;`ń0G1U‚iś=źľwKĄĽął›,»îekčŇ ňUTŁŘŠc+9ĎÚ{%ŃxuĄ“ň¶qe‡ťaqĹa8Ą‘tŚ->d«tĄoµĺÍ2ôŃĄ"ôŔ~ňDsd)› uť1çµ pL÷ ćIĚô}ŃËpp™[*ľä›ú­ą’ŔZŻŃŇ{»î¶Î ­G‚ŇnNĹęb?˘ń§6jD"’!}íř!Ľ.UÔ»‘ˇNč†,+y›,¤d_úŞ# …mrču×á¬ű4ôHäř Ńłt2łŰł#ÁKá}ô$ކÚT VÉ4ĂÍéO?6Â:4ü묗á݆/§*ťĎ¤ť.51źłUô×¢aŻäU°ÇwCO6i}>ßC|^L FäW’)ůŻaĄ[dµ×šIă<ćŻĂ™F|„Č`bAJăžŘ"m˘.‰Ě¸ `~ëx$Č:ź$VżS®źŽŐřÍöMěVm8\NćźL&j¤×54ÁęqkŐdđ )îP@ ˛Ř!k©•XÚŽ4ôfŠ·Ťbé[&ŽÇ ´CÁ)ĹXo— >3$`=O÷yjD¬˛$şr\ěăn_„‚ĚŔݡ_HŤç˛n§îśý űŘMęţŐU´ęápš#ÇŃ'ç°ß¸öI.Gżb9ŰřşCűŰ+řéĘc`XÝBE9śÍݏµB |&ü(â™[+oµ„s\ÖgçnłM%Ĺç;ZÉp‹?ÎĐW $Ί‹GtIxź; Jĺ·Ě]¬k°>켴C€¤ @rú„/8 jŞ=˛×đÄĂ4 ZN®$śŽ€ úFţG‹Ëęqµć°X@Ş6 u/ש»™XĚ÷}‡2ëĐé>áqd•U‚âýĘtŐĚq©Ő&ĎŽę,…IěÍ»·Đ:ڟĀ Hj¤›Ľ©_‚ąśŚš,čO»D_ˇŻSTŕšł¸cď5ě,ÇnÇ^Zi‘)PŰgU•utĎë†ä–Ý3ďb#%ßYsGí—ňěöAA;“š‚—%mBâ#9ăO€@h•ôF’őÔ"L\¤{ęŤň+jĆ@XHÎrJ°˘°Bg±÷…îSÔLĎüWLňłÁVrU ežđhźł—™ ćÝ“^oĽUµŢ#„7 —ë]đĄ3UŃ*ÉĹ{*ľtL`lw‰[Ň„ÓSö.Ulš“‰×Ěརk'!„$˝1{R˝bş.±†¤âýçç";WDż'ȉ™–Š?<‰§k‡p3ôŮ ŔX®ż= !É҆·Z0| ›K…čýl?sĄq™´©(uaZ‡ß‰Yófű¶ ŽrÄ%Ţ’;ĆwąWBÁŁ)ެRş*ľÍŮ˝\‹ůč®z8ă ű7Mqéě*8‘·.X±uąOŞőˇÄnű1ôłkőFĎĺ)I#uîŕëO˙…ó›Ăp8őŐZçń Í3´@µzŃ1»]0żőÍJ**šăb¤óDâóôuBw˙˛ě…ʉjĎ;4ĆŤQżĽÉN©Š{ č1n #÷X‘aźé.áh$‰źz*ݰł>Ź\ÁĚŤóMÚ˘#BŰ\Đ —ííĄŰ‘'H/)‹?âĆڨٟó¶Y“%‘otďýnťjż<Đ»ĎDîµ§Ç>ĺm`ÚÜÄ7á"Ţ‹čL’łI bźţ;†:ÝŰ9-ţó‡bÜłŹM&¦7 µ~,jęŐţ“™ŢMŹ,Qp`‹ń ,źSĚkµĚixkŕ*ü!8ú_î¦)ËHMŤxى«–¶“t[÷OîĆZO‚ľÇ!xň)Ş«¤ëh/ť±µáuЏř»eKX˝M_o€jhžĚ„Kkţ¶9¦FÝ6~ޡăvÓ?ś¤ýŢ|ď{Ä`¤o&đú˝B§{´f“€¸ó‹ĎŞş¬·ŠoôÎ ¸şbţ&¤v‘Ufű_ęꉤÄć%é­p^Ľ}|ÄÇ쏧Íh-©ÄŇ–Íĺ?qśi”ăY,qf}CmA göŇ,Iń×C*ëĘ\-ĺÍ+eZ\č>O?\„IŞ4â„%–Ń{Ůë2NăŚŐyëôpűô‰ť®˘_®˝}Ć«ËpČPÔLwB[úąÂă÷ĺNß?ůďŚWě'ݵµąy(Z×]Sżań‚Zq¬™t/X©ńŠ˝gµSĆ_Ϧ’iŕč.Đ- -B©eKü4oÄäĘÚÂKrµ¸Üő çälý»ňČ'™šn Ź®U– óˇžĐr ` cĐęG¤Ě+„ ýź‰Uš|Ö缫 FĚhĨJűwóÉ8y7:R:ŕĐőŇy)ĚCM©źi*ĹŘ•," (XEHŤé|sKřâYÖńJ²B˙H´‡Šܦ´]E&äh›p3îŚ×by““„GŐÄA§Ň)@Jü.¶S,7Sň0®Ą÷ÉÍk\%uĘ‘5p3ŚĹliÎĘ-,V^uÜÉŁ6ŕĐ8nMčYGNĹT(× IÓ,ş‰?-C¦ô—J·IöÜôäŕ—'<źZ9´ă,»®ŐŹ&n%ʰIŰ2N]ŽčźčQwL锢›i0O’[>좫ş7sß |9„łK ŮýmKĺ&Ó đ˙5±Amx÷yIŔUöO&3qł…† ˇR ±›{¨˝Š{p§ZÔü™ÔçţŠô"n Ý:['‚É;ĺěôDZĎâďd±4 ZŐýjŮç¬6î=/ó‚—ťôCF YörYd”¶8k¬ˇ$ËMny8!/Öü ž Ą˙)Úýó°¸"ř‰üíśř{ŔC..VeÜë¬dşťFú©Ťt«Ü[ňÄAĘÉŻ^ b ~˙|Áqkz»–@VGáhFłÂiĎB†ä.8f@âJá™l&”­ŃK€ÎMŠEíó š'ÖÜł¸‚„”Tó.oşr”"e˘jEK(°^ç­?Ín=đ%_JËô&o0¬ýWę»9JW0ëg‘Ę0™}¨ę łžÍŔ3órxe„”ŮĎ Ź"5m‡·ţĹ 4áÄH@ăb+%Ć"ŕÍgŮ>Ą‘SŚůôcbwBŞĽzsŠĽ‹ řöp(aYy5iî î5ż^8÷ŻźăUŚô | ' |ČÜ‹€#‚,‡\vYí­{˘Ň#ŰťŐ”¬^ăćpY¨k ě±®;“c©Ó[·nŇ/w[ç¨čg3S»Ů/őů»÷[Z6x"-P©R0 ÷˘Ba ±®”_(Ü”˘}]ńn‰f8©;o.ź>`łš`€÷{‹AU7j/{cä2‰ĚžŔH>¶:lŚ ·»r–6ËOmk…ˇăy¸µGŽsŹö¶š–·{č}đÜĘio9ďtĺ2ŢAHy5Ĺâ˙ }„YM@f‚­#­?›ĄşŰ͢¦UŠĂÉ–¨;#‘Â6ÁĄJ\uĚWűŘ.cş_ü¬«~şj« â×…×=ěRńoQĚK'ŽF…Qł¤’k†u{‚ĎĽ/(•dÁ]çąŘ¶őĄ€´µUÓN X(Ż"XkĆĎŻŻdSąŮ‹c ĐZ\GY‡/Bźn‚ăr’¬ „Ěpn§{ş4c‘}MřŢc Ę¤¦?Ń ęí’┕›r[6@ă«ĹEđُ{˛ÓbTř(´î®ŰJ"HĽ«ÇŮÄ"ş˙‹în'ÁMő<@xJ oQQaMĂAÎ˙`´ş¦ t¦zËHÖß”˙ňŕď#ă¬üU˝żFî/Ń:–Šr1_E^…§µ]0ŹOäj N›Żśhۇ ‡¦Ď’fđcϰq5÷ŮÜmlě*`bĽOÔ cĂŃř˝|†±WCHi€e]–ݤŁ=úŁg.‰»_»lq?´(EšmZ—ŘÝÔ,ŻWéś#ë±€QF1»# óK»ćIëf÷ŹýS`¦•MňbÝ˝Ĺxď–Ďk8Ä}‰|zŞ€)ÇYę}•µHľ×ٔƅť´Śúľ˙\%™—ł+phĆ8>9zť¦JäA^T?{Fpk†l`Ęrg7@—ϱľ-2i›lJśówµ1ĘäVD8¨*¶  ĐťŠ®^šÖHľrótUŻĹšZR¤›5c"Ž Ś_®x1dŃ™˛ÜdhCşDČ®Ň7 wÇŹ›ŽžŔĽű˙h*JM„®QřE@˛TĄ—˝ľăť%Nę{ź2­vGmUţ%ú|<Ńî@ëÍŮŘĘ,RĐgY”ČBËŮĐ9+„A%™č+U3˙Pv˙K€v=XP)t­>ńÄĚ`W¤`]¶ëIhŤ+O¬mňśX[ ¸Á Üů´…DLÎâÖnę·ĆO6uŽ^¸pIéď58·¨ÄMaÄz„€N±łčŤĂ·H›ń0mšl9RŤ]m}>l(ęî[nEţh×°Vµ# &X;&2>Ó Eśž»§pAGźŔsx6äK@ ł_›Pśęť5&á± Ŕf5Ďé1şÍ…`ĺuí]žey¦ŻŐ¶ hV“ŹnY3j đÖ›_ĺ|ăÄn…ŽxńY â6'«;>jďdz×KŃťúc¸ëqŮŹnd„ąŞÎ ԝىŇĹ~(Ö÷2R°;Kb`¸©x^Ő€í ^ßâZĄ#"+9QAK5P˝U/zf|Łżú©Bőߌ5ÔCKmgsÚé"˘N™ÎkńÉţˇ×3©Ub˛5fö1kř°#Ô—ĚŮĚÜ!‘ŕ?S+đatÄm¶…Ehą8ÉlOrB:¶'§@ř§‰Ň7&ŃęÜŚv˛xş#łţG˙u ÓS†˝yfťżTć‚IĹŰ%ąÔTĚnż[űŕvŃŽ*š[;Ĺ×%Ťç-‘á`2⽦ş%×ÁÍŻţkx…!]6ůCö‡FŤˇ”8`6\rkű»9×őçô‡¬ďëU2Ę<–»etXR´# äg˘1ĺ“^ UÜ”{ÜhĄE-6iéz‡” ěŕđ ëˇâ‚†OcnJc“?G¦}?¸X}^î4ÍĚĎ~ä˙?9=pźĽăÍ%ów’·Z”ňóXś~‰†kÓ™ËőĐż\“?௧¶Äëh şEéSł´ă–żL-“Üꮲ˘şś‡ŢÖĨ4S‹Y ş>#cţÓś[#+˙ Ô†·ËŤ¬ő^śR`U°µ ˛:.‰O(+™Ü”u5aŃsRß” K«2©v A±lřh€Ł2gŢ1ßJÇa›ä?mQذYămćjk}[pĂ ©·2[˙±…w9^×Őé­ŕ7'ČĘŮ ŮŕLxÓ¤ Ů)˝5â¤ÂRČ©ÁôžŠwž·‡aęŕXW'@P‚I{dtż ëRw¸Ą”· z˛Xß1ŔG“VKJSĆ_ѤĽŃ‹ÜPťZŃTyWěîHdŚiß~“ D~Ĺmľń˙/›Ő? kĺ·0űÜN®1m ÷LÄĺlWÇäŁ(ÄOáËÁťźŁeRđaMűéţş·÷ŕÖ±›ú9”ĆŰÜ2˝sŐQÉ“ Ľ6âĂ'ŽdýFČZÖTMőČču¤~ľ¬ŕMVŃ]ŇĽZĄy9 .Ńq©oíÎĂĽ?5MŘř;]*nY&ç•Ńś”Ô0e/(CÖ+Wëę´ pô_ć»m—E^ˇÝŕß<l-béXőú~d¦gĺ{ÎPZ0»·…š–í×WÄą|>¤GWłH?‹ŻűJ r[ެŽzřî)$óŠ5˙q„SŤv+ﰿǭďxwآh/ŕnĐ|Ô¸A5ÜE0ÚĄą‘GjęFZ#»ne‰Ä…îíÝůeo¤ wę©ó.p¨ě1Í‚¬×¸ź§–LgţzF š€Tg*dö 7›'Xiň~!jż µ5ücX—sţ8¬©<TZd9 IôĽéŁŇ˛oŇc,'|‘†×oý¦ę\ }žđEņG{ă0ő’"÷Ó\R“•ÖÜÎÉŽČďńî-Ą.µéD@s#$Ŕ?˝Đ5'ôŹŇ‰,˘ßżâ·˙""f9ĚU™ŽÂľŕüŢ,rn,M9 ŢEçÜc˝~;Úö|uŞą•ű©™ÉF`.z¦"íý/‚Ťí—ňXˇ + ü,©şE}”íx >ĘĹ\’Źa­Ű÷ć“»ă74Ú&’üüÂ@–çx‘*h«ŻĺwT˘—Â未 X†Ř§şéĽNnž$x‰-§|CÝFXńÁEŢ“ Ű‘ĐÚ4á}M…Bđ¤…űv|Ťź%s#>)8\',eSʨQ6Sxň:MÂGN|0˙0®¬ŁąÄL§Wv_Ƨ'YŰZW O‡}SĂqBcF•ż% …ÚTyŕć7gŢD?NíĄóS$wŁG@l)$J‘‚ÍĚC-§›pyřş~=/?4ľ¸‡6 ˇ·0ĄçÁ©—ć¤&*Üţŕ>*`SăMyjRPî,Fć 1˙RóĄ©őĆéÓŕF &v[ŮÜâUŮâ5î ­ZÜn­ýĹJ®0ŻĽŐyWťĺEwŰX­2[53!€ÔP*Šk›x Ő¨´5×:Z sł`şŐß‹đťŇ\¨—Ý4S´Ŕ|kŃ„‚ĽĂë–•g9ą!óçav$(^Ń:ŤŰîí4±…U µ}Ś#Ő‰SĄ ŘrNö6Ř(ŻĐ÷ oü;řĽC-V®´)Q©ý[HEtŔ‹yĹÁ8\ÂOSÇ´Ż+ß7»–d ˙˙őIŤ$—ç xY:ôŰaů>˘ŃÔżď‚ëu¶Â8s2%żÝLďĚm}2FŐźý×ذđ13 Ddtł•ŮŐË›´Đ 5âwöţWŘ'č—0¤1–#ňy 6ÚAĘV H§â:„ł6NL‰2vlˇ’BxMV®ţÉ™ş˛ĂĘo»0íJ_ľ·üő…˝Ŕ0źĹA hÜă4>»ŢŞëüČRSă”eét¸ť="őśArlßsorg#¬ĄÚťçůăŤńç>ŁpfÇ4Ţ%<…¬16}Ę7& pią0­;s‰ĽNYßﲛľ(“4Rb˙8r_đ÷+Ƈ:_ç’G‚_ ´».čN›GXËcÝ­,¶Ąu/ŮťpąűöěůşĹöl/–ńŮ«"Îaűv^äSÝ榎î¦=е‚­xLł´™#P@^.BJËëĹč{xĎ^±9ŢcČBŻfÜüíÚÝéäEĽ˛Đ΢”q+Y„ú%FďżťF˝ˇ;`6 )¦‚|±\/ľŤ.ňH@Ůş`E?ţŢ"ę/Şţ±z¶h D’g| Ó´Hłńž6Ü?JůWÖ ±ŐT˛hAĐŮCéćÎ÷Kę—Ů!ęVśACđ?~ĺEÇdx^‡=,č´<ÔdŠ®ňRń˝Ú*Ą¤ˇ|Y~âłő‰·fş]řŤq?…(eĚŁ,P9SŤ˛¨2»Z" ˇĎ§íĎw]IáŞ}HăuśíěÂ?Ô ˛=âĆrÓlO±6ť“žĂŢ€…o2ÝrUɬŇ2!|‚ąËĺÄđ9Ć=‚IěK\ŐÍ*“ýrRJ˝%ť¦21)’ű×·˝ăKŇ}C­ňzłß¸OůŤç!(sĘŞdËoĹ8¶ÝńOŕĄÓV Ü4V*…δj¤=1Ć%đÜÖ–ÍžČěÁ‰źŘéÎďSK©×Ą őŠ·#Ňx÷OŘ…Jµä=L.aaQś/¶ « ÝݺIl”ň-EOň^ĄńüÓś~«•BĹ^ŰŘ Ĺéë9Ě™őUB€WŃĭΠ„›¶řŤ°Ţ/Ä.A­‚jëÚŢŠ’EĎ™´č/™yâLőHXđĺ’Ę—6uné4§ Î䡂×ČÇ[R+.ěm-Ľb[·Zh=˙Џŕµ:đ1<ÚÔđmEť%YńěĹÔóĎ«c9â.–´ľCp×0ШÜPLײ(s%«îOŠ>źcÔŻ‡``@´?C#póĹx#Z.ü¸ż Mľh+ ń*‘eë-4¨µ G*,óž!RĘ„ű![âM©ˇË9˛çq »™ú%8ţ#¶öc g˛´höZňđ@gřBT>Žţ­ó:Çîm_Ĺs. •yŤë&38»I†ĹËfc§ľÉÍŇĹě?§' ,dťÇϨ°źçqŰ}‘Pł3¶;Îń9űŃöĐQŇć Ů~h»E[ł‡G|LNµ’ńüV WoßĎ».Je–yF©~sżä* Ö˛ŚMë9ąa/â p3†¨ ‰ÉŁ×ź˙‚x•Ţe7Zˇ ›ů˘\’ë™üÄ"ZXeĚ2đ ćtx_ă.9éŘ1L`Äŕ0äóý0Žç —Ąí!TiTIĄWťčwX˝ó[ŠŇH !&m« ”Źżů(Š9±ŹB|\VĆšŞ7 : ĆYęńŐgíE6|d&ĺô9úŕ( ·7Aż1.^ jP4}Y©Qśz ă¨RŔEŢźô]ÚďŹý˙?w6-pCo0(D˛Şň€ŮÁÇćI‘Ů`7”Ň,?Xř·ŰQ†¬‚´5ꩊKĺŐŕLV­łĐË‚…ň·3{"RP”¤ ž¤ź<Žąď zÇIŻI0ÍťÎK!aĂ–ŕÜăä‹7.ú'knA¸˛` „Qw…žíBć(“)U`CB«}sBŢŮ#  “ň“\3‰„0ÚäÇIőRĽAË€GťU#eY™¤˘'ÉĚôĘĐEWťĂ´5VPË0€űâÉŠ~±˘Úk"-„~Íá_eôfNš@WȢx÷C˛ˇ›`o¶ť«Ć)ý¸›ÍˇŢ†JăbŹ|"GuŹ[‡ź2ÚBq†Ěăf`ÍiĎÝ<˝´)|R´Ç“ ý{߇7nt&+Ű'Đô µżu›mŐv_·ŤpÎfĺź%˙GPz#"ĐU$“/QóŃ}•đ¦8@p_ÚZ‡„§ÉцjÓÍg×ĐyrĂTEf\ô“¶Ą^n&žëŤł_§ř·"E“}ľôUŠ?­0}Đc˛Í*N˝ Z‹ŘŞÂ MlŠ™!Ív˙'řLŤs6hŔ…Lq–ČĆ>[Š*§ÄmEHćě­Jwđr7(ÜĹn&Ţďö™i¦/%±­÷8 şTmÖŢľîKČ›˛ ŁĺýÁÇČ·ö1lž—Rž-Űă §B$0şô™îJž\§â*EłpJ‰e X1`†Áú®–ÇwżÍ·ľ-ÁŃ{”HlşqŢ+5†XM‰śm!Ę{ą´ýmńVľ,Fň§“Ce?Nh+ĘŞěsJ·Ť„řCrŇÍdIşE'fęĂOXVÇě\T3LVFƜޅżúW3P®Ľ˙nTEƇÓ‡u®őŞz6ž›B×s!|[9–QŻMMó·óBö /*%ŇşŚ­ö2•ř yŠ%âđ8…Ǣü¸k¨˛YÉ)ůčZé-ČçéŮü–ËCVÔQŞńvÍpňG\ĂT¬š á\bV‰˘á@r“üG`4ŻÉý2x_?ź¦{SńL4ŹŔ3ąă´µş ÄË ożÓp˘ďďśůĐ©QÄ_-ńc Ňĺł™%Cg[,#Ţ–uŢĎÜ‚+ő ĺ^*–IźÓZáYF ýłR°‚<$§0- Ë›Ö;ßĘĄç ›Ć“ž®˛"0&=ľý?đ—  GDŹßČ–Sôj^X` I]ź@{A…ľő2ă‚ôNH\Ő…smüőLöˇ×ËŃ%˙ô7ŘÓÄíš»išż-6x@/rŚcE=.´»“ýaxÝš›D¤ŧ'¦Ę—çÚ#űąź´VÉÁ|ř(ĹŘ:8”AȨ_<Ä×ð˘săkË3?Ä:€px2ohbî.Ť€2x‡r#‹µ&ULÚxýĽ- +gý§ă#mȸ6ěĄ>kČ;Ŕţd·žŚ˙X“Vęí×’Î5V¶ók¶ěk^Î!ŇâőĹ™u\'a÷U¦ô]d±“ b G¤úÎvgh„Ż÷x´ëŁpř#Ŕy,@/$NŁ¤Ő´´ů ‚Šą rŞ~Żřâ|ć`óHpŮł*ÁńíÔÓNáŁňúń˝ÜĚŘK ž¶Ă%čęÓöʼn‚x “ç?ä]#}łsś "ęžÁt R]ž´J…o˘ÝTav"…,öµýȨO:‚žp䍳8·$Ž6BÝ覺ţ­DÔ4ľůÚ \_Ő¬ŽW™ú ŽESYčó+h4 v ±RČçoŘ˝VŽÂĎůŁ’ *Řź.tLgvg5Ř,:8çÓ­ôN2ŮŇ”ú}´-HęŘ3ŁÁ4ËÁ¦†1ÎÓ§‹ú $ÔOP;}ü-yĐ8đTĹ|`)DůUŤi¶ ¸xĽĐ&µ¨x˝=­Ř_ŕ %H”4)ŠZţ04¤6W.éG ëż.Ü—{ĄGđô3WĆĎb“OžżG »ÓwŘYń{.w*¤Ťô‚uň`úhW"Ĺ:rŞĺ’źŘ^" Bí8š‹)MĄŠďÄMĎRŕŁ;ŹńÉzUŞCŽÓi9—/ź:ďFÍŚÚ­^éę-#i”Í ŻŞ Zś+ă Ľ‚‡ł=E„Ó­&PpŕŻjŤ¨3A_›-Z^zEy°ZJă6Nŕ–á4YŚjˇźŠË˘±“¬ÁR®ç4YŁŢľłźSŮyĹ{ Ói ]X\ŰKia!GÖŘ*1Ôş1Ô ˝gs¦Ă<.€˘ë!L–ßß»‘ĚÚvjÓÄ ŕpť,Ü;uÁCÍiVíÄ ÖÂł™ú0˝»ĺĆ%PÇŐ»Ş+mś˛Â횥ÄíÁŚŤ¤>zŽd‹^ÓôżqĐ«$X\_ZlZ<Ő#Âĺ{ÖÇ­0d,› ÓoÍ6‡{µ"UłTŻNCVAA©ń`†3Ý^6^͇Çc«j˙üY}im‚»"[KPËťŃ Ť…µľÓGrő%Ĺ@Af‡nF5ÄôFÖkkĎ3ô•ř><{k}ZXjťş[¨TŁĘ»4©p̉ňź4ÎLÚx§ŕřéM)ăŁ2’­řpy8É8$f°üéxŁçś]!h[źpĚ+»f€„6+:yX»x>¶G3 ?‡ sőâíęŇ„¸Ńh€ôvߑν\,‰  [ɶNĚÉĂŻFťćvtD;ˇwç«3Y•0KÚŹ{ÇňâŃň`ß3˘ÄHďŚŮ…¸Őý}š\Ą!Se@ŔTřŃÓ>ʞ»C$Ż}w{ň•ëď2|AÇęŔYśß3yůÉ]Ú¦ ­2EţŘ· ^„×aŢŤ+UNhV_3“'U×…ťŇΞôâÁč»i-âßęďŵـ˝ŔRݢćP ǦyÜúl}D 5ĽŁĐÖđ, ŰpŹŇó2änóBť÷_÷EV,™“ç‘krůţ©ŹÓ˝˛Ů™} ĆKo›Yuî.nläÓ×ËęSŞą!»šB2îěTţ™T›ĆŰwâG\0B_ń»^ę…)´ČĂ%e¦Ű…!w}/\™-‹.ł ůü-WÄX§˘(="SˇłtrÔĄÔŁxŮuăm¬™řMŽĽŠý‚,IŢxÇfnÖDş™žčµňŮ⎟‚XőŤăUŐwŘÜŤS_SQÉ!Ιôą,ĚAúYZ ¬A ¦–Z5íüa,é«H¦ĂG@K&0ÄĚ™ifR9aŹ NţÖĄ™Űž˙cZř /2bćHÜ*p˝IvąŃxBYq¸’ő»ČÂG¤ňG|úî*Ő(ČiÉ×Kepĺ‚ÖD.řť5Éô¤˙\SÖ|ĽT€6Ń 2 sý˘c‹f’îF}uS˙ő }Öčď÷X&€«ţ›/‘Đ]©×?ČŘGRŤaBÜĄä{¸űýY‹"Čń†S=ë–>'ĂP6Bé¸1 ńó—®uKöf7˛J ëó¨} ‘\űÓ3@ú˘I (¬V›­Óę\‚>T“s• sŰw€"°Pܶ(U;u $U%«zĺÉö­Şřßj)SńTF˘î)|×Č˙Ö32-šĘ-h·™şŞ¶&źő$ÜË>¦»ĂňŘĄn¤÷'óÍ$ë.ę±O[ŁÜŃ˙ ˘NÝGѦĘö˙OtšĂ+-?Ł"ŃĐ-LĚĹ4Ł´" DiőŞ·cB§=j?$Ý3ţ¤™' ŽSX= nşšhu—‚ŘĎ»;p¬Ćd}ĚPŽ®=îČ$Ů ~řÄ·¤{¨n‘uë'×ßă”Őm§\‹€'gTi8Hž›fâ-Dńüŕ˙7´–]W—é˙zµ†ŰßeÄ1ąř®É! +řELŃφţÝy%±—°—”T;úLĹ\OđµIŢWűQMĎÁtůňĘýč˛l_żv-Ĺ÷BöŔa€ţě4˛őąK,účQí«,rřO»™ZcYťj°iýQ˛ôĆó-›dďX$¦df jt,uR¬eĆŘx.TĐý4©k'ÎMiŃJ±G¤ěîg25„{ŽMAę9€mć±.ľŘ Ľ#Ř!ŢýNîhl/uĘ“ţúw3ü‚y2ľ !ĘÓç,ł \!­ĺăefěh]XŽ"»÷Šóáé%,GśĹ‡SyRËÁHłĘp¤=Y˝Ǣăp¬ŕÄó7_°ŞFÉţyď†;2ŘcÂç9k(UŰ÷Ř>+Os% ©Ń;ËjV"ÜrmĎ巟ͪţ )yAÎzÜűˇdKŮŔ“ú®x§Ý,ž™żľ˛ľăh™NJ(ncp?V,!ÜƆƋźWîú1J]*&ć=Ű$ÓCyü";_P?ë‘«ń Č"N ⪷G+gŐĎhŻsiMÍů«q+ĆŔ Ťn®điŐLÁ'yt\&ű˛WN˛‘h¤FX ?„Ä© ‰zĽÝƲČÖH8'ă˙?;†ˇĘá†-q$܉K Ü‘2ĘÝČçuŔěĎ.Rż6Č\ÎkWŤü…ßĚaŃ( g,d±H/R8ܬպJ0¶gż‡'*Ç©ËÝ ó˛ĘţmťgÉ5·OŠ˝Ů‡ÁĆíł·R–íŃiźŁłäíOýŞá®® I'7¬€üP©ŤČ~)Ĺ*×t¨ ‚çżTş%ČZ)ł˝»źýBđ ÷ě ťă˛•BU#jě8¸ňëä'Ý“J9ÂG$ýß3×ÓâĽIĘĐnm3nlśi ÉŔĆT¦R2"`a†PşZőęÄz¸¬šŠ¬WeżÖ&k&±ü[Ă»BLD}äůgŤ ‘,“í@žůžLĄŮ‘ś»TNü ?„¸‡Bńë(p˛Rcô~MJ Ä˝ě\ ó)ꆒ>RŞkö8H"[¶¸!=6’çäq9­Ŕ$ÓŠ}»¬$ŘSŐüĆLls«/ňRBá!YWď*Đč+…E3éň/úŤÓhײ¤ś•‘^Č,×#lb µčxz3opÍ”oX=ÔsO™'ÎFV1gO)Úh”ÓĎľ-Eą°ÄIDăÁP±«µ'3_90©ýYaoµľ4wIf°wv¨âĄg°ĎE‡űŕť‚SEÔŘh%ăđą+‹¨–fsbĺ+ČŁ§Ľt}tŠĺĆ 9$ †M–AÓŠX'óŹH·úk´±¬C… âŃTÚáC]˘|ÉX Ű;tŃŽX)›âo'Ő™ŐT˛ÝAvˇÚ~ŕO\óŚ€2XÂĎŮ@ČYłMő™ËýŹF‹ŘTÂřkO’gߏd˛¸I·F®Ź™ĄJ«Pý'ńdś,ÍŢZ0%ډ’]VhÁ”8‹ś˝Ö1ôłh¬ř|1ŘI–eőĚ \šiˇM*´8ď>Ť–™d°Üdî/˝¸V¶čţ+ňG_*“wGň7'^FźÄp¬%Ůů”#L`[°‚[Pj¨Â> í¬xôrP—Ď+r¦.őqňŔQs‚2–)/irQůl¤ÇP–*UNąüé~ `ÁóÍ’›ěvŃX.„ĂËw3µ« °Ç;B­Ë#ËYĆŔ4]ˇ"š¬¶6#Ó™ ~Ž UäfHÓ{ŕ4 ^Ü0ÔÉŢčłĚ#÷%Ü92rÜyíc°xhNÝµ× ŇQăT†t–™˘FOL'–ő#Ŕ•¸ń5ŔţJ#‹Ľg̦RK•Íwů"ź Ţ÷kŁĎˇ)X OŃ_H.:6Uľ»ür,;Ęk”’4ŕHź˙=Q0j~€_Î륊\ŔÝϸ]\M ŞđůŕD™DňŢú?eŘŠ§QéEó †#ě-}lđ+n_ŚžźšhÔRmš·E‡"T€n{ż±ťbc?őŐNwâEű%RŘp^j !Jn§řď(~)^=ŇnFĄÔ[ ŕĘs§)ú-Ůe§·s÷z$Ś^”ëBjĹžć ŁŤtůËuk’U–t1E«J%7Đcz2ůŁ t@꺉ě*¤Á§<;'Ş0L›=@˝-†Š8ŚŐÎë )…ĎLŁĘ}ljHˇ`l®Źž+Ťg(?áS¸ŁhŢjÁj9ĽŮą.V߉¬A%Ś5^µ Aťâu.ć=JčKĂ7D¦Ö6]w”qąŽÔIˇŞ‹†:-—¤y—hűăĐđ€çA,ĺĘĎ‹&ąśˇ»mĚ]ŤěŐtň´Űß„6.WŹaĂWˇ\ň&·Š˙>d†yQ!ŽCižZ\*h‰ß;Şđ·v¶_|ČcŐáţ.šžŐeĹ`MfRý[ţÓEŚ‚qô(ŚĐ(­‹)Ăcq!Éb¶Đj/—z\ťĽý—ÓB¤Ş7!ŤćukŰńŻÚlp}¬R‚÷ńsĺ.· UżqŞŞFő›#‚I˘qB7Ë JĚrÜśužE(Bm*¦Ď~‰‘µBź8ź×„¸ÉůŢ·řqě#Őž"°!ĽÎ‘ţܰϱŕ$k[qíqŻ™»«+Ď ¤[ó|x˛«DŘÚrK0ŕžţă6×Á˙rwiÔ—k çăŁGĺ" e˝Á6év4ł,GÍ(’ĐFW˙;>—ť±âš]*%M•"ڸġlěęŠ]%˝Ó_Á…¦…™e\! Aó­`tůOJ‹Á™+<Í2•µő+>DĘgÝvUY—‚rSšâ>Kă‹Fí_CËo<†sĘŮ+ÝÉË ZB»PBÔ$ő™×¤Ý~k´@Ĺ‹Đs2U•çvQ^nŤŕfď˝—ň‡$B<Č ;ć _ŁjQG]§Ňöóşˇ80Ň=őO2űu9ů˛ľd®Írč|Ĺ̦lÇ.ËÁrg ‡ě}—Ť×°Ď›ńXŃDuő¨“ą],tv€ů}/­*[žO5=VşşŐđ®ó¸s¤g9ŕFͰăAľ˙:ńt ¬“´ďř§η§Łí-]ŐŹ®Q‡ăKM ˇţé*kH¶akRJ˙‚^ˇ_˙ś~/(ú1“SýX“ĎeO=°ĆÚkJ3WéÓ^ŮűϝР¤LćÉ4˝&·W—őĐťüMÓŠůRĂćö„Ö?Ö\ţśÁDoěaˇ¬ÜÇd 2íŚÂ]ńT^ł‚ë«+Çđm¸ŃÍvč(DäßȤwĺĺ6öb缅X•4ĄŐö[×:N˙§(~ˇňčqy“ËBC]ôŢÇL¤źF AţđĄé-1Îźlš-˙[đ ôŽŞĹýĽţ{¶É4íŘţüJ9€ÖVsUÍÔ&fv^Ž÷ę¨x‡ôÍ·)µ<&ÜŤč–ć.5ďq…7˝Hţ1®đN1Ý›F«.Ůęű&Γńn¤-đ@Äěăí5ă.cB™"ĘĂ?xGŇ)*ź*µç9MĂ™čĎĄ8I¸¦mP XĺC׾0Ą3ÖŻ=MÄCb"śpiôż€Ľ6,«čOfí˙wţ२.ÓĎ5˙W9E?;›ýř'LˇÁíÖ }Ă.öC¶űY…82JŚ *mD˙"=)mâ‘ZeUj?»™Î ŁEׂöş+˙KÄ2ň·Ó§ť1†ÁcđcŁ™rJ­ cФ¦•ťbĘI=ůşÂX˝±@UëšÇM59Đ:L‡î•ŕSü×ççÎ~"›†°PȇŰQ4«ĹO 8ăQ XyÉłi?žO}»ľAĹ2Ôŕ|qď9˝–¨‚<F…{îËŇę!é<*«yPU—ýŽqdłĄ”ЧpÖ^Rô=A1ňěµ§¤a …0S•‰ޱ¶ĎŻé!Ŕä¤=Ĺ•šLjő KŠÝ(;©{bÎMhX‡ĘŁ8]3čJfÔňĹpAO iEݞ4ž´y«Ż@ŕ1dp%ŚŞoÜxÖľ• ífIR'5ŃĘţ˛"ČN¶!€)zîVŻ Ž(hĺ-^ŃšžPZ+Ćnáís¨Î¶Ú¸ç˛/ **\1fńZ2ŻÎ`8đâY¤đö ôj)|56¬Őj÷ÄĽéóş##ÍŠŻaŚó°s§«­¸ăőF˙d˘[NôMŔ•źęO­p+Ďdźć‰µ‘t5cH'ůÓ=ĎŮb>Ľ°ĚÚxşCŞŻĄŘ Jʆ'/`ń.őéöZÜ ßń©2QJÜ®wÚë€É#Ý,ť„§VˇËI“!Ľ.BŐ|›ŘŻÉscWP*óŁAÍĂv‚ŠÇÇ|[]^ZËóŞÝ°żLđÇřžżQŐkľQ ýĂ:Ýš $¨ľ"ŞžÂSšŽ88Ţ!©U1wČzSŽŁěWě K‚*0j8+ ž ŚľP!ő&Ę10ŔĤSŔŻX)#rťîIď"PŃz0‹Z“LjŔŤüS’˛÷ŤĹ”Ć‘áŕUî‡6]Łâłč€ćE¶Í,ű)ŇÉ9 ˘ľ »ŕICyÉc_Eô@„2Ü:(ŇW—óLvÇTP9ČçµmgĺîTÁńGt\ŠodÝÚ!Ž'?ęţ…?[JÂŕVź’=Ö“fj¦LSpPZĚS> )'Wy —?¶űDa©mYP‰«-X»KôSäôÔšÇwh _íÓ×Ă–µbYN˝’gÔŤŽ•É&0T°ůV‰,+Ţ> e|NX‡»­±ß50úµJżá®: SŠ Ý罯ŽdĺtÍĂQ¦µą™Y›…š‚äÇčNFĽÂöŢ[_ňŰ’$5‡i-°‹q`”ş2răëîgPĂͤťD ź«` ˘ UôôZ%ÔôWwfsťŠÔýć ý–N˘ź«ţŘMŹŘhŰ3ËËM-{®Jµ –ëíÄ:¶_şÄ†Ľ‹MĐ| ü†TÄRĐO妮ˇVŃF'>ľp€WűSŚ?<Ż%s5L OXFň,p™’ą{Ťśţ4t· éN•z[ÎLԵ˚«ÁµÖäşFhd›ŠČVşçęŰšÂČŕ©‘Ó…­l,.LŮ3ľ„?ÄťUŹSÎ GöÇ­Ü Ä*±…ţ•úw¶÷ŐBóŐ§yµ/+y,žŐó]Ýﲰ.Á/açÍËraŚVi˝5`YuśsŤ‚¸ĽůcŰ1p†FëŠgS ²šâlmĚu$.2ĐÉH¬ń í%Ďů»©)Ch.•éÉ'§Ő_v­ ;ţŔżô˝sUŢĎŤŤ‰ZwąŐŇĚčťuµžŽX[â´ťŇ]ť^7d,)¨Ň„7ŠÓfĆU)ă—<«}Ä는BnަtĎŘC”’TzâPiśFAn_¶µ Ľ·Ů€ŃX$pż”Vńňâ•ĂaĽÄBŮő¬‹ŞŮÍďĽ1@óGĚą*8ö™SéĂ ÇúhĎsůbc pn†ňzÓ¬bݱQŻývžĄ+µ|žŞm´Ýźä‰Î˝ái@ÎQL N#+3—G¸L ä ·,4·łMdRnKUr°>aÖ:ŮĐ|ű‚]Iň­¦LńňŚŃMl őżTÎ5rS❡ Öđ&şĂâ ˘ cĹň˙”2<ęG{ŕóĹEâĺâY€Ä«`‡ßA*mĺqŢ. V>qćľĚĺŢ%qęJŮ^ń­-ĽŰĽßrŢĆžó`“ŁŹw˙B. ’Ţ1)jç«B1X›c•ˇŮŠĹ©źpKű«‘0} ]UiŰWi˝RH™´\Vr%ŞÍJ NŮv•4±í>sl°ĘK,Ó%±űʶýX nmýd„xÖwłmĘD\›ć~Ç?—+…ĺ>áą4í(.řĆKʇ¦†!.Ç4üÔíJü&őç\ůůE_ă–J'đ8 uXzú¬¦­ú%FSj!™5“=r6LÓ 9ÚťČ0€Xôg"cÉ{y–´ĹČőfśşvkŃÄZ^ky×€ýÝ×ă>€ˇŻ«l"°ó•ĚáČ´ľGš;ŽF^ĆdőiűP@ľĹfΡGTŮöpl&:ˇmr_ҵä*†)»6•)Ü|}Ť5sŹ›r\Ôťˇnż;áĽđ¦~–ŢKs o61J§„Uc6!ÓźÜlĘS`ĺCŐA^®}J`ĚJŁćĹ{+UÁ(ČÖ2‡"y^MQÝäÔ•ô8ĄĘ âSł•16‘"@Zľž·Áíľ?C`߼–Óuô!±őÉNŘÁf{iŚ—ĆJ‰c[ŠúÎ!ȧaňiŞâĂ(µľťB.›ŤËk1*Z”Q ­{žžůŚěźŘa ¸ ?*@3z­€rdĽĺş÷đN{‘‡çsIćpWݵ"Ę@edP÷Š;±íĺ·Íň/ٵŐ7‘2ŚÎÚˇtő™§¦›Ń>»Ť`drřľ€Žö×o{ç…Kú Źď_’ŔTĂÇęśrîY˘cďÄLJPŕ6ý>ó‘‰J6…ěÚ+‰t|‡ügpjľl9Ž ČqÚËR+tŇ-ËŚXnř’˛‡OÚ˝fćOŹ# 1†ôęyŽQ7ˇŹşáů-Ä׉Ü;ĹśH€ńÖ«őĹ…ąĚË˝QÇߪ¬{w”µ­cž”ű11ó{:J–ë|¶~›ŁH¶…ÁüÉsF‘öµ@P›ŢęŰz@5J˝“h~«.î÷¬˝~űÄ“~˝Âč×›če‘á·eOČÚL P™ŮuběżéixÝ‹Ä:g ¶ ţ×:€;ŐţhĎřHÇŤCâăd$]—î·8I\1™1z9RÂ)Á«yń†µEd»°C „Đ'jCa‘×»`ä´±ź¤N |ţ×xi §ů}ę} đŕ“łLWŘS•‚ďm){¶r•BŹí/ŠZc†;ˇ±ŔĆ Šg|UZgľâ–łcwş‹ź,%ˇś$Ě31Ί@AËq27´ŠŇF?ner6"Ć&ÜŠĹ»ĘňŻ\Hż#>ĘW؆jşÖń/‰ĄÔ±‡k6&§ˇHe÷2RčO?…Ąáa§˙™ą! °¸ŕ¶ÁüĐ‚l— %S,Uzüî®ÄËZmŮM pÓ¨ýcŔ€ň Ö©¶ß¨©ëťtÍ"¶śby0Ő[Og…ô54ý‘GxT(´vź„HK µz›.§©ÁZ7O¦wĘP"äÚń·q´ţ•”Đ+^ž™áęŐQóI\á°î…7ĄŽÜäĎŔ<„ŕ;tĆŚJZ…ßěśŘŤŔeâńřˇú´˙):;ĺ&>qŮÂÇËÇš±As"·řťhYšĄ?6ţU;Ú ŽÄ* ţV!kˇA8~Üľë·ô©bWždęŹWäé@˝c,e ÷Ç…-¸"¨K?EU}ŢE^ŃÓÂŇW[ä‚G}%»Ë/R¦ŤÄ>mp‰±ö†ĎrňEěŠĘŃçĘJ<ë,Vx"BÇA0őĎBÎčü#°§Ôl×@/ŢźË6ňŚ4óö×°göľĹ:ţ_KX×4Ő —ÜŐfc­\žľŐ&v||ˇÍp‹+Ľ+~ ë7źÉ;…loâ żżăµ čumL‘@o°([`´F¦Ĺ z€†ŕß ®u¸P‹.‡|ř›ˇ«Ç˝ôşGj2·Äx´ţhz—e÷¸´đ ő×K<‹· ín@7Ăe˘”b1jÖ Ş?×n+§"KżČ5g…E<aŇËŢÎţDäč"ňć~C8¦pžÎŢâd$ěY${pŇ,žPĘşä 3Ű{~KšŘ„Éë9úĚęŕs™Q¦OHł°ťŃd0Ѣz_╿ŐälK‹c­Ďě„ó`Á ;ŔĄ5örÇ% Ő6ľbkC„ń•RS®i{™]Î{ %lźYÖÝ‘#ňߎÖĐ\ŕ#‚Q iüwÂN9‹'Łé“G¦tűYä–Ś€mqš hWÚHËó‚m `*vٶ]¶"˝˝M–9Îű‹Ě ®i»ű ©ĺţ×$dĄnÓú;c•G7řÁŕÔßÚg·{{čš™Hć>Éč†ę‡ŚŻ®‰8µĹĂýPÍfžnvÁýxŔ†‰“ŢY§nŠ\T/ŚÓ;ÂŮĐHY]Č·đ|A´!±ůÄoMŤ¨>Wi%żőj =MudŕcÔ>¤šç±naďÎŚ?˛Ýś»+8Ú•óą^‡uÍÂý›&xRH·îo¶MrÎҰîvÄD€á¬{ç!A=…YŢ­çűó×҆ý3٦lN?ĂŢĆS53HőîX$Uőđb/ťÂľő­â#§ż.Ě‚GËr6đ=_˝ąçgÚj1%˘ŽXaç‰ń¤{­5“Ů dÉ7úę<6]"ąđÖvZ{‹ńp»‚Jů %¶ž·ĄiĆŠÓfĚĄJIMĚ‹’2ĺůĐŽÝŻĆó4îJ“ŽX=ĺŃĂ2$Xřw9î0%«^°i¤6 6őźyLmXűži(ňOµpXŔȸÉ<Őř5ŕ¨ŕĘ űýrVMCőŠ8jpíďÁgˇ7łP•Q©ôŐő9×ĘęÍY¦,Š|"Důˇčú#z6™×ˇÔŢ•‰wŕš\ÍtbśQÄŘHÖŃ–Ň ĄÖ™™äĆŞ|Ďylóő,çÖn H;""K_ %Č–B›Ę˙kµą+°?dŮ.掔YXżďH^yÂ/Ö‘Ă9=µ,ź­e±6Ş˘O‹Ř â%˙ŔNĘ—´Pţs"9,˘N¬UývŹaĆoHµÖúµâ ¬^„Ř–…żSľÓNĄ…(/ä„(ÄM„đ]Uf/cx î1"EʇsvöKríx;]ĚĂ7ut@;q9/47áŇĆĹÍčoş 2hyŇŇÝ,žÝ¶/™ÖŕČG=€/ß>IB—ę+ňńa€í|äbµۓ(łlv1š°ĐýuąŤćuŕ·8ŁŢŔŕ‘<ßwźšęTh?üšhgőţ<±í„ë[°QN Jľ'@p‘ó!aŇËç4Žş'÷JÝĺMu¦ˇ;Eś[OŔ ť};Ť‘«ź^wFËJ2}š©6Uxg‡˘Ěá\áÖ9M rŰ2Ĺ PÉ7·‡Ńá†Ô§@ŔŐĆQ”Sl'_®¶‹“­©›¦DŻŘXgąP WĹm‚8~v«°#„ĆłÜńŘęÖÜŽÇ4_üą· ʡN0óč[ÜZ=Ĺ,RÄ0ĽĂ?Ĺh†D9qâKłŤďQeYvë\śËą~¸KŚÇ€­›e’6Ţţ›ęìľŇÚqmeÝa¸éĂ҆Ě5t(Ŕeˇ Ŕ„CŤ,+ŃŔ *‘\˙CQđ’*÷bĎš6żdËi;rÄt#÷ÜFHźí H ]hqSGÝpŚl»ěRĂvđĐŁĹ»Ćtí†Ń*ŕ.¦đĺým{Ý6OëÖ}g$­áW´ţ± ęň‰3LéĘ{kšlvo팳Tó !¶ľťŻ4AT&NęĎ[QşrDxşIě*Ă”ŻÓîo7hŃśpϤ¦NCŘůTuÔĚd[on_@Ö/ThÓ:†4ď} ŻwĹŞ hhĎ•îţÂĄ›@çÚ¤úˇĚň›k©mε/ňî†6DŠ=2}d®2Ŕ¦Í¦Ů¶řrBVŠ–ß’˛™Ĺ˘gtăc3`ŚŔ5ß)áÝe,w—ď|¬ p¬HÂÓ»M´,‰ä+"#˙hőźEÂíEß\S·|ćżłH¦ew‰ÍÍ k`ą9I ąŞ˝H¨ź˙ Ř-JĘ´dŻr. =S·¦[QÝćáVM,ŞéÔ‡‚›?Oź?đ-Öą L*“±Ýʏ¤C7–ŔąHÔOé{ ŽsÁÇgmâOPË%ďć§LĽFó[±ňă€tĘ,ËMŮ*xúĚ[čÓąíś?ň•fÍ[™ĺĂQb˛ĺnKęď1® łÝtÚÂ3—řŔüϲn˝ĆhÍ}‡ř ]i´9R_);ľü-żŕÝ;é”YC Žť¶‘đk *Ś­±X×ú;žĆB>Ç™"Ŕ;J!MŘö9ŞÝę1’B®Şá&/Çť†<§ş˘śT rř«*äXSźň $˝őWŕ)€Á`.ÝŞpŮ–îĐďoŐFÝC~ź‡O…Ľ´âňč&¨(&HĚÉaCŹ93“®IßP+üştnF±{żíşöş!©'-ÁĄB[U$ż5Ł—W2¦t„!Ę”bBŁäbÁĆPGY…nf †wP|(ćlyćl_C˛ţçiŮy´ĹAÂc€Î)FÝĄíEĽŔé#XŃ7ŕČÓUAwéÔ·ŕ¦ä˙OĽI`üwÍĘLëä¨Ů•ßľ„ż—Et9qŻg‰§†«Ů˝+s4ÔŚĎú1úĽT”ÂÂó!ĘĚ`=4đ @`±¨YŃ{Y+M7ŚC&÷txv4µFőŢ(sʏZŁ|<@NnĘ8x ®e¶†(–Ćänm3˘ËKŃ4ŁÁł!z<· {Ľł ἠ:w†ĹBb\dwÚYĽ~YóAR¬Xsúśłîę_w śÓ‘ٱ±O˙',_™7±Ď˙+„KÝßďh« uÁ”LÜŕĄĹŻ ŠÎIŹ"?—ÔÖ÷ř›‘·pPéöžČ±Č ——o9 €•óy‘SÎ+¶®ąQ$ĂŰd5ˇëUÓÄ@ -ŔW¸¤ô'˝·oź>S´öŁÖjő[y©°˝•t¦)wxń6±Ţp> O;bŻŮL5/É7Üv¦§ëĂĆMr=…ę'ďnňwQ7LŞB–~„şł"žrO\ŮUń°ŹfţO˰9÷ ^¶yţ_üGv&Ú·;ŔĐë™7±ĎŕöĄɨ¬®ŤËxkv~”b™S©ú9tČdş R'ńÍá^Ż|äh{ĘŮËĘ…•’`µŔűg†ű™Ä­BČâ—Fg?›¶aŕ%ĐgcČęńŻâ¬8ÜĐxŤĚ˝‚|jf©eĐgä +°«ËŇż‡*±×v̲ŠMÉ6ŢđĚc†®…LNŚCŹĹôo˘8‘S%ݰ+ť”ŮI5e®’aűë…Í tYîSó“˝Sř;ÁďŃĽţ^EŻ*xŘ˝™ę.áÝě€'ôÂBă3Fýqif»zOÄW ĺň•LHŞ<’ ě šž5A Ş‹˙YIŃ}^ßŐh!óŁń«wË:Ę/ťčŠĘxQÝ­Í ±Îý˲ۅIl_Śźn˘šůďgýxa÷ń¶Őŕžš÷śc°Â_]’ż±đň¨łĂđ…őů§N6đ<ÉW#Oť<‹)YŁF{.mČJ´A{0ľY:Ěđ©2ڏ b@ÁžôćVh°íÔŢP“đ5™ERË)h”PQéţ&ޱ)Úµ™y·1[–ůű7Ýë|Óś*z 9iÜ ®˘*.ňż)un*ÇßPĽ€ DĎv*ţ‡ű&ŘGh+Ĺ 9ęŮ[óÂrjŃćż™:š&îÖqĘžPâ‡÷‡Î=őBGxAĶLůăÇ6¦ě}"®ś!ů9ďţ˘~µ’§ż—A9°—PPčň†łw©ż UŻ L€Ę°ů±íŃA1toWô!Ť(ÚH°ŃżóŽőLŞ)Ď]_‰ŢžôvGŹ'ôW'¸$ň;ÂEfŞësżÂŰö${¬9rgrë­…Q^Ż:e{ŇRZäî¶Ó7Ýi µ×Ř)ŢőŠőu@H 'cĺ[%Ýąâˇ:뤤Ш*©¦«fůĎłéIGK¨čôFé5ŕ[tťü’˙ô{€âĆ˝Ô5ú…¶ŮŞ 5ˇ~ąg}®z¡ăW~ŚŹ¨@˝ŤŢ™Žw˛řű=“çÔéW° ą¦ŚÉz˝çŢĎ50‹ľłiĚBŐ0ëí}:S?_Ą RŹ ’ ă,˝ń+Ň/<®–QeE‰YźŁ÷ü_®¨s⣸‘‘…ě„Ú98ŤžÇ}ŠÄ=ř9öÄôľľđܡ_Mń«P°áU:,6˛…h«݇ ýýÚ`QfŇX}=WCÚčýČÓnů-=‚ݬq8\'śŤAhčQ~Ý;SČ`4Ĺ Ńk&»lµ-Í™Š‡”Uşˇ†¤·?ů€`h)˝mŁ ąmŁđ,Ť!\0î˘ĹŐ<]ňŃ2äܮ۸ęjäëądŘ«ěÍ*8ľúE#ńj«ĹĆŃ ykұń™&çxÝ„N*°),zż4ýčÓhýŻK+ńe™ČčűŻď#LOD¬B:ęôŕČŔw 1Ťö9¶L°('sçmr©ÁQ·©%`Äi0č+ź.Q$ĎX5ôŤLA¸3đ} ß›`P"XQH@žÓŠÍ†˝¨ŕ!âHíâ+.-ćZJĚúywÁÇ”Ą“(äa«”°Ä0&a†Vę_¤ŰżóŔ‡ý’«FçĹŐxěj?BÇ˝Đ:8ÚUAÇLhŽ+đŻ=»îs*Äĺ~)ČNşH)Űś‡Ł<łřQVǶcĺ{^Âu4·r—„ Ó¸cĐ{2%|Oî䊵-¨dâ2v?ĘAĹEáô=]´ćlŘAŹ»xUgŰţĂ ĺ–ăč#éÖHyŚîY´ť–WŁŹŹŢ4A„•żµ'#ńĂ=?…Ö†3G†_|±%şÎvy]ţn°k§vftűËA^WM<űÂşçë1\׾#łµ;Nx_îrÉŮýŽěnÂČ•f›W©“půŠż-¨cikĆ”säž#"˛/KA"°n„ÄôÇ ůy`ŮDřîU_J%…)»—7ë ő>O1 eiŻ]ih-Îeď Çřň ÇXâőÁŔV\g¶ţĎdşč?ôKÉ ű5Z¤Ipa"ázŹDRŕa–e¬˝w©ď«ŽěΑ3>s]K_©ŚčđQžě|2ĚC˝ßâg60xÜÇŰ>‘Ężmµż!łBOäEek®~úIä°‘r/ď…^!ô)©ĎµßIŠ YSŰď5>§®ˇ…´±+|ÇůŔ/{öAJ.ćµ×ŕÝMăń· ĆTęíwĺÂ’XŘÉ=eĚĄĘË|ÝkHÖ/ŢŮ“}(ŐmB1•9„ŕ¨ë¬Sa)V(=#“ë*•3u€´– ­Ű€{Ž5˙dŠz’(đşK1öxÍ<ó¸]Ţ–9rŰ„š “ç –€+–SŽ÷f×6Ć[5ő΋qr†şAŻ?Ł<í1€}ÂĘ•Âä n]çĺ âň,/óĄ%hîÜhľ=€>ŽĘ¬é ˛ůÜNł‰(µ|ŻNýXBŔvä\:ÇüŠ!e|y(ä@@Š٦ˇËúŻ'±eě.±ń1eܨÄÝöK‹á‹ĘLĹ€÷ý¦É}Ick+݉dÁÚ®ŘNnĚ4™QbLµk›Ŕçô“đHqÄ ć“Wö•HůO0¦ÚqŤőw㵉íc ŤĹ$čÎĐ’ň; A”žŰŹ–‚oľ;F‚D4•])›Óů4ŐÚB5äŕ9űŤÖ ÇW—›Ť›:K‘”éµâf]R6„_Ýníß\ŃYŤ–{Đkźç ·FMHă•:µ&čÖ¸lP-Bb3“B­â|(ýhş- †üĽ.ö>Ísť'˝¶F›čbAÍ“ÓŔp_i¶),[SŇ VŻ# *‘gą2*×<®zf(’ŤbřBé™°ź¨n¬`ŚFäÚŽ&¨×jĽ*†[6VT_Ĺ]ĐŔ+)Jzfř ¦_#Śp¶´¸Ř’·>4|˝Č% /§n:ʰ·¦ĆFůhćXmFť’äo^.ÚřŞw•U X˙:·\9ôĎ—tŘhnĹj.zë384vs1Xß>ŁÉ1łź˙Ůih32Ůđ«_ćöčj” ÝÜÚ€ŮŘŘŮŮŘ€ŮŘŘŮ€ŘŮŰß$ “ŘÚ€ŘŮÜŢ€ß ÝÜŰŰŢáćŕŘŘÚ“®ĐŇŮŰŰ€Ú×ÚŮŮŘŘ×ĐŘšÄĘČ©ŚÍĎa-*'*"9  iĆĹŠ]˙ĘĎfsuu{y{ބޑš[KA?;7?3wĹĘ‹ëűů˙ĹÍa™ˇžˇťť  ¦¦© >11-(4uÄÉ‹îíěđÄĚc‡Ś……~|Ź{}y¦G/.*&+wĂÇ‹ďď€îíňÂĘd…|xŤy~{¤D,+(!vÂĆ‹€ňńňóőÂÉg‡„|y•z‚€¤M:98!{ÁÄ‹!źś›™—‘ĆÇfy|ulmšmwqvžA(* xŔĂ‹!('4 ÉĂgtwu›‡jijŤošA( yľÁ‹!."F/s7ËÂgppnŹ_gghe‰l–@# zľľ‹& ĹÁghjiiXedebbhŹ8 {Ľ˝‹„˙ĽÁ{Śšvhfgfrmš˘~plf`cQLJ‡ş»‹ńđď€đö¶Ŕj]]bh_abag^d„}ąş‹€ńđńňřµŔk[XQ„OWaX_\}" # ¸¸‹€ńňńóî´˝mWWO–wKNO„–I|! #€··‹€ńôěă᳼p[Y`bOQ›XjS^Š6$''$:$%-…¶µ‹!óóńÝŕéö°şnMJNWMDŽHWDO!&´´‹!ňôÚ×ćíüŻąoK@w1TJR‘# I6@•…±®‹!öĺçîńđü޵sTSZbZ@|He_dž<+/=}”Q,7а®‹!öëěóöńů¨łqJFGXA3s9WMT™" ™ˇ†ŻŞ‹!óôď÷ůđ짲qV\`gHQft||®L4!<"‡®©†&«±ÁĄôőňúňę禯pV[^WFJvUkgn­QNcf±J#­§„(ŻÄ˛›Xöőöóěâߤ°q|z}„•’žźŁ±ZPOhŁlkmZЬ¤„+´ľ2ů÷÷řřů˙˘Żnspnwnu‹„–•śŻPBBxuQ>BU‡¦žž“€´: ÷ódňř˘®o‡†‡‘Ž’™™ŁˇŁ­UJJ`b[FDM¤˘nĹ”©ĽČ+ #%(ypqstut¤¦l ˛˛¶łłŻ˛·łł´Ŕ˝˝ĽĽÁľżż€Ł¦†ľŇx!&*-ť–š›žžŁĄ¸Ş«Ş«Ş‚«,¬¬««¬««¬ł ¦Ď‘ÔI %(-1€|~„…†˘ˇŰÝŢŢßßŕááââ€á#ŕŕßŢŢÝÜÜ× ¤ʦµ“ $Z[^cgjkŁ ›š€™—––€•””“’•Ą&ŔSií@ 58>AGJL_„€„D„„‚€€~}{{zxwTEV‚ëh #).47:rxz|~€…‡‰Š‹ŤŽŽ‹‡‚}xsngaXf†‚_€,e|ËĐ: "',13ejsqrtuy}‚…‰ŚŹŤ|vpg`WQ>W†źn]9*czšÎÔi %&PTZOJIJFKRSY\^YT2,+8k»zS]5'Iu‹ˇÁŕČ~> -37432644989880( 3j•Ş…bCYU‡#Av•ĄąÍÜäÚ©‚pXA2+$ ',2BUezŁ˘‰†j9PUQŚ]~™´ĆÍÎËČĹÄĂÄÂŔĽ¶®Ł—‹zhZ35DZ`U ’Xx„Ž•›ˇť–Ś…}zxwskc^[ZS ź)?E1 ňđ«_ćöčj” ÝÜÚ€ŮŘŘŮŮŘ€ŮŘŘŮ€ŘŮŰß$ “ŘÚ€ŘŮÜŢ€ß ÝÜŰŰáćăÝŮÝŰ“®ĐŇ€×ŘŘ×ÔÖ€Ő ÔŐĽśŞ˛Ć„É©ŚÍĎhIEAC<5_.5+)-6+)(%," qĆĹŠ]˙ĘĎk“•–ťź˘ĂŻĽÁĎw_SQNIRE!|ĹĘ‹ëűů˙ĹÍeĎŐÓÖŃŇßÖÝßâŐQCC?9H {ÄÉ‹îíěđÄĚfł¸±°¨ĄÉ¤Ż¨Łß^@@;7< {ĂÇ‹ďď€îíňÂĘg°Ż­¬¤¦Ôˇ­©¨ŰY=<92 |ÂĆ‹€ńđńňőÂÉj¬°®«ŁźŐˇ®¬­ÜeNOM(3#")ÁÄ‹!°«©¨¦ĄźĹÇiˇ¦˘™‘‘Ü’ž™ ÔY<=!'ŔĂ‹!QD?JS-ÇĂkśťŢĽŤŚĆŰŃZ>0,€ľÁ‹!VJFdO‡SÉÂm••Çź’Ž™©Á”ĘZ91!‚ľľ‹!OA;:1-)ĂÁj‹Ś‹’šćŢ饒‘ÁP,»˝‹ţ˙»Á¸ĆŰ——ď×ď«”Üĺ·§ˇ™Ž‘}tr—ş»‹ńđď€đö¶Ŕm~}€ŃÔĐ‘…Ťµ04&†ąş‹€ńđńňřµżr~xn»…žé˘ž»…°>"''$?%'/‰¸¸‹€ńňńóî´˝swwlŘŻlwÁŮr±>#''%A%&1‰··‹€ńôíä⳼w{{nqŢ|’{‹żUCGGD[EEL¶µ‹!óóňÝŕéö°şvlinwodÎk€n{ąA(>*)H*:?‹´´‹!ňôŰŰçíüŻąvj^XkabÇeyr~ż@xp,MQŚCŹł˛‹!őçŰçčěů­¸wgdcn`aĂS~u€ĹKK'—-G•l=ޞ±‹!őáÜŕćńú¬¶wscl|dałV€v€ĘF,0o\f»/@ʰ®‹!öćçîđđü޵zx}‡d¶qŽ”Ř`QVd¤şyS_–°®‹!öëěóöńů¨łwlgk}gY¬a‚{…×G28*żČ1L”¬§„(łÉł k7ôőöóěáߤŻw©®§ŻŞłĐĂÓÔÚęxy‘Ę”‘“‚ޤ„+¸Ŕ‡G*,$ř÷öřřů˙˘­tž™™˘ Á´ĆČĎçukl ž}lp€“¦ž˘—€sƶN+-49,őňóóňňř˘­tĽ»şĂÁĹÔÎŮŮÚč~vuŚŽvv}–¤ uČ—ŻÁË?"05:>A{}~€‚٦t§·¸ŔşşĘşÄ˝˝ľĎÉËĘĘÔĚÍĐ‘˘¤ŤÁ×.38DHKy€‚…‡‰ŠŚŤŽ‘’’Śzuoiam‹‡g€,q‚ĐŐK &,05:>BDos|~€‚‚…‰Ź‘—šťť›‡}uof`QcڎqeAp„źŇÚv%(-278[_fd€b]bklsvxtpJEF8.'S„ż~Xg<T‚•ĄÇăÍN( >DFIHILJJNN€P JA$'H|¤µŤeId`‡#Iˇ®˝ŇßçÜŻŤzfQE?72/4;@DTet†­«Žt?[`^Śi‹¦żÍÓŇĐĚÉÉĆĹÄÂľ¸°¦šŹl^8>Piqd’e‡’ś˘§®«ŁŹ†……yqlhjb ź.HP:ňđ«_ćöčj” ÝÜÚŮŘŮŘŘŮŮŘ€ŮŘŘŮ€ŘŮŰß$ “ ŘÚŘŮŘŮÜÜÝÜŢ€ß ÝÜŰŰáĺßŮ×ÝŰ“®ĐŇ×ÖÖÔÖŐÔĽÖÖτɩŚÍĎiMJFH@9g2:/,1:.-+(0$! sĆĹŠ]˙ĘĎkš˘˘ĄÎłÁĆŐyaVTQKUI" ~ĹĘ‹ëűů˙ĹÍfÓÚŮÚÖÖëŰääčÚSFEA9> }ĂÇ‹ďď€îíňÂĘi´´±±Ş©ŕٱ®¬â]@><4 ~ÂĆ‹€ńđńňőÂÉk±µ±Ż¨ŁĺĄł°˛âhQQP(5%$*„ÁÄ‹!Ŕ»¸µł°«ÄĆj¦Ş¦ś“•ń–ˇ›ĄŮ\?@#)€ŔĂ‹!zkdinJ<ĆÄlź˘›ńË‘“ÔîšÖ]@4/ ‚˝Á‹!~oi~k—jÇÂnš™“ÔŁ–’ś¬Ď—Ď\=4#…˝ľ‹ yia[RJEÂŔl€Ž–ťéáě©••ĹS-»˝‹űýý˙»Ŕ–ÄŐî››ňŮńŻ—đöĆµŻĄ›ž‰{›ş»‹!ńđđńđđö¶Ŕn‚†ŚÔ×Ó•‘ş47(ąş‹€ńđńňřµľt€|pɡ릡ɴB%**'D(*3ڏ¸‹€ńňńňđł˝u{{mëľp‚{Îít¶B%*+)F)*4‹··‹€ńňíç겼w€…„puń•~ŹÄYHKKJ^IIQ’¶µ‹!óóňâçíů°şvqmr|sfßo…s€ľE,B.-M.>DŽ´´‹!ňőŰčëđýŻąxnc\oefŮg~w‚ĹE}†u1RU‘Gł˛‹!őéĐÚěîú­·xkhfsdeÓWz„ĚPP,ť2LśrC’˛±‹!őĺâŕßôý¬µywgp€heĂZ…|†ĐK15tblÁ4E’°®‹!őéëňńňýŞ´{‡|‹„iĹu•“šŢeW[jŞÁZe™Ż®‹!öíďôöńú¨˛zplok]»f‰ŠÝM8<0ĆÎ6BN–®Ş‹!óôńřřńđ§±y|…Š’s}Ǥ௯ěv_P6ĆjCGS–­©†&»Çδóöóůôí쥯x}qvş†ł›ŁězzŤŽÝwUER–«§„(żÔ»Şt?óőöóďć䤯y®´­´°·ÝČŘÚßđ…~~Đš—šŞ¤„+ÇÉN03,ř÷÷řřů˙˘­uŁžť¦ť¦ÎąĚÎÖí}qs§Ąsw‡•§ť­˘€sŇÁU14Dtuz~‚†‰˘ ›š€™—––€•””“’”˘>Ę_ýX(/5:?TY]cglmj…‡D†‡‡††„„‚‚€~~}{zZĄ”Qhšű&.5;AGMSX]a…‰‰‹ŤŹŹ‘“”•–——–’Ť„ysmdo’Žl€,{”ŢăS'29?EKRWZ|€ŠŚŽ‘”śž˘Ą¦¦¤ŹŠ…|vmfVgĄzlB*x“°âć€+)5=CJMkpxwwvxsw~~…|UQP@6.YŠĆ†bn?'XŠŁ¶ŐđŮ’W0%-KRWZ\\_^]a^`^^UK,.QŞľ—rUlf‡#LЬ»ĚŢěó縖mXLGA:8=DIN^p‚•ĽĽˇźŠOdgbŚl‘®ĘŮßßÜŘŐÔŃŃĎÍÉĂĽ˛§žŤzlJO]x{h’h‹Ł©±¸µ­Łś”’ŹŤzuopd ź0KR:ňil32őÉbďö÷ďg‹ *âŰŮŮÚÚ€ÜŰŮŰÝŐŃŕ=„‚ÂĎÇĆĆĂÁŔľÁĆĹÄƬŞČ»†É˙΄{v{}‚‘‘~72-1#҆ţňńńöLJ“ť{©3.)=ŽĐ†űîííóć‰|źzw‚y”— %%ŽÍ†‚˙ĹŚ~fpqq‚\=2%’ʆ"҇wlq\ehdt>Ȇχ„lbehc‰0|dh@0ŤĹ†˙úűúý˝Źphnfege‘0 /""”†ýńđńů·Ť`QrOY`]u<,‘Ŕ†˙ńóó鵍VDťZLgTz‘.’˝†˙ôĺăń±”^UZX\žXŽ/50@04–ş†˙áŰě˙®ŹH7P?B‘=‡KR /N,“·†˙ŕęęú¬E6P?0Ś>Ť.W7v“µ†˙ĺîň˙§–YQ\RJ‹_˘?7‚…B7˛†˙ëřňî§ŹPIb;C‰Pś'T–Ż…]˙óří楎TPWGQ„i°hOoc –«ąÎ“6˙řöďň˘‘‚r}‚Ťźź˛_V”€ok—ĄĂΩ, ŕĐĐŃע‰†}Ť¤ź®^@{e@C“¤uÖĹ"ź•—™ś˘Ťsvxtuxtt€}|}Чʞ»‰&)|€„„ŁÎęěěîîďđďîîíěëęŃĄ8ż<ŃEIOUVž ś›š™––•””“€”C—q± #+36fnptwy{~€€yrkcXOMŽKOŃi (-cldedirxy`XJ8%urV€Hv¦Ř˘\-62485<=<9)!VyŤtQP!V Čć긚‚mbXV\dpw{†nzMHTMś§¨Ş¦˘›‘‡wf[OJOY“%0¬Ébďö÷đg‹ *âŰŮŮÚÚ€ÜŰŮÜÓŘŐŐ=„‚ÂĎĹĹÄÁż˝şľĆĹĹŻ·¶˛Ľ†É˙Î‡Ş˘¨­´ŃʲOIDH:ŽŇ†ţňńńöLJŴ˛Ş¨ß¤ä=>:P ‘Іűîîíóćą˘ĺą˘Ş˘ÜŮ-76’̆˙üüţ˙ÄŽ´Ł¸łŐŢŘŮ}OG9-+—ʆA1F?#ĐźŤˇ±ýóűŐ`'* “ȆB2782ˉşÎڎţđüÚB»škVŹÄ†˙÷ůřüĽ“—‰Ź‘äúĺÎE77I9:†ýńđńů¶Ź„nťŤµňĽĹ`H!—Ŕ†˙ńóó굑y^â†v „µÓ N %•Ľ†˙óĺăń°™‚rzzŕÄKWQcPU›ą†˙ăŢí˙­“jSpbeŃeżkuBRrO·†˙Öĺěú«“eSqaSËhÇN|]ś+™µ†˙äěň˙§™Śr€xpÉŚßa\¨¬j`걆˙ëřňí¦“tl…akÄ}ŮK*|Ş3@›Ż…]ţóřë䤑{t}nxÜ–čŠt•‹;@ś«%˝ÎśL˙ř÷đň˘”˛ś©°ĽŮŇ넼¨—”ź¤ ÇŃ®@$ ŕ€ÓiÚ Ś˝®Ŕ»ÄáŐę…o§‘qw›Ł}ÚÉ-7;§ ˘¤¦ˇ‘wz€yz€zzЅچ‘Ł –¶Ŕ”4<@ŤŠŽ‘“˘ÎęëëîîíďîííěęęéŇŁIÂ@Ö'.UY`dgť ś›™™—–•€”G““””—–{„—ą(06=CGmsvx|~€‚„}xqj`WY‘TZŹÖw)3:?mtvxv|†Ś“‹sk^N?›u^€T®ŰŞk1=EHKMKRUVSB':kŠ–w[[#dŹ«ĎčíľŁŚyofchr|Śs„XRb\Ž©˛łł±¬˘™qe[W]j“/;¬Ébďö÷ďg‹ *âŰŮŮÚÚ€ÜŰŮÜŇŢÜŐ=„‚ÂĎĹĂÄŔľ˝ąľĆÄĆ­ÄűĽ†É˙ম˛ąßĎ·RLGL<ŽŇ†ţňńńöLJ˹´®«đ§ç?AšÂ†ýńđńů¶‘‰r¦Ź¸őľÉh"L!$–Ŕ†˙ńňňďł’~a÷Žy¤‰˝č$Q#(—Ľ†˙óéčö°›†u|}‚ôĘOZVhVZśą†˙ŕçđ˙­•nWufiähĂp|GXxT™·†˙ŐÚíű«”iWvfXŰlÍS!‚b˘1šµ†˙ęđó˙¨š’v…}tŮägcݞpfˇ±†˙ďůňđ¦”xq‹foÓ‚ßQ0‚±9Eť®…eţôřîꤒx‚t}č›îy›‘@Fž«ČŘĄV˙řöđőˇ–·˘ŻµÂĺŘńŠ…ÂŻť™˘¤ ŇŢ·G*(ŕÓÔÔŰ ŚÄµĆÁĘěÝđŚu®™x~śˇ‡ćŐ%3?D«¤¨¨®ˇ‘xy€{zy|چ„Ť‰’ŁžŔĚť$=FL•“—›ź ÎęëěěííîîííěęééҡNËJă &1:afntxśž›™——–”““’€“D”••ЦÄ&3?FOW]w|‚„††‰Š}vndY`Wbźă€!#6CNUz„†Ś•š Ł–|tgVE…ˇ~c€WŚ˝éµs:&KV]`caghf`N0Dp’ c_(fµÜöůČŞ“womrz†Ť‘ž†™g[f]“°»˝żĽ¸®¦śŽ~pfadl“-9¬is32öł€żş‚żł€Ć€=‚ Čę˙˙˛7ź*’”€Ĺ€˙¬$|.LHj€"ż ·e2cQuO"¸łz J1u¶€˙qť—w‡¨K<˛úňň–)„+ErŁýÜú/$q9 ˇŁôçü‰4, fA yžřôü„;5-_H 8S™˙öě}@93VM7,“đčńŠŽŹŹŽŽ“‘’“k{:$ K–ˇ—¨Ëě˙é`}š¶Ěן“ ľÚöřńëŇ\sŹ«ĹÖł€ľ¸‚ľł€Ĺ€]‚Çę˙˙ŻZçĽ?Ď٠Ā˙,©@´Y•yź ľ?4Ż’)gŃŽźrAµ?;:­5ł'ˇT­ ·€˙™=ݰÄćh_¶úňó“N-´Oh1šźýÝú‹UD3žc-BÇ=źňăý…^PD•m2-ˇ1šřôü€fZTŤx4c=”˙öëyod`‰‚-f^<Žîçđ‡‡…‡ŚŠŠŚo‰O?7."&5[ť¤•¤Äć€˙ţĺ]z´Ëע“ž»×óőďéŃ[sŹ«ĹÖł€ľ¸‚ľł€Ĺ€d‚BÇę˙˙ŻZüÍ@Úí Ä˙ý˙§AĹY—{Ż ľkW3­š(hŇ’¨yE´k]UŞ8Ä(ĄVľ ¸€˙@ňÁŐřm#d·úňő‘R/ľQm6 žűĺý‹[H8¨h2GÍCťňŢ˙…bTHťs73¨8™ůőţ~l_Y•~:j†D”ţöđwuie3mfEŽ/ëć톄††…‹‰Špˇi[SJ?3)%10/3?`ź´Ą°Íę˙ć\{—łĚŘłŁ«ÄŢ÷ůňíÔ\tŹ«Ć×it32uMłýýýýýýýéöôô¬őôôöëÄîęë°éëëîÂÜĺć´äćéŔÚŕ·ßááŮ˝ŐŰąŮÝ×˝ŮŮŘŮŮ„ÚŮÚۇÚŰŰÚÚŰÚÚۇڀŮÚŘŘÚŮŮÚŮÚÚŮŘ×Řĺ»ÝŢßââ€ăä€ĺććççčééę€ëěííîîď€đ"ňđďďîîííěěëęęěîđóő÷ůřöôđěéĺâááŕßŕć¸ŰŕŕÝŘŐ†ÓÔ„ÓÔÔÓÔ‡Ó…ŃĐЀςĐŇŃĐŃŃĎŇŘŢĺ¸ŘęÜÖĎĚŽË…ĘÉČ„ÇĆÇĆĽÇÁL¶ČbËÄĹ»ĹĆÎŮěł·ÖÓÍËĘŠË€ĘÉ€ĘÉÉ€ČÉ€ČÇ€ČÇÇ€ĆÇÇĆĆĹĹĆÇĽąĹ¬”ÉQ ĎÄż·ĂĂÂĆ˶ËĐÎËĚÍĚÍÍĚĚËËĚĚ€Ë ĘĘËËĘĘÉÉĘĘÉÉČČ€ÉČČÇÇČȀǀĆÇČĂČĆÇÄĆĹĂÄÂĂĂÂĂȵĎĘĘËËĚą‰“€’‘‘€’€Ź€ŽšŤŽŤŚŹŚŚ‹ŠŠ‰Ť‰‰€€‡††‰‚… „„€‚ڧÄÁÁÂÂŶπËĚÁm7765543207.--,+)H&('%0€#!€$!- & .ZşÂÁÁŔĤóŤüýÉËĘËĚąwyz|{zz€y$€z{{}~~‹„…†ŤŠŚŽ“•śO654A110/.,++)(%5€#!!=;A88766"PhşÂŔżżŔƢŮűŤřűĹĘ5ży|~„y~z‚Š‹rrtt„wz||……‡‰‹Ś¨O99H565210//--);'(&&€ DhşÂżŔżżÄ Çšô÷ŤřűÄɀȿyw~~}(‚||}€Ś‚„…†Ť‰‹ŤŽ’“¨–47G554311/.-+):''% FhşÂżľżżĹˇňřŽ÷9űÄÉÉČČży‡Ž‘—•”’•—’ŽŹŹ—‘’“”™–š›śźź­±h4F44220/--+*(:%%"‚ GgşÁżľľ˝Âˇóňôő…ö÷üĂÇÇČÇżyَ¤¤ˇžš™ś™ťš›śś €ťśśť›«¬ł,F43210.-,+)'9%&‚GgşÁľÂˇćę€îí…ěńÄČÇÇĆżyŠŤŹ•ŚŠ……Š…‚‚ʇ€€|šŻ*E121/.-,*)(%8% GhşÁ˝˝ĽĽÂˇćęŽîńĂĆÇÇĆżyŤ•ť–ŽŠ†„‚€‚‚€~™›Ż)E010/-,+*(($8„HhşŔ€˝ĽÁˇćęŚîíîňĂĆĆĹĆży€‰ŠŚ•ŹŹ‚‡€€€|Ź}€†€€€€~–šŻ'D/0.-,+))'&$4… HhşŔĽ»»ĽÁˇćę‹îíîďň€Ć1Ĺży€†‘•“ŹŽ†~„†…zŹ„‚}}„}€€}–™Ż&D./-,,*)('%#…JhşŔĽ€»żˇćę‰îíîďîďňŔĹÄÄĹży“’‰Ś’}„||}{t„w€{„{}}~~~•Ż&D/.-,+))(&'… JgşÁ»şş»Ŕˇćę‡îí€î€ďňŔĹĹÄÄży|€…Љ‰†~‚zz€xŹ{}~|‡~€€~”—Ż$D--,,*)('%€ LgşÁ»şşąľˇćęîď6ňżĂĂÄÄżyz…’‘•Ś‹ŤŤ’vwx‚‚~–€~„y|}~{||‘•®!C**)(&%$$…KgşŔ€şąľˇćę„îěî…ďňżÄ€Ă2ży%}‚„…„~~~}~…›†‡‰€„……—š±:LAA@?>=<:' +]işŔąą¸¸ľˇőýŹ˙żÂ€Ă2żxw{}}†wv}ttu}}y–|}{w~svvxxy{Ź“­"C+,*((&'  NhşŔąą¸¸˝ˇ% ŇÂÂÁÁżxvz{{„}uu{€rqqn‘oqqr|rtuvwy{Ť”­!C*+*€(€Ohşż¸€·˝ˇ€$A#"! ŇÂÂÁÁżxuy€~vr{rppusp“prpp|qrttuwz‹‘­ B*+)(' € Phşż¸¸··»ˇ€$@#"! ‚uAŃÁŔŔÁżxsz‰†‹ŠŤ‹Ž}nnvxw™yvnoynqrstvy‰Ź­ C)*((& € Qjşż·¶··Ľˇ€$?#"! i‡"Tk) TËÁÁŔŔżxrtuz|xpnwkllour–vwut€vwuqstx‡Ž«C')() ‚ Rjşż€¶µşˇ€$?#"! «rr‰‡…e ĐżżŔŔżxprsx{zzyx~ijjmwpšqwxvxy|vxrw…Ť«B'()‚"€Sjşż€¶µşˇ€$#"! j xx qrĎŔż'xopq~yxvu~slgkto—ehhiwilmopqvŚŞB&)"€ Tjşżµµ´´şˇ€$#"! `f `gh-pÉľż&x mnwsxqvhhnaaekqmťmqtszhilmnpuŠŞC&'„$€Ukşż€µ´ąˇ€$&#"!!  Ďľľ˝ľżx llz{zqxgaŞ©Ż^g€pnorn«¨¨hkmot‰©C' ‚$ Vkşľ´łł´ąˇ €Íľżx jj‚†z€yi©V\Wes€oln]ua¨djknr}§E€%€ Wkşľ´´łł·ˇ÷ţŹ˙*ą˝ĽĽżżx hfgjlpqgb­`dVdkhkhjjWtf«fskjqx…¦7†$ Vjş˝ł˛łł¸ˇçë„đďđ…ń ö·˝˝Ľ˝ży*mnŠ„€‡xxukj\€giggh[qootuxyŽ«53%†'%4%'€&%%$6jlşľ€˛±¶ˇčë‚đďđńđńđń÷·€»(˝ży"fdnlqwuspuWTWceedeecY\[ceghhqv„§'„&Zjşľ±€˛¶ˇčë€đď€đ„ń-đńň÷¶Ľ»»˝żyb`pjnsmjdpbaYefegfee[l^b`acdnr‚ !€€$‚ Zjşľ±±°°¶ˇčëđ…ńđńňńň÷µş»»ĽżwExx”Ťś—™ś‡zc€f/gffeis^_•‘Ź‘’”˘^s``][YWSQOMHZCB@=;953Anqşľ°±±°µˇčëđđ…ńđ€ń€ň,÷µşşąĽży!_\][kjge_n`c]effgffe`p]`^`bdmmsś#‚€&„ \kşľ°ŻŻ°µˇčëńđ†ńň÷´€ş&»ży#_]\hky}iao`_]dfeedcaZk\^`bdepavť+† +  ]kşľ°°ŻŻłˇčě„ńđńňńň÷łą¸¸»ży"]ZZdifa^hg]ccUd€e`TXkZ^_abec_vť,€ , ‚ ^kşľ®®ŻŻ´ˇéě‚ńđńňńň.ńîî´ąą¸şży#\XX^XV[USZXSUS_gdg^TUiYV]`b\^_vś, … -  !_lşľ€®­˛ˇéě€ńđ€ń‚ňńňđčßâ´€·(ąży$ZVVmutsjtŻicX\`HgH`VRiRŻW_^O^_vś- € .  "`l»˝­€®˛ˇéěńńđń„ň1ńńîâÜŢ䳸··ąży$ZUTVdebTQ¬CLSR]ed_Z[TdJŞV^MQ`avś.€  . #al»˝­­¬¬˛ˇéěńńňńň3ńóđÝÖÜŕ沶··ąży%WSQ[ccafa«¬˛`cvvq_]aP±««VNNQ`bvś/ € €  / #am»˝¬­¬¬±ˇéěňńň5óóĺâÝÚÝŕŕ㲶¶µ¸ży#VMcKSXTRSZ9ńôŢŐÝŕâäçéëîńôü®µµ´¶Ŕy&STa\Vd]a]j]aYVf`ZbVZlADGKNQ`hxž2  € 2  %fm»»©ŞŞ©®ˇęí€ňôŢËŮÝáăćéëíđóő˙®€ł'¶Ŕy'QNWTV[X[Qb__JGXRNVYYc@DGKNQaizť2 € € 3 &em»»¨ŞŞ©®ˇęí€ňEęŘŐĐÜáĺçęíđňőř˙­µłł¶Ŕ{'QHEkVk^kR\HJKV_\•OX]YaHNFLORbkzž3  4  'fm»»¨©¨¨®ˇJęíóňőÖŢŕŰÔŕćęíďňô÷ř˙¬˛łłµŔ{'OHGD@>8:8R;@BNQSŠXa`HdO[JLOSbm{ž4  5  'hn»»§©©¨­ˇDęîóňćŕŕâäâŘäęîńńóůú˙¬˛˛±µż{'OGD_ZPR5@cYe[YmfhhbhuaiOLOSdo}ź5 € 6 ‚ (in»»¦§§¨­ˇęîóőÝâäĺćçčßččĺëíëňţ«€˛3´Ŕ{(OFD]c`S\\bHO^GURŤUJIL\CIMSRTdp}ź5  6  (jn»»¦¨§§ŞˇJęîóđÚâĺčéëěíŰéňóôöńń«±°°´Ŕ{(OEBGNNTC>RBDEDJI‡E=AD[JPNVRUfs~ 7  7€€ )kn»»Ą¦§§¬ˇJęîôćŕăĺčęíďěëńđóőóřô«±±°łŔ{)NECffp^fpybijpVM‡+49;WAHKNRUfu€ˇ8  7€*ln»ş€¦ĄŞˇęîôăáăĺčęíďéňďňęęňö˙©€Ż2łÁ{)NECKR[STWbCFJ`VV„AQ;ęîőááăćčëíńç÷ńíđóđ÷˙©°ŻŻ˛Áz'NOGSV`W]QjTPULX9€1@6:WAFIMPTdw‚˘6„ 6 (kn»şĄĄ¤¤Şˇ>ëďőăăäçéěîňçůńěóőô÷˙¨®ŻŻ˛Áz4Z[Znpvmpwntowzx_Źhnnar]adgjmz‰‘©+J7€9::9ow{vG7988:yq_Gq»ş¤ĄĄ¤©ˇ[ëďőćĺçčëíńóěöőóďóöúű¨®®­±Áz)OGDCLUQXQ`ILAEJF‚D?;=^CJPTRUm€¤9 /aG^oY @gd+mo»ş¤ŁŁ¤©ˇ[ëďôéćčęîđóőőířőôöűűć©­®®°Á{(OFDifmpdm}loh`b]_qei}qoxtw€€”¤: L) [‡  ytC,po»şŁ¤ŁŁ§ˇ[ëďôöŢęíďňô÷ůöëó÷ůóß設¬¬°Á{)PFFU`K`[UeTQCKYP‡OLED^JOTUY\kŠĄ;>«<‡y-po»şˇ˘ŁŁ¨ˇ[ëďôöĺěďńôőřűřőěäáâćé§­­¬°Á{)PEDVQLONTcOF5DMN†N?=?\FMQSW[k„ŚĄ< ’I €“7.qp»ąˇ˘˘ˇ¦ˇëďőôďęđóő÷úů÷óńîëčäć§€«?ŻÁ{*]chiw†vv~zŚž|zŠ‚—}rvvin…ڤ; yy$©~ .qp»ą €˘¦ˇ[ëđőőöćóô÷ůűřôńîëčĺă䦬««ŻÁ{)TNOU][YQQe;@DHJN{[ef`ngo{€‹•§¦ł7\( c¬m´"/sp»ąźˇ  ¦ź]¦ęđőőöôé÷řűřőóđěéćăŕ⦪««®Á{)URR]]dccdf@EIKN]epo`oimwy{~‡źĄłQ€hljZH5#;Ř˝s.rp»ąźˇ  Ąś®§ëđ€őQôňďűůöóđíęçäâßß¦ŞŞ©®Á{)XWXW_aff\hLHJLO]cgc_jbahlsv‚ž¤łThjhhecbdS?&/ĹgĘ0sp»¸źĄ™ ¬«Ş¶ż´ëđ‚ő óíůôńîëčĺâßÜÝĄ€Ş­Á{(€Z/^jecVF\HMOQR_cjknksuy{€‡žś«"[BQ`outpke]Zs©Ée€ 0uq»¸ž źź˘–´±®ąŔ݉‰îđőő€öTőöéěđěéćäŕÝÚܤ©¨¨­Á{(krkjnsiYZl\`abeq‰rlmpsvy{}‡ś ®*X35406ETcpohz·NUA(/uq»ąťžźźŁ”˛©´¶Ä˛Źx‚‹b#öđöőö4óčăŕäáŢÚŇؤ©©¨¬Âz&nw~|‚ptu~pusrvx•†Ś‰Žś“–™śťśťĄĄ±2a4‚6 530>Js’›[W€O 9:sp»ąťžžťˇ’´ł·ĽĹźpn]. ůń„ö8őö÷řőëéčęő˙ˇ¨§§¬Áz4r{‚„…„‚…{€‚™Ź“––ťśšśź ¤Ł©©łTj\__`€_^^][gµśiyxtnex„s»¸śžžťˇĹ®şľÇ“^il; úń‚öôö÷ö÷-ö÷˙ ¨§§ŞÂz(jnl}szndnagimqu‹~„‡‰—Ž‘•™ťťž©Ż5_@‚BAABA<‡Ž‹:;FS]Ygtq»¸›ťśś Ź±ĽľĘšSa\' úńö…÷.ö÷ř˙ž¦§§«Â{(osvtlqqnw{imowvz…‡–Ť’”–™ťž ¨°;cD‚GFGFF>§h@DCA?Ihuq»¸›ťťś–ŁŚ˸żÇąYSW ÷ďôő†ô€ő+ý ¦¦Ą«Â{)v|~‰Š‹Ś~“Ś”ŚŹ“›“•šśŁž¤Ł§¨¤ˇˇ˘ł>fH€KJKJJIJSŁ]{EGFFECTxq»¶š››™µŻĽ‰¶˝ÄĚ@X'!#řî„ňńň€ńřꀦŞÂ{)~‡€€‚Ś‚„‡‰‹‹”“••ˇšťź ˘Ł˛CiLOONONM_‚i€JIHGYyr»µšś›™Ŕ˝´¬‡´ÁÇÍkF? "$%ť¤¦§¦…§$¨ĄĄ¤¤©Âz+db]__`abcschijkl~nqrs„tvxyyz€{%KjOQPRQPPQPPO‹zMLKJKIGZyr»¶™š› `Çľ·«…˝ĂĘÎ]I! !"%%'#T€€‚%„‚§ĄĄ¤¨Âz4H6;==@BCDYEIJKLMgNQRRhQUUVWW€XZXrZ[Z[ZYZXnTWVUUTSRc€s»µ™ššź?HÇż¸®…ÄĚŃjD  !#%&'*(dťśśťźž  ˇ˘˘ŁŁĄ€Ł¨Âz)šĆËĚËËÍ˿ˀĘ̇ĘČËÉ€ĘËĚÍËÍÎÎĎĂwq»µšš¤8WĆľ¸…ÄĚĚ›< "$$&')++a—••–——™€š››śťť€ž ¤¤ŁŁ§Âz:¨¶»ĽĽ»€Ľľ€ą ¸··±¶µµ´¸ł´˛˛„±¶°˛±˛˛´ş¶¸ąş˝ľľŔÂŹr»µ™—Ł 1‹żż·‚6®ĚÍÓ?  !$%&')+--]Ť‹ŚŤŽŽŹ‘‘’““”••—–¤˘ŁŁ§Á€;lx€|{{zz{wwutssrpoompkkiihgfeffeh€e"deddefgjnnptvxz|~~rmĽ¶—™™˘1Ĺľľş'ĆŃΙ$ #%&'(*,..Y„„„…††‡‡‰‰‹‹ŚŤŽĄ˘˘ˇ¦ÁĽ¸©†§€¨…©«ŞŹ«‡¬«ŞŞ«µ¸˝µ€—˘żŔą‚ÍĎÔn!$%')*,-//Tzz{|}€~€‚……†‡†¤ˇ˘˘Ąľăěě‰íëĄíěěëş´–—ˇ _Ćľľ‚2ŃĐŮ<!"$&'*+-/00Pqpqrttuvwxzz{{|}~}¤ˇ  ¤Éň¶îďĐ´•–—ˇ /ČżŔ‚2ÓŃŰ,  !#$&(*,./10LgghikkmnoqqsstuvxyvĄˇˇ ¤Óĺäĺĺćçç‚éëę€ë‚í€î‚í€ëęęëé€ç€ćĺĺäĺ€äต––ź ĹľĂ,ĐŇŮE  $$&&(*,.021G^^_abcdegijjlmnoproĄ€ź¤Ż€Ş«€¬­­®®€Ż°±†˛°Ż®®­­¬««ŞŞ©©¨¨§§€¦€¤ §•––ź 7˝şľ‚/µŐŐ !%'+-0ASVVXYZ\]__abcefhijeĄ źźž„ś›„𙄗‚„—–„• ”ž r´¶§‚-„ŘŐŕ  !-:<<@BEFIKNOQSTWY[\XĄž€ź žžťťžžťťśś€ť śś››śś››šš€›šš™™šš€™€™ ————––€—––••––€•”€•ž ´®ł~‚2JŮÖÖž !#*024689;;>?ACDFGIJLEźžťťžž€ť śśťťśś››śś€›šš››šš™™€š ™™™™——€— ––——––••––€•””••””“””t¨©°Q‚.JŤŰÖŢW  "$&(*,.013579:<>@ACD>5Ą€¤Ł‚˘ˇ„źžž„ťśśťž†ťśť‡ś››€ś ;¦Ł§O‚/P[·Ů×â= !"%')*,-014579;=>@BD@3AWY€Z[[]\]\]^^_``€abbceceec%bba`_^^]\ZYXWVUTRQPOMLKIHFEDD)'ˇśź”\V‚6MbeÄŘ×âP  "#%')*-/12458:<=?ACCW|z{{|}}~~€€‚„……€†‡‡„‰€%‡†……‚€~}{zywttrpnmljhgeca`^\J—”–”a`PBmdmÁÚ×â…  !"%')+-/12458:<>@BAkyxyzz{|}~~€€‚„…††‡€‰Š‹€Ś.ŤŤŽŽŹŹŽŽŤŚ‹‰†„‚}{ywusqomkigdb`^[ZWQvŚŽb^lxLhio°ÜŘÚĹ" !#%')+,.01467:<>@@hstuvwxxyzz|}~€„…†‡‰ŠŠ‹ŚŤŤŹŹŹŹŽŚ‹‰‡„‚€}{ywtrpmjifda_]ZXVRMV‹‘Ť„_^aO…vegmr”ÖŘŘ㇠ "$&()+-/13569;==cnooqstuvxyz{|}~€‚„…†‡‰Š‹ŚŤŹŹ‘’“””“Ť‹‰†€}|yuspnkhhca^[ZVSOKIxš”’“s[]]d‡tmiqx~ąÜŮŮŢq  "$&(*,-/135799]hhikxtwypqsuuwxvxy{|~‚„†‡‰ŠŤŽ’’“”•”“‘‰|yvtqpmheb_\YVSPMLHDAOP}®ť™›Ś_[YZh‰rmnq{~’ČŰŘŮß{  "$%')+-/1355V`abdnbhiQRVWTUVSOQQSUW]^]_acfhhkllonkihg]A?<:8<90-+('$  u˛§­ˇškVZX]g‹Fbvr|‚śČŰŘŘä ? !"$%(*,-//OWYZ[f[_aMNRRPQRSOMNPQSXZXZ[]_aa€c&eda_^]V=975263+(%#! 4eŠ«±®ŞqOVUVd^ŤnA{tz„Š‹ťÁÚÖÖÜÖ‚,  "$&'()ENOPR[RUWFFJJIJKLMHGHJKPQPQRTUVWWXWYXTSRPH40/,)-*"  $Zť‘Ť¸ iJRRTXmAAkx‹‘“š¶ĐŘŐŐŢÓ†?  "";CDEGNGGK=>AB@ABCDD?@ABFGFFHHI‚J$KIGECB:)'%" "3a—źšź¤ |SHNPQTha’;*w}‡—›śŞŔŇ×ÓÔŮß­l2 0678:?;:=246767899:8678:;€:;<<;"::7532,2aŤ«Ł ź¨©…`AHKKMRei+–8x†‚Š”ś˘Ą§˛ĂĐ×ŇŃÓŘݲ~L€ $(*+,0-+/((‚+,€-/,*+--,,-,-,,++**(&$#  :k¤ÜâÔÇľľ¤X9@EGHKRhg6š&qŤŚ– §­°˛¶ÄÍŇŐĐÎĎŇŘŮł‰c?€ € €(  7Odťžš ŻÄŕŇŞ}K9;?BCELYna'ź"\“Ž”ž¨ŻµşľÁÄÎÓŐŐÓĚËËÍĐÔŘħ‹r]H4"€"*:J[n€•Łźś™–– ¸°–~eHP[SK@>AGUkkQ¤g‰™•™Ł­¶˝ĂČËÎŇÖŰŮÖÔŇŃÍÇ€Ć;ÇÉËÍÎĎĚ˝±§ś•މ†€‚†ŠŹ–ž¦±˛Ż¬¨Ą ž››ž®ş±˘‘~c6')/=KX\RLKVllX© b‚śžť¤®¸ÂÉĎŐÖŇĐÍÉĆČËĚ€Ë&ĚÍÍÎËÇĂŔľ˝ĽĽ»şą·¶´ł˛±Ż®®°¶˝Ŕ˝¶ŻĄś’†wZ@;€: 85402@O\fnvgQ°9nŠ ¦Ą«˛ĽĂĆÇČČĆĂÁľ»¸µ°­©¨¨Ş®Ż°'®®««©¦¤ˇś™”Ž…yj^XVUSSQOLIGDB>=<=@GTkxq_5¸ '`~”§¬Ş©«­°±€ł1˛±Ż­«¨¦Łˇž›”‘ŽŚ‰†€}zxuroljgda^[XUSPNLLNQValrk`N%Á(So’ž©Ą˘žťś››™™—–•’‘ŹŤŠ…€}{wuromifdb`€a cgnu}wpgZEÍ'Mds~‡‹ŚŽ’”ŹŚŠ‡„€~~}}€| }{yumeYF%ß 0=AGMLNONLLG@;/!łýýýýýýýłýýýýýýýéöôô¬őôôöëÄîęë°éëëîÂÜĺć´äćéŔÚŕ·ßááŮ˝ŐŰąŮÝ×˝ŮŮŘŮŮ„ÚŮÚۇÚŰŰÚÚŰÚÚۇڀŮÚŘŘÚŮŮÚŮÚÚŮŘ×Řĺ»ÝŢßââ€ăä€ĺććççčééę€ëěííîîď€đ"ňđďďîîííěěëęęěîđóö÷ůřöôđěéĺâááŕßŕć¸ŰŕŕÝŘŐ†ÓÔ„ÓÔÔÓÔ‡Ó…ŃĐĐ€ĎŃÓŇŃĐŃĐĐĎĐĎĐŃŃŇŘŢĺ¸ŘęÜÖĎĚŽË…ĘÉČ„ÇĆËp„ĘÁ†¸Ç¨‹ÉÉYšĆĆÎŮěł·ÖÓÍËĘŠË€ĘÉ€ĘÉÉ€ČÉ€ČÇ€ČÇÇ€ĆÇÇĆĆĹĹĆĐ>ʱY˘Ç}\ËÉcĹĂÂĆ˶ËĐÎËĚĚÍĚËÍÍĚĚËËĚĚ€Ë ÉĘËËĘĘČČĘĘČČÇÇ€ČÇÇĆĆÇÇ€Ć ÇĹÇČÇÄĆĹĆÄĹĆÂĹ€ĂÂĂȵĎĘĘËËĚş‚›šš™™›™——§•—••™•€”€“’–‘‚ŹŹ’€ŽŤ ‡’¨ÄÁÁÂÂŶπËĚÁr M€N:MLKJIPEEFDB>m<>>;F8866532:;:8E7765432110.<,,+**)! ;`şÂÁÁŔĤóŤü ýÉËĘËĚąz( ˘€Ł4˘ˇ˘˘¨ŁĄ§¨©©ż­±łµ˝şľÁÄÇĘÔkJIGWEECBA??==;8J564430 HiąÁÂơ®BôŤř8ýÇĘĘÉĘż{4w{€‚†‡‰‹‘Ž’–™››¶ Ą¨«°°ł¶ąĽżĂĂX^]d[ZXWVTSSQPNTKJ€I % /\nşÂŔżżŔƢŮűŤřűĹĘBż{+ťŁ¦ˇ¨› ť­¦±ł•—¶žŁĄ¦°¬Ż˛¶¸Ľ˝ăjLL\HHGEDCBA>>:M7978 OlşÂżŔżżÄ Çšô÷ŤřűÄɀȿ{+ś¦§¦Ą¤$ޤ¤¨©Ş©Ă¬Ż˛´»¸ş˝żÂĹĆĺËEJ\HHFECBA@>=9L€7( € PlşÂżľżżĹˇňřŽ÷:űÄÉÉČČż{)´˝ŔÇÄĹĂÄĆĂ˝żľżŔŔŃÂĆÇÇÎĚÎĐŃŐ××ęđŤF[FFDCBA?><;8M662 RlşÁżľľ˝Âˇóňôő…ö÷üĂÇÇČÇżz)ÇŐÓÖÖŇÍÉÉÍÉ"ĘÉŘÉĚĚÍŃÎÎĎĎÎÍĚáäě;ZDEDBB@?=<:7L47‚ RlşÁľÂˇćę€îí…ěńÄČÇÇĆżz)µş˝ľÂą·˛±¶ŻŻ®­­¬Ç¬€­ ·®®­¬««©ÎŇç8Z€C A@>=;:97K6 ‚ SlşÁ˝˝ĽĽÂˇćęŽîńĂĆÇÇĆżz)­şÂĘĂ»¶±±µ®®€­ ©Çެ­­µ®Ż®­¬­ŞÎŃč6YACBA?><;986K% SlşŔ€˝ĽÁˇćęŚîíîňĂĆĆĹĆżz*«µµ¸Ă»şŻ®˛€« ŞŞ¨Ç§ŞŞ«ł«¬­€¬ŞÍĐč5X@B@?=<:9874F„ TmşŔĽ»»ĽÁˇćę‹îíîďň€Ć2Ĺżz+©±˝Âżşşł«°¨©Ż°°ąÓݬ¨¨°©Ş«¬¬«©ËĎç5X@B@?=<:8864( € UmşŔĽ€»żˇćę‰î?íîďîďňŔĹÄÄĹżz,§´żľ´¸˝¨¨®Ą¦¨§§ąŐŁĄĄ¦®Ą¨©Ş««©ÉÎç5X@A@>=;:879( € UmşÁ»şş»Ŕˇćę‡îí€î€ď7ňŔĹĹÄÄżz+ĄŞ®°µłłŻĄ«ŁŁ©¬®±Í٦¨§ł¨«¬¬©«ŞČÍč4Y?A?>=<:88& ) €€ WmşÁ»şşąľˇćęîď7ňżĂĂÄÄżz+˘°˝ĽŔ¶´µ·ľťźž««¦Đ§©«¨®¤§¨©§¨©ĹÉç2X==<::876. * € VlşŔ€şąľˇćę„îěî…ďňżÄ€Ă żz4ĄŞ­¬Ż¬¨¦§©€¦"±±¬Ô®˛±´®Ş«­®°˛łËĐéMdXWVUTTSP..,:,-€, ++*:kpşŔąą¸¸ľˇóřüüýţ˙żÂ€Ă(żz,žŁĄĄŻ¬§ťś¤››ś¦¦ˇŃ¤¦Ą ¨ť ˇŁ¤Ą¨ĂČć4Z??=<€;/ "[mşŔąą¸¸˝ˇ&@??<:9764310.-+)(&%ĎÂÂÁÁŔz,ś ˘Ł­§¤››˘™“Í”™šš¦śž ˇ˘¤¨ŔČç3[?@>=;='1€%\oşż¸€·˝ˇ€KJHGEDCA>€;6:8755$ĎÂÂÁÁŔz-™ˇ¨¦¬¬¦ťŁ™––›™•Đ–™Ąšťťź Ł§ľÇç2[?@>=;3€3€€ &]mşż¸¸··»ˇ€K?JHGEDCA”Š^9:7644$ÎÁŔŔÁżz.™ˇ°˛Żµ˛·´·¤“”žźžÖ ž––¤—š›ťźˇĄ»Ää3[?@>=;‚4 '^nşż·¶··Ľˇ€KJHGEDCC€.Dm?E/jÉÁÁ€Ŕ){.•™š ¨Łť•“ťŹ’‘”ś–ÔťźťśŞźˇž›ť Ą¸Âä2[>@>?5(`pşż€¶µşˇ€KJHGEDCB¸‡‡š4—(•y*Íżż€Ŕ({.“—ť˘ ˇźź¤ŤŽŹ’ź”Ř– ˇź©ˇŁ§ˇ¤ť¤¶Ŕâ2[>@?)‚6€*aoşż€¶µşˇ€KJHGEDCC€35Ś'Š0„„ĚŔ€ż1Ŕ{/‘••¦Ş žś›Ą—‘Śš“×ŹŹž’•–šśŁłŔâ2\>?59 +boşżµµ´´şˇ€KJHGEDCCx=:}0v{|I‚Çľ€ż'Ŕ{/’ť™ž—śŤ‹€‰Ž—“ß’›› ŤŹ”–™›ˇ˛ľá2\=>„:-doşż€µ´ąˇ€K=896.23Ěľľ˝żŔ|1ŽŹˇ˘ˇ•ž‹ö÷ţŽ—–•”–ś–úôôŽ–š Ż˝ŕ2]? …<‚ .ep»ľ´łł´ąˇ><;:774320/-+*(&%#"Ęľ)Ŕ{1ŚŽ©¦Żˇ¦ź‹öt€®ź›śśšś¸ …ő‹“– ­»ß3_'‚>€€ /fq»ľ´´łł·ˇôúŹ˙.ą˝ĽĽżŔ|0‰‰‹Ť”–Š‚ýŹ»›˛Đ¨Ď´¦ľ¤ŹúŽť•–ž¨¸Ý/Q= -dp»˝ł˛łł¸ˇçë„đďđ…ń+ö·˝˝Ľ˝Ŕ|=‘°«­®°źť™™łżöôěôöľ¸§›–žˇ˘¤¬łÁâMM>…A@?N?@@??>>€ 0hr»ľ±±°°¶ˇčëđ…ńđńňńň÷µş»»ĽŔzh¤¨ĆĚĹ×Ô×ެ§¨¬ů÷řĺ€ř+¸Ą†×ŃĎÎŃŃŐ䓨•“ŽŠ‡„‚}{uomjgd`_ZeŤ}»ľ°±±°µˇčëđđ…ńđ€ń€ň,÷µşşąĽŔ}1~}|{Ť‹‰†‹™řöňěń÷ů˘ś‡†ŠŚ™™¤Ó=€€A3ls»ľ°ŻŻ°µˇčëńđ†ńň÷´€ş(»Ŕ}6~~ŤŹź¤‹’‚ŹŇďî÷íéÓ•‚‡‰ŚŽžŽ§ÔG!$$„%"H"‚% $%8ot»ľ°°ŻŻłˇčě„ńđńň1ńň÷łą¸¸»Ŕ}6}{|†Ť‰„€‹€‘»Ň÷ööÓ»‰–‚…ŠŤ‘ڧÔH"%&&%‚&#I#& %9pt»ľ®®ŻŻ´ˇéě‚ńđńňńň.ńîî´ąą¸şŔ}6|zy€yw|vrxyyŠ·Äűőüɲ––|‡ŠŤ†‹Ť¦ÔJ#&„'(%K%€(€'&;qt»ľ€®­˛ˇéě€ńđ€ń‚ňńňđčßâ´€·)ąŔ}6ywvššŤ–˙‹‹§ž®łý˛żŹ®•v˙~‰zŚŤ§ÔL$'('())&L&‚)('uu»˝¬­¬¬±ˇéěňńň4óóćâÝÝßŕâ䲶¶µ¸Ŕ~6rm…ksxurryTYchhcŐiruu†rwvpuyŚŹ§ÓL"‚&'$N$„'ęîôĺŘÚÜŢŢßăçęńđóőóřô«±±°łÁ;kda‰‹•€Š–ꇒ|sÂO[`dlsx|€„Ş·Ü![0€4€5€64]487LzĽş€¦ĄŞˇęîôâŢŢáâăĺćÜňďňééńö˙©€Ż(łŔ€;kcdluvwz…eio†}|ľfzcf„muy}…¬şÝ"]1456€75^598M„zĽşĄ€¦Şˇ?ęîőâáăĺçéëíă÷ńíđóđ÷˙©°ŻŻ˛Á€9ošyvz„{rŹzv{r_şWi_cjsw{—®şÜ[+0€1212DG/\2€5 4;SŠ|Ľşˇ˘ŁŁ¨ˇAëďôöçěďńôőřűřőëäáâĺç§­­¬ŻÁ€>9˘ 9OЦ9AAUŚ|Ľą €˘¦ˇ[ëđőőöçóô÷ůűřőńîëčĺâ䦬««ŻÁ€:tqrz~uv‹`fkmrv˛‘ŻŐÝŔ¨¬µąĹÖŮé[€NB66:<<>>?;ŠŇ1•ŮNABAUŤ}Ľąźˇ  ¦ź]©ęđőőöôę÷řűřőňďěéćăŕᦪ««®Á€:uuv‚‚ЉЋŤfknrv…¸Ź›źŐŕ×Ǣ¦Ş¬¸ŇŘéuŁŠŽŤ~m\K;:>?;c‰‡‰‰‰‰‚Š‚‹+ЦĄĄ¤¨Á€G`TY[]_abdzgjkmnn”ptuvŤwz{|}}~™‚„€…„…‚™„„€‚Žť˝µ™ššžOJËĂ˝˛…!ÇĎÔlV(#(,.024578:=>@B@t§Ą¦§§¨¨©©ŞŞ«­­¬®¤€Ł¨Á=ŁĚĐ‚ŃŇÖŃŘŃŘŃŇÓÓŇŃŮŇ€Ó ÔŐŐÔŐŐÔÜŐ××€ŘÚŮĐ“€˝µšš˘/IZĘĂ»…$ČŃĐźM$$),/014678;<>?BCBsŁ ˇ˘ŁŁ¤ĄĄ¦¦§¦€¨©Ş«Ł¤ŁŁ§Á€JŻľÂ‚ĂÉÁÂÂÁÁŔËŔ€żÇľ‚˝ľľÇ˝ľÁÁŔÂËÄĆÇĘËĚÍÍЦ€˝µ™—ˇ+!BŽÂĂ»‚(®ŃĐ×K*#(+.013567:<=?ABDDo™™™š›śťťžźź  ˇ€˘%Ł˘˘ŁŁ§Á‚Gs„„‚‚…€€~}}{zzy|wwvvtutsy‚s ttsuvx€|~†ŠŠŚ‚x˝¶—™™ /'=ÇÁÁş4ĘŐŇž;'*,/034678;=>@BCEEk‘’““”•––—™š›śśťŁ˘˘ˇ¦Á˝Ľ®€¬‚­®®‚ݰ°€±‚˛ł´ł´´†µ¶€µ€˝µ€— *5ŤÂĂ˝‚4ÓÓŘ|%(+-013568:;=@ABDFEh‰‰ŠŠŚŚŤŽŹ‘’““””••˘ˇ˘˘Ąľäîě™íŚě‰íě»´–—ź*lÉÁ‚2ŐŐÝN'*,.013679;<>@BCEFHc€€„……‡‡‰‰‹‹ŚŤŤŽŽŁˇ  ¤Ęň¶îďе•–—ź, AĘÂĂ‚2ŘÖŢ>!&*,./24679;<>@ADEFH`xwyz{|}~€‚„…†‡†Łˇˇ ¤Óĺäĺĺćçç‚éëę€ë‚í€î‚í€ëęęëé€ç€ćĺĺäĺ€äต––ť-!3ÇÁĆ,Ô×ÝV#'+/35:;;=?@ACEGH\ppqqsuvwxyz{|}~€Ł€ź¤Ż€Ş«€¬­­®®€Ż°±†˛°Ż®®­­¬««ŞŞ©©¨¨§§€¦€¤ §•––ž."GŔĽÁ‚/şŮŮ› !#$),/369@BCEFGIJLNPQRSL>€¤Ł˘  ź  €ź„žť€śť››ś€ť†ś†› „%Kަ«S‚.Zb˝ŢÜćN "$%&(*+./02458:;<>?BCEFGIKMNPRSN>G[€^__`aa€bcc€efghgf*gffggffeccbb``_]\\[YXWVUTRRPOMLLJJ39Ł Ł`^‚.WjlÉÝÜć_ "#%&(*,-/03568:;=?ABCEFGJLMOQRRc‚€€ ‚‚„„……††‡‡€‰‰Š‹‹€Ś„Ť'ŚŚ‹ŠŠ‰‡†„‚€~|{zxvusrpomljhgfdU››™eeZBzksĆßÜĺ‘ "#%&(*,-/03458:;=?@BCEFGJLNOQQt~€€‚„……††‡‰ŠŠ‹ŚŤŤ€ŽŹ€‘’’‚“'’‘‘ŹŤ‹Š‡…€~|zxvtrpolkigec`\{”‘“’fbwxWqpuµáÝßĘ6!#%&()+-/01468:;=>?ABEFGJLNPPr{||}~€€‚„……†‡‰‰Š‹‹ŚŤŽŹŹ‘’“’””•”•”“’ŽŚŠ‰†„‚€~{zxuspomkifdb`]YaŽ”ŤcaiX…vspty™ÜÝÝç’ "$%&(*,.013579:;=>@BDFGHKMMmvwxy{|}~€‚„…†‡‡‰ŠŠŚŚŤŹŹ‘’“”•——™š››™—”ŽŚŠ…‚€}{yvtromjhfca^[XU~›—”—x`acq‡t|rx…ľáŢÝă~ "$&'(*,.013579;;<>@BDFGIJiqrrt~‚„€„„…‡…†‰‹ŤŽ‘“”•šśžź ˘Ł¤¤Ł˘ˇ ™‰‡…‚€~|xuromjheb`^[WS^^…°źšśŹd__cv‰r|wy‚…—ÍŕÝŢă‡$ "$%&(*,.013568:;<>@BDEEajklnynuyikpplnnkfhikmovyvxz|‚„†‡‹Š‡……„yXVUSQVSJHFCCA=:86:7*0…ą­°¤ťpY]]eu‹ppz‚Љ˘ÍŕÜÝč©Q !"$&()+-.014578:;=>@A\cdefqhmpdeiiggiifcdfhjpqpqtvxzz|}~~{zyxpSQOMKOLEB@>=:641,*Ozśµął­tT[Z\pkŤEKŚ}‚Š‘’ŁÇßÜŰŕÚŚ@ !#$&'**-.0235689;:SZ\]^g_df\]aa__abc^]_`aghfhjjmno€p%qqnlljcKIGECEC<:7430* >p¦¬ˇžŔĄnOWWX`|JAzŽ‘—šźĽŐÝÚÚâבQ!"$%'(*+..01356JPQSTZUV[TTWWVWWXZZTUWX\]\]^_`€a&bbcb_^][T@>=:8:71.*!!Ju¤­©«˛¬XMSUU\vp’@0‡Ź†Ž—ť˘˘°Ĺ×ŰŘŘÝăłyC"$%'()+,./@FGHINJJOIJLLKLMNOOMKKMPQPPQRRS!RPNLKE420-+* Hr›µŻ«¬´łŤeELOPSZry3–+?‰—‹’›˘§¬¬·ÇÔŰ×Ő×Üṉ\1 !#%&&5:;<=A>>B=>‚@ABCC@@ABC"BAB@==:81"0O{ŻâéŰÎÇǬ†^>FJLMQ[wx?š),ž””ťĄ¬˛¶·ĽÉŃÖÚÔÓÓÖÜŰą’pP0 $*,-.1013113€4€533€4'3323210.,)& #6LarŤ¨©¦«ąĚćٱ†T@ADGHLTe€q.ź+i•¤šť¦®µ»ŔĂĆĘÓ×ŮŮÖĐÎĎĐÓ×ÚÉ­”~jWE4&‚)$1ĘÁÓŔÄÄËÄÉcĹĂÂĆ˶ËĐÎËĚĚÍĚËĚĚËËĘĘËĚËĘĘÉĘËËÉÉČČĘĘČČÇÇ€ČÇÇĆĆÇÇ€ĆÇĹÇČ€ĹÄÄĹÄĆÂĹ€ĂÂĂȵĎĘĘËËĚş‘€ť€ś€›ť€š ™™—Ş–—š–—––•””“—““€’‘’‘€“‚Ź ŽŽ‰“©ÄÁÁÂÂŶπËĚÁr$P€RQPOOLTJIHGFAu@BA?J<;:9866€> >;O994 TmşÁżľľ˝Âˇóňôő…ö÷üĂÇÇČÇż{+ĚŘ×ŰŰ×ÓÎÎҀΠĎĎÍäÎŃŇŇ×ÓÔÓŃčéň=]HHGEDBA?>=9N79‚ TmşÁľÂˇćę€îí…ěńÄČÇÇĆż{-şľĂĂÇľĽ·¶»łµ´˛´°ÓŻ€˛»˛˛±±°°­Ó×î;_GFECB@?>=;8N8 ‚ VmşÁ˝˝ĽĽÂˇćęŽîńĂĆÇÇĆż{-˛żČÎÇľşµ´ą€˛±±®Ô®€±»˛ł€˛°®ÓÖî9]DFDCA@>=<;7N& VmşŔ€˝ĽÁˇćęŚî9íîňĂĆĆĹĆż{.ŻşĽĽĆŔŔł˛·°°ŻŻ®«Ő«®ŻŻą°±˛±±°®ŇÔî8\CDBA?>=<:96H„ WmşŔĽ»»ĽÁˇćę‹îíîďň€Ć3Ĺż{/­¶ÁĹĂľż·Żµ­­ł¶łĽÝ˛°¬­µ­Ż°±±Ż®ĐÓí8\CDCA?>=<:86+ € € XnşŔĽ€»żˇćę‰î<íîďîďňŔĹÄÄĹż{/«¶Â·»Á«­łŞŞ¬««˝áĄ©©Şł«¬®Ż°°®ĎÓí7\CDBA?><::;)  XmşÁ»şş»Ŕˇćę‡îí€î€ď7ňŔĹĹÄÄż{/©Ż˛´ą··ł¬°§§­°˛´Ů¦Ş¬«·¬Ż±±Ż°®ÍŇí6\BDBA?><;:' - € !ZlşÁ»şşąľˇćęîď7ňżĂĂÄÄż{/¦´ÁŔĂşąş»Ŕˇ¤ŁŻŻ©Ü«­Ż¬˛©«¬®«­­ĘĎí4[>?>=;:88/ ,  WmşŔ€şąľˇćę„îěî…ďňżÄ€Ă4ż{9©Ż˛°´±®¬«®Ş¬«µ¶°â˛µ´ą´Ż±˛ł´µ¸ĐŐďPg[ZYWWUUS0/.<.0//€. ,=oqşŔąą¸¸ľˇďőů€úűüüýţ˙żÂ€Ă1żz0Ł§Ş©ł°«˘˘©žźź©ŞŁŢ§Ş©¤¬Ł¤¦§¨Ş­ČÎě6]AB@?=>>1€ #^nşŔąą¸¸˝ˇLliigdb_[YWSQOLJFDB?1ÎÂÂÁÁŔ{0 ¤¦§±«¨ ź§śťś››—Ü—śžť¬ ˘¤Ą§©«ĹÍě6^BCA@>>)3&_nşż¸€·˝ˇ€sIqnligdb^[YXVSQNL>ÍÂÂÁÁŔ{1žĄ¬ŞŻŻ«ˇś¨śššźžß™ťśś©ž ˘Ł¦§ŞÄĚě5_ACA@>54 (`pşż¸¸··»ˇ€s?qnligdaĄśvWURPML=ĚÁŔŔÁż{1śĄ´µł·µş·ş¨—ˇŁ ä˘˘š™¨›ž ˘¤ĄŞŔĘë5_BCA@>6‚ )bpşż·¶··Ľˇ€sqnligdc“P§_‚YŽ]G|ÇÁÁ€Ŕ({1™ťźĄ¬§ˇ™—ˇ”–•™ šäźŁˇ ŻŁĄŁ ˇ¤©˝Čę5_ACAC‚9*cpşż€¶µşˇ€sqnligdbš©RŁDˇ‰CĚżż€Ŕ({3—›śˇ¦¤¤ŁŁ©‘““–Ł—čš¤¦Ł­Ą¨«¦©˘¨»Ćé5_ACC+:€,epşż€¶µşˇ€s>qnligdc•TT›EšK“’2ĘŔżżŔŔ{3•™™Ş®¤˘ ź©š•‘”ź–ç‹’“”¤–™››ź §ąÄč5`@B8< -fq»żµµ´´şˇ€sqnligdcŽ\YNŚ‹^Ĺľ€ż'Ŕ|4”–ˇť˘›ź‘‘“„…Ť“›•ń”ś źŁ’™śťź¦¶Äç5`@@„>/gq»ż€µ´ąˇ€s!qnligdb^][VUQJKK7Éľľ˝żŔ|4’”¤Ą¤™ˇŹ„€˙„‘š™š €˙ ‘šśžĄłÂć5`B"…@€€ 0iq»ľ´łł´ąˇihgea`\ZVTROLIGDB>=/ÇľŔ|6‘¬©±¤Ş˘Ť˙v˛“Ł€źž »ˇ…˙ŽšśĄ±Ŕĺ6b*€ A 2jr»ľ´´łł·ˇńöűű€üýţ…˙+ą˝ĽĽżŔ|5ŤŤŽ’”™Ť…˙…’ľžµÓ¬Ň·©Á¨‘˙‘Łš™Ł­˝ă2V‚€@ /hs»˝ł˛łł¸ˇçë„đďđ…ń ö·˝˝Ľ˝Ŕ|A”•´®€˛َś–ť·ÁřöďőřÁĽŞ š˘¦§Ş±ąĆčQQADCE€DBRBDDC€B@Qv»ľ€˛±¶ˇčë‚đďđńđńđń÷·€»&˝Ŕ}7ŠŠ–“™ ž› ›ł­ä÷řéř÷沼Ą““•—™ŁŞĽäD"€# E ‚"!"5ns»ľ±€˛¶ˇčë€đď€đ„ń.đńň÷¶Ľ»»˝Ŕ}3…„•”™‘Ť™Ž™·ůůúćúůúş©ŹŹŠŤ’ťŁ·Ű=€@ 3ms»ľ±±°°¶ˇčëđ…ńMđńňńň÷µş»»ĽŔzp®´Đ×Ňĺâčń®Ş«Żűůűçűúú»©Šéáŕŕââĺő˘·Łˇž›—”ŤŠ‡€”zxtqmjfbm•»ľ°±±°µˇčëđđ…ńđ€ń€ň.÷µşşąĽŔ}5‚€€~ŹŤŚ‚•‡Žťúřőďóůű¦ˇŚŠŽ‘ťž¨×AE€!" 5pu»ľ°ŻŻ°µˇčëńđ†ńň÷´€ş(»Ŕ}9‚‚Ź’ˇ¦Ź‡—‡“ŐńđůđěŐ”š‡‹Ž“•Ł“­ÚK$('(€)&L&€)€( ';su»ľ°°ŻŻłˇčě„ńđń…ň,÷łą¸¸»Ŕ}9ŠŚ‡„ŽŽ„Ť•˝ÔůřřŐľŤš†ŠŤ’–•‘­ÚL%()*'M'€* )*)(=uv»ľ®®ŻŻ´ˇéě‚ńđńňńň-ńďđłąą¸şŔ~;~|}„|z€yw{}|ŽşÇýřţ˵š„‹Ź‘‹‘­ÚN&€*+(O(+*>vu»ľ€®­˛ˇéě€ńđ€ń„ňđęĺ賀·(ąŔ~;}{z“žśś‘˙ŤŤŞˇ˛¶˙´Â‘±™z˙€ŽŤ‘“¬ŮO'++„,)Q*€-,?ww»˝­€®˛ˇéěńńđń†ň/ďçâä쳸··ąŔ:|yx|Š‹xq˙^n€€±±«‘Ť…Žn˙Ž|€‘“®ÚR(€,-..*R+. -Azw»˝­­¬¬˛ˇéěńńňńňńóńćâĺçí˛¶··ąŔ;zwu‹Š†Ť€˙…Ś˘ĄžŤ‰Žx€˙ }}€’”®ÚS*-‚.0.0,T,/ .B{w»˝¬­¬¬±ˇéěňń„ň5óçĺŕâäĺĺ貶¶µ¸Ŕ:vq‰ow{xvv{W\gmmgčlwzzŠtz{uy~‘”­ŮQ&))€*+(R(+*?yw»»¬€«±ˇéí„ň ńăßčéęěîňóýŻ€¶&·ŔG}‡Ž‹‰•‚‚……排ť—–ŠŹ“—¦¬˝âEeSV€WVVUgUVVUU€T c’{»»Ş¬««Żˇęí‚ň<óçÝĺćčęěîďňôüݵ´´·ŔęîóóŕĚŇÖŮáęíďńóňôůú˙¬˛˛±µŔ>oie…~stUdЀޗŹŢ’•Ź–Ą’š}‚…™§¸ß#]2€67785^69 :99L„zĽ»¦§§¨­ˇęîóőÖÔĐŃÖŰâëđëçěîěňţ«€˛(´Ŕ€?oif‚‰†x‚‚Šnw‡ozÖ~xvyŠqy}…„†šŞşŕ$_377899:7`7:‚; :N…{Ľ»¦¨§§Şˇ@ęîóđ×ÜÜŮÖÖÚâăíóőö÷ňň«±°°´Ŕ€?nhejrsyhawhjlkspŇnimrŠy‡…‡ś¬»á%`488€9:8b8<;< ;O‡|Ľ»Ą¦§§¬ˇęîôćŢŕáâáßŰÖăôň€ô.ůő«±±°łÁ€?nheŚŽ„ޙً“•›€vĐS`fi‡qx|…‰ťŻľâ%a589€:;;<<9c:<‚=€?>R‰|ĽşĄ€¦Şˇ[ęîőĺçčęëíîđä÷ňďóôń÷˙©°ŻŻ˛Á€>rž}z}„w’}y€w„aĆZmdhpw{€„‰ťłżâ!`15667766IK4c7::;9@BFP‡|ĽşĄĄ¤¤Şˇ[ëďőćééëíđňôéůňîő÷ő÷˙¨®ŻŻ˛Á€L{¬Şť™ź–›ˇ™ź›Ł¨¦‰Ô”ťť‘ĄŹ”›źŁłĆĎëStaddeffe›˘¦Łudffei¦źŚp €Ľş¤ĄĄ¤©ˇ[ëďőčéëíďńóőěöőóńôöúů©®®­±Á€@q|mhr}x€zŠqvjotpĆpnjmu{„‡‹ĄĽÇä(d7;<<=<\Ťt‹ť‡<@A?n•’FTŚ}Ľş¤ŁŁ¤©ˇ[ëďôęëíîńóôööířőôöűüă©­®®°Á€@qki“šŽ©—›”ŤŹ‰ĘŚź•ŻŁ˘«¨¬´·ĚŃĺ)e9==>>=zU=9‰´8BB=¦˘rAVŽ}ĽşŁ¤ŁŁ§ˇ[ëďôöäîđňóö÷ůöëó÷ůóáę§­¬¬°Á€?sll}s‰…~Ź~{mv†|Ę}{uu’{‚‰Ź’ĄŔÉć*g:>??@>k=BAD×LCClµ¨@DWŽ~Ľşˇ˘ŁŁ¨ˇ[ëďôöéđńóőöřúůőěćăĺčě§­­¬ŻÁ€@rkk}ytyv}Žxo_pzzČznnqŹy…Ť’ĄĂĚč*g9??@@AABBC:ŔxC=ŻÁgEFY~Ľąˇ˘˘ˇ¦ˇëďőôđíňőöřúú÷ôňđíęçë§€«(ŻÁ€@€‹Ž‘˘˛®ˇ¬ł­ˇ«¦®şŢ©¨ş˛Ć¸­¬»«ź¨ÄĚç)f:?@€ABCCD?¨§?U׬?GGZ‘~Ľą €˘¦ˇëđ€őéőöřůúřöóđîëéć馬««ŻÁ€@€w<‡…‚z{ekpswyŔ‡•–łŮŕ­˛şżËÝßđa†TG:<@BCCDDA’Ů7śŕTGHI[‘Ľąźˇ  ¦źżëđ€őVôě÷ůűůöóńďěéćä祪««®Á€?yy{†‡ŽŤŤ’kpsw{ŠÄ”źĄŮâŰ̧¬Ż˛żŘßîy¨Ź“’sbQA@DBl˙6é˘CIIJ\’€˝ąźˇ  ĄśżşŻëđ€őQôňńűú÷őňďíęçĺăĺĄŞŞ©®Á@~€Ś‡”wsvy}ŠÂ‘™”±Ń×·ť˘¨­»Ůßď}Ş’‘ŚŚŤ~lVaň—÷FIJKJ^“€˝¸źĄ™ Ŕ˝»ĹĘżéđ‚ő óîůőóđîęčćäá㤀ŞC­Á?‚‡•Ť‚ptx{€ŤÄ’›ť ˛©­¬®±µŔÚÜëO‡o|‰žž™”Ź„śŐő–DIJLK_”€˝¸ž źź˘–ÁÁŔČĚą˘™˘ëđőő€öTőöëîňîëéçäâßᤩ¨¨­Á>—ź™ť˘™‰śŚ’”–ˇÍĄ ˘¤·©­Żłµ¸ÂŘŢěV…`dc`fs€Žš™”Ł˝ă{‚p\KK`•˝¸ťžźźŁ”ż˝ĂÄĎş†¬†HóđöőöCóęćäčĺăŕ×ÝŁ©©¨¬Á=š¦±Ż¬ł˘¤Ą°Ł¦§¦Ş¬ŘşÂŔÇÓĚĐÓÖŘÖŘäáî^ŹbeeffefdbnxźľČ‡„€| ji“˝ąťžžťˇ’ÁÁÄČϨ|€ž€Q!(!÷ń„ö8őö÷řőíëęëô˙ˇ¨§§¬ÁKť©ł±´®Ż´ł°ł¶°®˛µŰĂÉĚÎŐÓÓÖŮŰßŢéĺńŠŤŚŽ€ŤŽŤŤ‹âĘ—Ą¤ ›“˘§„˝¸śžžťˇÎÁÇËĐšj€Ž]('058*÷ń‚öôö÷ö÷-ö÷˙ ¨§§ŞÁ?•šš˛Ş ¨›ŹžŹ•™źŁ§Î±¸ĽŔÍĆÉÎŃÓ×ŘÚęěcŤmqrso¶ľşnpy‹‘”‚˝¸›ťśś ŹŔËĚŐ `y}G -368:=.öńö…÷3ö÷ř˙ž¦§§«Á€?šˇ¤˘šźźť¦«ťˇ©¨­ĚłąĽľÍÄĘÍĐÓ×ŮÚéëg’ruvwvvxpŐ™¸sxxwt}••˝¶›ťť›’¶ŚÜĘÎÔÁcgx@!.368:@BD4ôî„ňńň€ńřꀦŞÁ€>®ş¶˛ł˛ł´µŔ¶ş»ľŔŔŘĹĘĚÎÚÓÖŘÚÜ€Ý Ţńp–z}}~~‘DZ™~~~~}‹™‚˝¶šś›—ÍĚÄĽ‡ĹŃÖÚr[`#+1468;=?@CEF9¤ŞŠ¬­#ŻĄĄ¤¤©Á€>‹Ś‡‰‹‹ŤŹˇ‘•—š™Ľťˇ˘ŁµĄ¨©««€­Ż´w}€€€€€»«€Ś™‚˝µ™š›źfÔÎČş…ÎÔŮÜecA#.257:<=?BDDGIDhڋЀ‹ŚŚŤ€Ž€Ź-Ť¦ĄĄ¤¨Á€JdY]_adfhi~koprtržvy{{“|€‚‚„„††† ŠŠ„‹‰ ‡‹Š‰•˘„˝µ™ššžVNÓÎČľ…ÔŰßr`.(.2469<=?BCFGILK|¬Ş««¬­­€®€°±±€˛´Ł¨Á€@ĄĚ‚ŇÓŇŘŃ€ŇÓŃßŃŇÓŃÚŃÓ€ÔÓŰÔŐÔÖŐŐÖÖŢÖ×ŘŘŮŮŰŰŃ‚˝µšš˘4S]ÔÎÇ…#ÖÜۦW))/2479;<@ADFGJKMM{§¦§§¨©©Ş««¬­€®ŻŻ°łŁ¤ŁŁ§Á€N°żĂ€ÄĂÄĂËÂĂĂÂÂÁŇŔÁŔŔÉżÁżľżÉż„Á€ĂÎĆČĘËÍÍĐÎŇ«‚˝µ™— /&I“ÎÍÇ‚#¸ÜÜâS1(-2469;@BEFIKMOQSSo‰Š‹ŚŤŹŹ‘‘“”•––—™™šˇˇ  ¤Ęň¶îďĐ´•–—ž0&!FÔĚÍ‚+äâëD&,0347:AFHLOSbrsvxzy{|~‚„…‡‰‰˘ źźž„ś›„𙄗‚„—–„• ”ś3'"‚żÂ˛‚-—ëçň! "$')+./14689<>>BBMXYZ^acfhkmoqsuwy{|{˘ž€ź žžťťžžťťśś€ť śś››śś››šš€›šš™™šš€™€™ ————––€—––••––€•”€•ś1& żąż‚2^ëčč˛ $&(*-/13589;>@BDJPRTUXY\]_acdfghjlmg•źžťťžž€ť śśťťśś››śś€›šš››šš™™€š ™™™™——€— ––——––••––€•””••””“””$„´µĽZ‚/\˘íčďo "$')+-12479:=?ADEHJLNPRTVXZ[^_acdfg^JŠŁ¤Ł€˘ ź‚ž„ťśťť…›„ś‡› š…(Q˛®łŠX‚1crËęčóU#%'*,.1357:<>@BDGIKMOPSUWX[]^`bdfhbNPbcee€fgg€hihgh€j‚k‡lmll€k$jhihggecca`_^]]ZYXWUTSQPONLM5>«¨«źfb‚2]y~×ęéôg#%(*,/13689=?@DEGJLNPRTVXY\]`adfggr‰‡‰‰€Š‹€ŚŽŤŽŽ€Ź‘‘’’“€’‚‘&ŹŽŤŚŚŠ‰††‚€}|zxwusrpnmkihfZ˘ ˘ nl^:…{…Ôëéňš"%(*,/0358:\~‚‡ÂíęěÖ< $')+.1358:@BEFILMPRTVY[\_abe{„……‰Š‹ŤŽŹ‘’“”•––—™šš››śťžžź  ˇ€˘% ž›•“‘ŹŚ‰‡„}zxurpmjheb^[X‚ź››hhju‡t„–Ěíęęđ‡#&(+-02479<>@CEGJLOQSUWY[]`bw€‚ŹŚ“Ž‘’“•–“•–™šśź ˇŁ¤¦§©Ş¬¬­®®­¬Ş©˘’Ť‹‡„€}zwurolifda[Ybb‰µ¤ź ”mhfiz‰r„‰“–§Úíęëđ‘)!%)+-02579<>@BEHJLNPSUWY\]ryz|}~…Š{}‚‚€~x{{|~€‡‡…‡ŠŚŹ’”••—–“’ŹŹ„da_][`^UQONLJFB@=A=05‹ż˛µ©˘xcgdlz‹pvŤ“››±Úíéęő´V$'*,/2369;=@ADGHKMPRSVWlstvwxxy|}{|}~zwxy{}‚‚„†‰‰Š‹‹ŤŚ‡†„{_\ZXVYVNLIGEB><83.T‚Ą»ľą˛}_ecdvnŤnO”Š›˘Ł˛Ôëččíć–F#(*,/2469;=?BDFIKMOQeklnoxrvzqrvwuvwx{trstuz{yz{|~~€€{yxwoVTROLOLEB@=;70&Ewݵ©¦Ć¬x[acbh€LB~—Ť—ˇ¨Ş°Éáęććďă›X!&*,.0357:<>@CDGHZ`bdelhiogilmlmmnpojkllppooppqr€q%prpmkjg_KIGDAC@951((Q}®·±¶ş´ŚcY^``c|s’<3Ťš’ś¦®˛˛ľŇăčĺäęđľJ &)+.03578;=?OTVWY_[\b\]``_`abccb^_`bcab%aa``_\ZXVO?<9720%!NxŁÁ»··Ľ»—pQY[]\by}4–,BŽź–źŞ˛¸»ĽĹÔŕćäââčíÄ’c8$(+.013@FGIJOLMQMNP€QRSRPQSSRQ%PPONMMKHFC@:)"7X‡¸čěßÔÎδhLSWXY[d}}Aš/-…Ąž Ş´ĽÁĹČĘŐÝâäŕßßâččÄťxW6,3468<;??@@AAB@@AA€?%>=<:9751,'(r©Řý˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙Ú¬u?+ +;e”ľâ˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙˙äŔ–g<,  #.;]„§Çŕ÷˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙˙˙řâČ©‡_IWbmw|‚Š‹‹‹Š}wmcXJ?93.)#   gammaray-2.3.0/resources/GammaRay.ico000066400000000000000000011415771255003167400175410ustar00rootroot00000000000000 ˘ťv ˙Řž€€ (w00 ¨%?  ¨ç¤ ʵ hż‰PNG  IHDRôxÔú IDATxśě˝y°eÇyöűşĎą÷˝yËĚ`@±(HÜ"R %Y¤UZ¬”*v’rY.;´˛XĄb§RJĄ\¶˙SIEI¤ŠťDڞHt©’T\"S’ٍb[TDY" ‹EŠ"‰Á 0Á¬o˝÷žÓýĺŹîŻ»ĎąçÜwß›·Ě{ÓżÂŕŢw–ŢÎąýű¶ţČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČČȸ[ĐQ7 ##Ăaccă˝Ěü<ŕY˙ďÔѶ*#ăžÄ€×­µ_fć?TJýŢęęęuŁŽ˛‘q„X[[{ÂZűł>e­]˛Öu“22Ž)Ą ”˛>§”úąŐŐŐ/uĂŽ˛‘q¸yó懙ůżđŃLúűff­5)Ą.ŃqćĚ™˙ů¨Űt/# ‡›7o>mŚů_ük-#˙32¬”"Żk­äřÓŁnĐ˝<ůdd®_żţ_[k˙ŁLü‡VJ‘Ręďź;wîoucî5äI(#ă€qíڵǙů÷<–Íý‡ĄÜdć§Ďź?ű¨ŰsŻ k×®}w]×_eć¬őgd-@­µţîóçĎó¨s/ OH„k×®}O]×_Î&˙ŚŚ{¬”˘˘(>ňđĂżpÔŤ9jäI)#ăpĺĘ•g­µÚGţŢ$ ČIĘ?ĹăŹý–óxË:dĚŠý#rźGŚ­ť5zđÜŁŹ>z_[ň¬“‘±Ď¸|ůňYkí f‘R š›ŁÖ76°ą˝ŤíímTµAm ڱ°Ö¸›gţ"÷đsmܢú®Úą€˝Üjčľ÷2őôÜ3Ł(JOrř_Ç}»čŕn‰MÍuŐ\g÷ýý80§—–pgsÄí6ÝĄPÓy;;1€Z+,%† Ă!–°´¸€BkXfřß$¬µě›g{ě±;wרă‹â¨‘qŇ`­ýC!˙«o]ĂŐë×QŐŐRk‡ÖÁ–/˝ö:F“1Ţ÷®'@Jýőwľóťżt„Í<ä)#cđÚkŻ}äí7ľ´=ń3ďzmnmu“222f`0€Ľř­ üÜ»§˛(Ţ˙ä“OţńQ·ë0‘€ŚŚ»ÄĹ‹X[_{s<¦Çy„&“ÉQ7)##cN,ť:…Żľô2żë‘‡&ĂáÂ٧žzrű¨ŰtXČA€w‰IUýńŰ·nŃ»ßőŤFŁp\Lţb‚$˘ěűĎČ8¤n€ôwIDXßŘŔóO?I߸řęŕ™ÇŢń‡ŢwDÍO¬ÇI´ÂĚęç˝ö޵ź‘ëx§™7&“É™~đ'v Ď‘±KTUőUźH¬Aţ}źiŢ˙4IÉn4žýžPÓ ŻĎz‘Ö;«m]çş4­yˇv»ú,'»‹yc1îłĆł«íűłś®qm×7ϸî&6ĄŻ}4ĐýÎ÷•ßŐŻYĎg7BTű=OßEĄTç;)Y<™yy8ţľî Źî-ń,#ăÇ7ľńŤ/XkżO)ŐIř)é÷Mdł&Ô>ëAzm»ś>"đ9ĎíęÓ„ç!śöń®zg]ŰG8óXFşîí’ ĽłśY}ę#4y–íţě¶ŤłĘ؉TçXćÚmŘÉŞŇWć<ÄÝ×·öńYĹnÇfžw3­WţĄ ”R÷Ůgźý{Sśd #cN|ó›ßü9kíĎ‘ěĺźh¨KhęűŢ'`íĆE0Ż*e[kBÄ,!¦O[ťŐ9×~V}mí#ńľĎYß»ţn·ż=&]w}v‘r*äĄeI¶ÍYőw ]ß­µŤ:ĆŹ=˙üó_śęĐ1G22ćŔ… ţŐŞŞ> ~úŮeĚŇČz­ €…R7żM¶ ›ţA'ÇzI»ëľžöÍ&B®ýŢľ&ׄ~`z"ęŇŰőt }×N†®kf ł®k_Ó¶JĚ:Ƨ5Nłęé<ßqŁÉ3ź^ýýmŇ—ăé˝í÷}'ÁI6úix›Ś…ĐŰdo-»Ť‰:»ëú´üö»Ń't¤eúO¶ÖšŃhtúĂţđ‰Jń™€ŚŚpńâŧÇăń"’}Ä;‰^ĚCF;]7‘q2źçŢ˝Ô×Ö˛gÝ·Sůó4Đo]×ę°SŮłÜ7rM×±YZ|×}ł}–€1—‚§7FjĽŻMňOźA—@Űőľďd-čjwY§ÄŰu®y;A`†Öާ> KŔM˲Ö!€™żńÜsĎ=ßŮącŠ,ddĚŔöööŕŇĄK×hU)E©Öß…®I§Ëd+č#Ż6v"Ú®kçąn§şű±­ťw•1á÷Ő·Ó±míž{ş®ŮIŁźU˙Nm›÷ÚÝžëÚBHAËyŇཝ¬Zí˛şţîjoźćL rl–ĆŢw®Żţ)ËF‡µHľ§–¨ëú<÷Üs˙ÁĚN#d #c.\¸đ/ůĂ©É6ăʱľď@·‰9ť|ۇÄ]ćĺôx_™{ŃČç!µ.á˘KCŢ©ě>Aa7ím·)­§O ëjOß=łęJß>c–Ą OŘšUoWůĐgťHŰ<ď±YďYJ môiă}$>ʤkś»Îw‘ú˝OčIĎUUýřsĎ=÷›S•Cd #ŁŻĽňĘ/Xk˙&€ ő· ^&¸TsIż§ź‚˝jš;a'tzÍN‡ »Č==×U^_»ú0ŻöĽ[˘ÜŤp5OۤĚy­íűvS×N×ďFPŮk9}×řľ÷˝ďĹ»â#Cvdd$¸téŇgŚ1ďl»1f¦ćź"ťŔv JşźpŘ$,uv}?¨:]ďŮa×eG#ŘŰ·a®_G}ý:ôâ"ô#Ź@ť9ýŔ@Ďx[Ö6··€k·-¶*ŕÜ áÁŕ%`Xö¸ l޵mĆő;77€ĺEÂç g3K4µÜ1”QU°wîŔÜĽ‰ú­·cP<ňÔ@ź= .KWG+Q&S€™§–LVUĹeYţ.€Ő˝ŽóQ# oľůćOŚFŁżšúôĹ×ßRmż‹ŘŇčçűYóO¤&˙¶f?Çş-ÔÔ3mżKůî´ű”~öŐe××±ţ…/`ń3źÁŇ­[x@ńŃŹâáźú)čsç˙Ű™şŹoÜf|ć·+|Ů>„ęĆ–ŻżŤżöçńcbXv·‘ÜÚ°řg4Á?zăÜ©pá ~č»~ňĎ.âě mw_ěxŚÉ… }úÓxđĄ—p Ŕ­GĹ;~ú§±đ‘Ź€Š˘seDú RëźÖ:^ f^ůÖ·ľőŹßűŢ÷ţ+»~÷ş×edÜgxë­·ÎŚFŁ˙ËĂňŇŻëƆĐŇď@„ńIG{Һבßm]uĄůAÔ'–ź´Ž»­§ËBŃŐ—ýčO_]©°:ł.Ą`Ż_ÇřÓźĆwŤÇř®ĺe|hqřŇ—pë×=¸şźđ_ŘÄ—O=†ĺŹ>ŤÓ?đ4Şw=Š_üőÖFýBˇRŔËWżüǧ@x g˙ĺ§±ô±gđOżü΋hŐߍpőW~ß}éľ{y>u ]»†«źţ4°˝=ŐOöĄí2Čżş®QUUăs<c<˙ř7ľńŤż2ďs¸—€Ś ˙´Ş*Xk©ýĂo›ţ»´űű…ŕm2i“0°ëN$)uíg}G%XD=űY×čĺ—AŁ € 3€sE­Ż~T3žđ• Ąx2Źkç–Q†¸üVÝCH|őĺ1X)pmŔă4,0xô4ľňR…~A“ĆcTßü&*"ŚTĚ8WŔ•+°ŰŰS‹bâo»÷„üĺ3ýgŚÁd2áííířőŻýáąňAvdÜ÷¸xńâż3™L>Ľ“ßżmâżźHżÓÄšLĽéç~×{PuÍc?Âo×}ă–~ߏ÷U ‡Řđ†18Ł4 8ňo ŤöŔűŐoÜ‚Z@ť€-Ƣ,şiȵ›0(ěťMÔ—®CťY‘[‹rŕŰÔ“H JA.×5jCĄ`ŮĄHîZšŘ^ŢŘ~FĆĆ2ÍÄ}@ÖZ®ëú÷<3ßHŢČ€ŚűŻżţúňÖÖÖ/UUĹu]łź|ďňů÷—/˙°5Ő¶ ażęşkř.ëéł$H=űy-1űUßŕÉ'a|W&\1—Ş ×ę+ß˙ýŕŞężŃźřŕ“K·P˝ö6&Żaüę śŃĽăa ćîçc¬Ĺ‡ŢSba´ŤÉĄ¨.ÝŔřâ[¨Ţ¸ŤřŔf:Ń`Äp…Ź~oU®׫ W'”ď{pęÔT]]ďBzMęH-~® ş®ź~á…ţÖ.‡ôH1kEFƉǧ>ő©ß4Ć<É~É߬µým-á¤b–ö¸źÄŐ < í»KłŰŸǒpV‹ęÓÔóaĆâ3ĎŕćëŻăćť;X[^ĆęOüVř‡ˇ|°±  ŤÓ+ ‹%ăµoݎz{O.Žńďýů%\óŚ[;P0mk cĚźý™źů™˙é—~é—Öwâ{'6ËČčÁ׾öµŹUUőű}ć?ů.ź'Ťüç!®ăXWZöaŐs–ˇ¬kŢçcG#Řőu`cĽ±á˙VWˇ–—ˇOźî-ß2°ąÍX1ÖG@eĄXYN/ Ý˙űÚ36ĆŚőmÂV 4°ş,•Ĺţ1ຆÝŘŻŻ×Ö\ň˘ĺeĐę*Ôę*¨Çő0ď8őŚk­żöńŹüý».üp˛f´ŚŚ]ŕ+_ůĘcĚSÔ1ó´%ű“€Ă&á´ŢŞë¨‹Şc'ëČ~×7ol-P×ŕş{ź8Pť„űë’ŐÖĄőŐ (´#5ŁNcÖ8ˇÁX@‘KTh‚VÓu…ľ0Ť×µk3ł[úW–{"˙´žľcbE‡˙úG>ň‘_Űs%‡„,dÜ—xńĹżż®ëßmOz‡1ÁŽ‚đĺűAŐuR‹Łb殇L’@:˙ ˘H$-KZł>Ŕđ޶p鬪cS]@ W˛-Ľ»®öx’ś—¶îb\÷đ|Xk}ýă˙ř=ż* fÜ—0Ćüç,6;žÎîĎ@żťĐöŰŹź~?Č`·´©'­ă¸öŐ{Áň˝ďůĚ]OBžJĹĽúä|ńRŹIĹř÷])·ľßµS•á>_%”r‚„&fżßáo_é^ČŘőó!kíC_úŇ—~xYȸďđâ‹/>ŕű™Žož>âÚó$ż‡şŽs}Z_^ĺ°‹zh:S^ZďŇĽóRsűţ1;Ő·χ™ąŞŞ˙dîŽ9@Ć}kí_OÜę27îclAŰWü¨í‰Ş=oqDZÝÖĄ¤€YíT »˙ÄÄJÍ­pJërQ”YżQ—µn»9Čq×őůĽ;ľ {)»e'Ąf÷eŻď8‘+×—9ýÎÍ·®žöµD~˙łÜ!wůN3â‹_üââ÷~ď÷nßMA‰,dÜŹř·Ş`f†ö»‡˝qő*ţŮçk±°x K++î¸ÜčA~–âpŽL\<ÍÖě‰3=ĚrǬ5QhŐľ–\u͝٦j şţîi §˙g‹ŐaíÚ[Ń.ÜJŠj–šüEX÷ö‘§ż%_hęŞVüsë/7-#J» FłŤÉ˝vĆŘµŻ…ŻcžG ř%liËô µß»f™“‹ÚpR>ót;ĘÜ˙L“?•RÍ,śˇh†© ŞÉň3ąrô92' Ęf2Á÷~ä{đđąs.ýŻµÎ­±ŹÂRâ ůiżpײq_áĹ_|ÜóĐA•o-ă›/}/~ýOpăö-|ć˙¨ĆCŹ<ڇĎ? "R„ÚXr“’Ż€[źMŤŞ‹ś{Đq_W=7g¶'ăö…=mén@üfRN2·[ă‰gÝj©×ţôE(]4n㦄“|í¨Ť-Hi°5ť­éí7OŤvk\rĺw—Ű[FÇęا5ÓťĘďŹéCZkŮ)áĎî{{Ľ¦%´‚5fZ ]mŃ|Ú÷¬*ŠUUMµ›¸sóz¬L>­ĹÓĎ<°[e@¤ ŠŻ|ăëř+źú:{ď{ď»ńř;V{ۨŞ+@0ÉZÉDô—‘€ŚŚ{ÖÚO”ů}c_} këë ‡C€4 ­1(XX\€"Rµ5 xĘ”.: ;­7ĺ@ŃnÓY5ýÖ3uNl #BLŹj=5·5ÓŇÉĽ5q:B—‚č5ÜxšĂ…!@ŔÂÂ)(­;UЦČŃŃßdĄ¦SĂe„ŢN EÔ ă`piŚ˝;ˇ”†µ&¨ď F:»Ž‹Xźę7Ç(=Ż•vÁsŰOsr{*ů>0‡b»ßnFQ¨[Vö7QcX’şĽ&ÍNź­«+ި•‚Q:\ eZlëŐő§ő6žI‚˛,Ăńô×róĆuďBjÎP€őË Iˇ( ”ĺ eYŕöť5ŔľŽóçĎca8Ü•ĐAřŤO¸`ŔĎ]ŕ ÷>©Ůőî±±±ë7n , (EĐJC?, Ľ@Ţ= jëü虌&˝ř ’Ă ,×Ä :Ţ.ŚJ‰Š;‹i×WL¬­I»Iámž–ú´>BSŔ0Jˇ,K€aş6»-P ]–'FŰ~ź'V€™ńđ?ř±Ź}ěwz/:Bd ăľ‚R껍1űFţĚŚş®±±ą&pE ŠČ ^1ŃD(ËJi袀* n )4p§ůS$Ť˙nçŽc@:g§çÓö&!řL™AZűąO×Ů$ÔĆ@řCÜ!tp#xLĎÔ5Â`0p€´ŘF˙Ó˛’D®.LmŇ+=!µZÎq|b[[Ä5%Ŕ0TQxˇ.FIL‘ią90ڜȀ… ä/ś­ ť )ÇkcĐ<85N±Ż® …ß°‡<ůęp~ş„¶ćOź-dXzꎥXĘOZ ĺ8*i¬@"ôŤ«·¤ŐJ…aoock}Í»Ňb"“i]€Éz ˇ(´'ÄU?ţűd2ńżáĆF?Ťöě6@ĐŻXř€ß™ë†CF2î+XkźŘĎň›^{p«¸nY+?§”V(ĘŇYŠăő1´VNë±6¬ÇĄ4ĐŞ”(™ăqöş 'ËžšwÂL Â_@Śŕăn M“s«méĄvş}ě#ŰHĹĄU ëJŻŚSÚ >đ”„:ËäďiËƆ4B®Mň穯©[‚-€Ą÷1Ą6¨M~8nĺ₳č%äŚ(cŁ@C€–'d0†VH{¶kNú•á-Bľ^°5Ć‹u‰QhN\ěŰěIÉ»Á€'r+•¦2E¸ŃőË• áÖÚ;™Ë ^ˇŃŤÖ5˙ú”¤ÔFM Ž˙]0㍷®şß™i ;ÁBÄ(\ź  I%9 üď1‘Q]× űąű$řνŢ|ĐČŔ}€Ű·o˙ĺápř«@"ő&QŻ.9ÇÉO ADxá…öuÉWUU¨}`ÁŤ©ł hîFˇ 袀©+ü»˙ŐÉxě&!?=Ő¬;Ů€[5I°¦^í8Dś·ÓcáHTń<,Ś×öŇ ŕëc¸Ô!Éý‰N×.öuÇëő`€OţĹż„_ţ»ĂS‹Ap’%žŮß?KOëľ8y—tA°V ;ÉýÁŞŇЬĺ]”Ç’hţNgŽB"hĄ˘ Ď ¦¤€đLä5b0Süň±î]N* ÷k­` ůwG„ŃäťóǢĹŢ ‰žßO8K I[˘P(´Ćµ«W`ëž­‡9ů€& «lě”Rţůęů3˘räźÓ'Ĺvţf~Ç^Ę9 dŕ„ăÜąs_2ư1†şH˙¸eľ»h˝?»_§š“‘ Qd )j2ťŇĺ ­ýd‚ňó(qśLR D˛-ădęłp“ą×t‚/ç9šŇU5X)äu –ł+Ąhž%s,€ÁޞpBńĹ/~ńÉĺĺĺż3¸wŻO󿟀ťL˙sHňŤóâ+”‰Cy"ó°@BţZ)E;©­@FĂ*ĺ52 Žu@&ěhnŤJĹ+(*Nłu*S0ˇ¦¤’诜6“ÜLÄÔŤćg[Čd›Ś“ÎŻ'rAň©öéâ$Ĺ›Jo†‡o…ĎtÂNă€VÚ5‚,’ÔOQX‘ć…ż)D“7ęJĆÝYľĺ7CÉx…!řÄ'ńí^ BĘłśp_BŽÄ7¸Ľ]č1¦ %v]+Ö)Úb°°€ÚÚ8f2ÓűĺÍJËBW»[×2€rą®!Ľ&}h÷;-·qĚ”ĘK˙öŐ«(±#¤,k1,‡0lü3ŐPE ]8×HtEA ='¶ű˝,Ľ—‘€ŠŞŞţÉĂ?,Ö,^Š—Ý»<ć5sťĚ’čç”ä§^´ä-ÉR ëfDĹ1ĆŁíŕ“U„°«ą%SP5¶Ŕů 1ʡČh -i›B[ĺŢ&q+­Ý2şt×4!EÄ{śň”’ełü <Č=ň]é`pć S[L]Ai„"…AQ (ĘĚçëTZÁoó&rc×~­5HŞŃż" ÄŠă“ Ä~iq˘ Š{6Ě 2‰pDe¬kďâ)<óá ň{_pńDMb Jjú]e9@57ZŽçSł~”zH”§ŹŐ¤aĆ㨉˵áţ®şRÂö瓤?©B¨ę*•B R"éG\‘’łĆbˇ‰đÚĹ‹(T[Ű)Ł{~×Ƣ6•˙M  Ŕ%sę@źRÔeýK?Ź3N~č÷}Ďţó?}ţüů§…ů»^ŘűŃBru‹&źţ¸÷}L„l}ℨ8{bČŻp·…@µäXCv˘Ő!ŃĚEC3tě’8šYâŠ'ŃÂ}©‰¦$şu˛40% ą'aJ'ü¨2z4v-Ú9ŔoÍ G®bˇ°Ć€-òeżíl›pçm폵MŃ^Žőř1`ĎXÁ<í˙…‰­c6´/^,®¬ žLđţOţ¬7ňĎ]„)˙Ý÷‚_㼊ç©ë|Ľ?ýBă|řΓł8Éű3u>ÖĹíşÂü—ĐÉűš>±°?U0ZWáO”’†€ĐÖ`Y#ŕĆőëmn [¦ţQĎ?řŔ’˙¸ă;Ó^:?„ţťŔů2[N~ű·»0ĆüâůóçŮZKmň?‰/ńn „ž$O †ß”ĺZ»%d˛\PQôÉ‹żU<• }íW8y«hĐBĹgî9 ˛4Ť ™‚đ‘ú@|ý$ZµŚŤhě©ćŢr;N÷>`Ńč’űŁT€`nÚH|˝iŐd3©ünˇ§šLÂ$O ş ćdéXŁüÔRâ„ Ą\V†AJ´P± „tAľoŤGÄ<Jkś9÷Ř2ľń˙ܵ] yöľ\ ă<˘ý¬h€ v$¬ý2;j fJ¶zIύЧGň ·­$ ŐůÁĎ/®0th§—‰‰)ý‰ŁŁ Z&1°üŔYĽýĆeĽ˙?/˙ß˙:I-ŰXşç¦n˙}yËóę0—wÝ“š­Ó‚pmËMĐ®«Ó×ÝCfý‘ţ–aAáÎu Ľvńeô— »„ű-°$E“…ÖÎ}Çw ʱúŕ9lÜąű›’p+řcťÚ4'äśľHI0ŕśäí¶N áćµ}ÂGŚŢçđ®L×%éú#ůŁ“üS¤äŻHáŐW^ęĽnWđÖ1 şÝ Ç1@0 'ëëëżüńŹ<¬ůĐůŢË/但YKwY’·Ą:˙{1şMŠÂ B@~äĆ3bQçýäĎ͵ţ2©’rH,”EűŚG]zZ­C@8Ć ¤Á‚•hö>Ď»8ĽÉ"$ Vg˘Gň>ş ~ŢÇ]ř5Ú"0AZ€RĐpĎAë–-,- Ü$¤’:)ÖÍ~o†x.Ńđý¸ÇĺaQHĆe‰Ą&d{gA±{«>7_ľ€÷}ß÷áźö×P‡Éáh‚î%Ôř}Šüů÷ßÓ"o7ŞŤgż“Ĺ!.çën«Đp:-G˛ĽĎÁÝ0ŁŻţ"ŕÚŐ+o·ţî~ŢÚŹ™o–ĐuH?EN>űŮĎľwyyů‡xŕŢ—1[v‡Y+ö$ĽOśˇh3¦«3ś yN^ăSä¶»đ2âDmŮ/WCTî%ß[ŇŁŕąŢŐ«µËĎßĐ ˇ‚ä["L‚Â$ďâ ˘†®”~ůŤVbcÉČm’¤ttMm1â±_ ŕĆÇúelJk+ ßWŽ÷sŇ'ż<Ó2Ŕp©qť Xë Jđ\6AŠ|ࡍż'% úBäSô©ŔwĽç˝xőkŚGž| 7޸ßť„ü»LřÍď”*Ţ3ŻÝ‘Ľĺáw ÷ţÔ„?ł­ť…şţ‡]Îp7Čuµą…[×®9Ó˙`ws`—pŘqD…,śÔuý ď˙űY|˙@“đÓř¸ľ¬Ť3á‰íŃO¤ĚŚr0€R.P'‘Ţ$Z+dŇ-ňZ¦ä9')2šVÁn•ˇ~ZůţuôEZi+Qčâ.H%!W‚Ż@Č0ÔAá^‰P…†5’€‡ŔlişĘY|‘#đrŕ­TBaËEQşľ ň.AIĺVÔƹŴ߂ŘÚxŹÉ•r Yc`-űÔËn†ĘoĘ–*Th|#fAš Bt@Î…Á6Ć„w§(B{( ‹Ë+xč±Ç1üÄ)ĽüâWP†ˇěN"o‘kçrżĚ$ďđöôkŢ]V€† żG@éiL“ü[í뎣ah"\yăuÔăqG˘źŚBŽ9>˙ůĎ?ňČ#Źü…6Í Ě8šńHµm]ˇ  gP’Ť®á;G`é”&Ú`ÎŐ‹É75ĂúňĬĎđd‹ ÝY–m۲´rĘwt&r=…5ř"˛ÄŰÜnt†Ó­VŮůP D9ŃŇ$‘Ž˘{ŕóň'-$+ß~K± vdUł3÷C·˙@hľü>â®…b±BŤ¸0´vRŰ ± ˛`b%xđŃw`ĽµŤüŕ'ńőßű]PË´-äŘ\żČD;űßw ďÔ˙ŢqW[Úu5É»Iţm"Däsą» żµŰw°văćţűýĹ’Ĺ©E—0–—f´Ö?÷řăŹ7ňŇúžµ˙»Ç^Ç05Ĺ;˝E9tëĂuY@+í}×Ę“H¤_CaiyZkÔuŤ˘,0Úv› ---âÖ­;8sć4Ś5°Öbkc Ë+ËŘÚÜĆňĘnßľˇ_N·˝µ…łž…µĂá``ssëkë‰ ĐrH˙ÓcmSţO‘h$±‘ÜŁ”ň$îďa†.ÝT €t ĺ`H Â`8€V~…ÍÍ{\ţËęSÚíBg­q­}ĆyU]ŁŞMtˇ‘X"¸’`E ±jˇńf%Ç•ňŰâ"’•. =€HwÜK€[čÇ‚á2űö¨\rD"—ę6hď ’~oE0Ö­UWEá%Ä/+#\•* ľl÷·†¤&ŽĆ÷Ü”ňŽ‚  °|ć ¬©ńń?˙Żáwí˙t‹ ˘ Đ8¸˙}ňîňżsęJj’ ĹÂ:É?ŤKxŞ­á«·8Đ1kułsŰĽúň·ç4űßĹśuÓÝq$ü6˛pŚńîwżű?~đÁIŇ\Űď&ĄI6óÇ2O];¶Ąý9kv÷$Žt=€Ŕ(Š2¸(5!#á\"ÜĽy¬”ÖŞ±éJ9,±˝5©‰Kc ¶'H)lŤ&ćö𛔉°1Ú†®Ć¨+ ‹xWERë¸qJ ů¶- Ăőŕy9.Ś'❢‡=ăá„P–Cź€3Ľ· J7.ŞůüÄÇĎĚa•€{6qôڵĐ^ł¬kÓS˙˘[Í;1˙˧'4áTxP!ˇÇëăVÎśĹ÷üčźĂ żő›oo·ŢŁĆh6Mř=ZôôŰ…iňoÝ#ÔŰ…ź¸şq\ű,łÚÚ¸‡Zk\ľôl]ßźÓ/w9ŐtöÇ‹đŰČŔ1ĆŁŹ>ú·B†´ć˙{]ÂÉA˘K{?žčő&Řr0p“`Y¸%p>€-Ő<ĺzö»‚Dř3HŇäSłKťKĘk艶ĺç]­ 0Ë.z=˘.PĆ)÷4Z?=‡†`0Š=lş š÷D ÂŐşôZ˙p 7VŕţV:/qgdɶđ>~B˘8Üë´s±NčŇGűN1$F<ÇËňĆÖď'!ňŢ(ú0PÉ€xc`AEÍ?ň© źýo>I$ďžÔ4ŃĎ žëŽřźß˙ŢţíÍr7¸f±çîv‚ˇiň—ĎľER ·nÜŔćíŰóůýe,w9] I’^îE HÇ˙8Ě«»AŽ)®]»öo ‡ĂS픿]ćţ»Ĺ¬—˝ďÜnîˇÖ„·›˛vsť’(rŹŁ2áÜ2@ç/CJŕ/&g$z7»I]‚şšĘĂĆŻMĆ“-5H!DĐD°~˛Ký÷))ŘĘ}`„ĺfěáY”v ·­kCŕCi7•Ăčá`’†žŚýµŽWUZą«Ë“ąR­e‹ľmN Ž„/Ö…Dr L(;Ůů6Ś›Ĺ#cĂÉđ»,‡ÁęĂĐĺßő_řě?ÂÍ«W“÷SŘ5y‡&ô“żX"äöµMňŽă-A˘áľÄâĐ.·ŹüAŔd<Ƶ7.ĎôG­Ď]b/€.â?iČŔ1Ĺ™3gţËŞŞx0P#PIĹ-?U‡Yí¤ľČó˘tČŇ<'“ďŇĘ `mĐZĹĐ~n˘f;V ÇD)Dnę˘{/R4ř2?ůţ,~ţoü †‹‹JÝG7‰vY¦´pömęzĚń]Ýź"˙Ö=‰Ĺ!=ßţŢř­q´NĽ*›ü îď9o˛pLqíÚµ'ëş;Ę>§üŢ|Ô']8ĐÉ„sx}ĄéoD¸óć01 Iä÷ ĄMŐ[>‰0]âřgŤE]W(ŠÂĄ«eŘ?mYȶąS`ĎI)m;ˇŃ° –Ö†&IÔ•Š-1ɧ¤Jâ›=ZQôi3@dˇO?Pß~ ÝY™•@qWŁÖ•J,7Ý<Ő 13y˘ŐFS 5îŚ}t„§ [›†Ö+Ö’Î?ęWČVĚž)’M•,O<ůęŞÂ`a±YGřÚ‡’žďFz%訳ů˝™†¸ŰÝĐmqh4)m+ąd?Ż˝|ˇWđŤ=ÜC D&qŃ<ÚăŻÄ[u! ÇJ©¸›\˘őź4Ő~bżĆdO?l™0ýäşą˝ "FQú @ň1ä´ęŘTgJ>»0„UŚĄSK`6760Úcea€•Ą%Ô•aR¸zĺ–– llm»üôl§&Ü`ľNúDŠbÁYýKď ¬“ô±ĂŕĘěrők z˝µ+Ĺ2`ýĆMź‡żY]®ŻŤZfOôŢ’!Fv1¶¶€‚‹|'r«Bvě”;:ÄSG¤ń3О@]Ő^‚†R X= ¶Ć{p\@§ń‡ç&.YqŕIAr(¨l)ĽF¦8láKcüH&× ]9­SX9}ĺ°D51°¶†©kŚĆ#Ôc ŔŚ1aľ“­˝oŰX‡ŇyQLşi¤7D±O;ă- ,Ťm§ł*€˛6hľQ«ôzş*Ý :‰}N3©Á…Űú×*čęlí>ňßµD…%J°6 @®f_eX`)ú>zçŬŕ8ty(?"ŽÜÓ2y÷¸Zv2áGňŹmŮÉ˙ŢiÂgnÔ•śnŢ/ŰÂÔ?2†éo†á25ľňŇ·ç¦f€ş»ą#V¨ąÓ}Á—ÇťôSd ăľDפ{ ?ě đ34Ä|"4ć É}·°5Č0 ůÉqiuU † ,aŤE5ž$fX!|¸Ýň(őçz !|oĄ•v… B_TÍsÚvLđi´Th#óŮÂ9çáű.ÇBký0Q¸7ś!›ŕů0,[„v*śÖEŕcj€]Ľű2Ĺ»"1 JÚ@9«˝Jdzĺ@‚m7ÁqĐ….ňťBwëoO ¬aÂשׂŮÂYî†v\Ât÷Ü1Ą®ľů&ŁŃÝ%űaě) …€Î#IXka˝ď?ţ„ßF2î;ĺN€Ž-Hi …ŰĎç'0ĆÝ[Ö¶;-ËOÜ–ÁŠpőňUďöłŰŕ&؛୅Ӻ…ô”@Ż­Î"ŕ×y;/ĄÖůĐ–`¨g)IȲ9ąŠ–e’¦VË)Ą°ÉfA쟍 e‰«żŢű×+żµoQPÚŤˇ,JEě¬X"co±NG'ŁOP%¤éâ ŮÂąŘühá‘„9$ٗ⣠°h’3s|łČ[ęŠMŘY÷ű6tĺÂŕä9M™đýgşňˇł.oŕ¤üŤőuÜąţ¶#˙Ö ŤNĚŕć 0Î›Ž›Ör’ÓAŢťoÝď€á{YȸŻĐ6Q_3śąş(K  UĺŇř2\ÔşML×€ź É’—V–1ŢŢ†Ň µ±.”0•.4¶67±Ľ˛ ](¬Ż­c<{mĎiÝBÚľĐ`ŕ,b†Űv7M0DHołŢŞ!št"Př ›¸„ňŮr˘éKˇÖ6}ň–­śK€ůX›pšł ÚěvX´lÁ~Y¤[]ŕďç¸iV$?İÖ@)o•ńçIą€F˛Ô’Žąv&1ŹîţSt_ö‡ ŮRž-tQ@UułžôŃzż#6S׊µÇűŕËr€˛Lö!č0ý7č*±Hpe¸…ĐŘuŇZĆ‚ŰÓ·ĎË×_ĂâĘj°ÍţĺĹ ¦ś,ĚXZ^Ĺd4 ż_ŐYX,Ŕ0ciyl\@,Cˇ(‡(ĘáÝ憼_ĆôÖ=˛‘± ěI€H&5!-kuUyŽpëűAěăm ŐLćo$VV—pęÔĹ ÄÖĆVNŻbksăŃKËËX^]ÂćƦFٰЀÓF„ľř˘™Ö ďw'PpS“¨ç ńO, ^DbKä×·ŕEđ'ÄWśZ!D—cVüŻhZ”KnĄ•ň:c¸°úÂŢ­´}RP·:ŔשHĂT.W‚'B‘[U°°0„© Ô¦vK45a2š4µ9ű-˛Śł>$„ĚäÜ/`°„Ş®1HąuĄśë"9)KĆ0šß ˙ě«É“ńdji_óŇ»°80c<ąáĺo ¶Şß˙´Űw 3 ŘZ»3,µŘÜÜŚuY‰ 5ęjĽ ˛7ôĹu%d»W€ŚŚhř‚¶cw)ČýľL0L]cĚumüF@˛ ]ER˙˝»ß˘®ׯ]÷ůĂ…¬Ż­acm ŔĆhk„…SC¬­ą €,‹/žĂn„`!>×"K€fż”Ť¸A 6tRZUÎJ ĺ'–…P‹Ć“ň|öă``fo˛÷'~Mżű´lÁŢ? Ë0Ę€|ĐŁw™řMgÁVÉ ŕÍŮĆ$ bĽ´Sł‰;FHŢöůâeLäÝHBˇÍ‹NIđ`úL9¸(RVęňż¨qOŰ˙>•RŰ·ˇ‹SĺÚ40´q_˙ř=ÖŰ®Kú8»růuGţ ň›ă7Ów‰1 ɧ0/ˇ˛[FĘÖŹM‡oî}«4€Ăw+Ţ-˛‘Ń”đ=ţ¸§.ĺ0q[c“ŘĄĘuäŰ$gń­ş5÷Ö­…¨'µ×żŤËúÇŔ`a€˘p k† ŘÚÜlô YÁ&ů•7ós7ÇhőTYO¨Ń Ä`9\Cśäňő& fđĎrE• IDAT`Ż=;í?Ž#‘|´Ö°>b˘®+LĆUŘëA ä…¨ O…çáţŞPű>LS¤$©îZhÝ ˙dDăx&wĄ¦óxŘÇc$ϤOstuĹÖÜŐ?–×I·÷sé÷íŰ·°~ëÖľ/ůŰ Ą6Ţ… íí}JpüżŤ,dÜÇtß7ďýÇÝ žLŕÚkĺě׊ÉÜĘb˙ÄĚpQ˙=ü0jSc2ž`eeĆZ, 6±ľľŽĄĄ%ŞĆňŮlll`sc3h¨ŃŇ.…×PE[e59–÷Sŕpé†'né“w „‰–=IÇĄz ±xá"qŽ»6úÍ€Ľ™@ lśÖ/Ű&[ă"´Ťµ!8Qj‘†˝IÁ -I@cĐŔ)_hF´V4ôĹbĄT»ćäq—pűé÷“7€Ć˛:;nđ3÷‰đ7}zö?mô“żsU“ ×.ż~ ëý÷ö+ô¨Ü,‰"v@Ă2“Cřmd ăDC~ČŤµÉGd‹>oGTÂ.8Ęťłâ7Ăq TĚŹÇX_»]¨&Öî¬ÁZ‹ńhk,676±¸t wnŻ%yń#Ń‹6ÄŚÄ©)Äş'cw "D4ç'GČ˙ßĺđ~x/ěHĆ”žeu »˝B0!5B CŔ[L`]jXcQ Ęŕ&PĘąR”Ď(’0µqŮ50UäľCŇ ®śHX^Ům0%ŐÎ2Ń"íÎşděş5ďNˇµŁĚÔŃäî»K0Ô4€KŻĽě“0‘sĹ­”ţ}‘€ŚŤ.ňW˘oD+S4 sHé'd*äÉl]9ńŹ»Ďµ;k.:=hë˘=3Ś©1Ťf(íČOrě[f(OÜâc kÁď );ň…”ziný@MŻ$“·ŹĐO Ë#©Řť?ž4ۆÝŤGÔśťgÂF>űDIŠšu±ŻĎDb"Ç%}ä#ú-bôż5.a’2­6ř?¦Ţ…Yä߹ĴLý𠓨É]Ň‹irĄ 7* }Űĺ˝ßEljń{ÚŕÇwH‘›—/Ťą»őţű n=»Ś&˛qâĐĄő͉ýp%z2âźĐBÎ śN Nõ‰‡ŮÉéN–P”ÔŐŘ ޤ†Clnnˇ,K †Cll¬cáÔ)lol`¸0Äd<ÁÂâ˘$˘”ň´M¬3íYk±uľµś®(ÜΆB ß1»vY4)0Y0ůxk=č~ő#(©Ĺ~D7ŽŽüŤµ X(ĺ¶S¶Ćm4DĘíŤŕ˘Ż­[Ú‚1NĐ…‹đ=ą,ž­ż„Á1™Să¶Ś)Í[äż5‰pčßł<·Č;•DÄŕhí™&ä´ę"±D‹CÚÖF»Ą Řܸq[›Ső5¬_HÉţW_— –—fdäǧ‚v|°uí¶ŽʰqyňŮźň'J´3BĘb`^>µŚńx‚˛ÔŤ –N-ˇ( Üľy uaQ. ă·ĐŔ@Y–XZZ†µë.b^EY Đ…׬‰źý̧˦ş®AŠÜZ{ß­ÝŽ”µqItˇˇuávëóĺÔµEmj°V0e&‚Ń~ą!űuýžDÇ}ś&.ć{¶»&( p턢,PMj7¦‰EB)ĺV(FĘ6Xd’6–|t9ű5ěŃĺZ‡Ď;ÝB@%ţçrň2ى1^Á%>JŢ×ŕú xŁÔE ąxi-{aŃ·+ěĺL®¬čcjĽGÍxwÚyeĽU$(MA"Óq|6ăń7®\Ápy‹Ý37·˙ ýµN÷Á,d{tiüűýŁëŤÔŢ5ܤKJˇĐ J;íBVZyW€+ßú­|Ůş`:Ň„+o^Aˇ O-`´ą‰­µő°ŃÎĆĆFĂĽLDž ·oÝ ¦}rŽwÔµ‰¦{Ŕ™ě­[j"§Ń3;â—5öžT…Wä%éű%WpKôŚłu!JX+1ŕ…T %tí…!ż±,%tĺřÝřŚk«x¬ˇ¸#ťßôH+…Ú7ń×UĺVV„ ™Á¬@P°¦vn "—'Ŕç?Đ…ű„BQ3ž~†.O‚¤/no8@źá9X]„„§ŻkšŻŁfŢĐ2EĄĺĺnú<âwj™đSĂK·ĹŠ€iAB/,1—.^ÄŞ K:zBq żŤ,d{t™ű÷Š b–elĂáŞtsČź¦4łÄY—ŔÔÔµó…+Gʸ$?¤@ Đđ™Ö˙«‘‚e­eYťkż1Ć»|˙”‚­kH° ;ć}Ě6MŁęÎVUM6 RÁ%`CŰŤĘ‹\áv"†ÔEXŔ(ĺ3ţú%>w÷FÄ(}R†ł0”D0Ö€´‚†ËĘůüaŚ`Čą1ÜAE PKnň“`//g„± + ä;#É©ůžkż…Q´ä *Ëí Ŕ†ń¨ĎŻŹ„>yĆůÄßÔKŢąX~’"q-¸~ů R‹š‚Dh D —^ľxáM!” iĂ[Š€*w_ŐţŻ:zd ăX˘ĎĎż×rä;p0}2ő»ż¬“ßĎ^´6ź/Ý­jFb§ÝY &ŔZň‡]`›MŇŰʧ»ĺ†É0”w1Xkakş®a˝Ź’” ß™‘PBó…– 0ţwX4zé]áŕ˛kíLíÖ‚¬ł[ńŔŠŔĘ}/,;_?8©Ú§F&†± – L]ˇ(ŢÍPŮÂÂů[e+a0¬Ď'€ď˛H4fßbrÎń@pî¨ Óaűé6Í˙,Ěź>äŽd\yű3Ě!ą’• Q\yÂďőׂü1)ąa—&Ą,žhůiż:b‚|\LŢ~ë*ĆŰŰÝA)Á3üň»đez\Ňż©QŔ]ĂŤ#‚6µ3ă ´—XžŇO‘€Śc…ýôó– O´´¨9óřd{ kÜÎv÷ž ÚÂMXďÎUÂîi¸Y– y"’Bh‚;*Ú»h„!Č ňwŇ ąÍÝädľvVbŽĽç5x ź#ŔZ÷Ź‚Τj ¦$Ű@ľŠť€˘y@ű ĆÂ÷±€"ç®°p±µ©Q”Ą[ aťöË O` \P oÁ˛qĎ"vxú]HÍć)I٤/ˇĐô>L#y˛R"«ëĹ<—¦±A¸‘\bHbö+%Č­ q’&I~ .l’C<†:AÂ+řŰ[[¸uí çآŻKŰo“|íȸ ĄO=÷ĐĐź4(‰0Ě^ř“ńýJb´VxĺĄ aĺH~9„ä‚đÓ첌^§€Đő›l[ …6ÚÖ‚ˇ ÜŞn©ÄÁˇýězEŇÝ ÷,sYßnÚłç¶߼#Ôjâö˛ą5ęđ¦Ůš'@Ý$c}dzp jČŕcş[É ffÉł Ą µBQhhí´}c-L];’- ,YŘĘä‚ĂŻÇw ďňŘ®Ź9Y ësô+O„l ¨®ńş®ťŐÂJŇ#ßë´UQAE¬L »ą‡ŚjâÖîZŁk®)šÓą)đy¬©QQĺ#Ú#‰»2.¶@Z”¤-źŘ1ÔČŕ®NůČsŞ-s¸&= S6üóÜ0Â;)Ł—ňqŇ>' ¸š\Y’Ń[]8şFBŽ 0”"\yă LĆăn E/—§)™ÝŘÄżE8ŘI(.łń= dŮăěâö‚yâîUd ăžCńĹi˙~Ř21'ű(|żľ^(Č™»µŇ AC‘‚*4) N 1MŰ[go&5N­¬¸Ťq¶cdŞť‚](ZĚż Ő¤BĄjHС+Źa°Ź=0Ćř•ŢJŕ­‘\9$Z!+ëäŮ'Pr5cşžV^q_©çú»źSŽűRŔ,dÜ3Ř/?˙~µŘß6Iú]o&uŮúPäüđĆŻĄ'KP…v™ó\k@DĐJĂ–ŚA9Ŕâ`K+KÜúţŰ7obőôjŘ&xmm KKKŘXßŔĘę ŞI…Éd‚•Ó«ŘZßĸš¸ýŇ76 —MŻ(`¬KlÄr ę>m?)čóť[kaŮÂú8­4ŇÝĺ‚=€ČE˙3ŁöڥѤ4 rkďĂ”. ţu+[ő"ńŐ“k§Ë—IŠkH‡dEV–-Šćç‰ÎièEx$HŔY°É$‰oG蛳ŰRY±ÎúSšišăc"žDH çÝőÍcň‡×Ţ“vQăĽÜß^;”âŘ–Ô€$ŔĐV[‹+—/Š$Ď?µĘ V–ąŁ-(PëďF‰ ––É"ÄĹáî$kâTŰ$’(>ç»@ßňŕăBřmd ăžŔAřůw[ż@vťöOq´Ż‹śżÝ㢳 †±ÜÜžŮ%̤ă*ă|ŢKK§ŞŞĆćúÆXżsEY`0 Ś·G€ÍÍM ‡Cgy°ődYŻ•FQĐ…vÁDŤ9pĽ©j0ą ~6 ç‡KĚŁŘş|ýš]ěĂŻd2Ę˙ͱBW‰›ű}´?)Č HÍÍŚů ±{IŔJ@["⏛@IŽrm'€,ůÜüBÂq-~¨ b0đDÚPý§Âă[‘šđÉ_éÓ#».y¦"H,€Á˘áÚkĹÚî·pÉ8t\ĂĹő •“i\Đ߯_‚© ¨Ašmm»C Gz<Ľ0ÍS ™‚š'¸}aS,íłÄí©Ů-k¤®2:šš6…Ł›~ü żŤ,d ş4ţCYŽçŘi}‡÷ĂŽľuĄ5ĘÁŔ™·9óµ'Ýşr)oĄ‹ĐŻ&•ËĐŔڛà Ă!@VWWpĺň›°>ÉNÚ_ÁćÚş'sn”U T¶łŇn™ť5µOí+dlŔěýěDřčz k,jU{‚ő®Pż 2t¤ä´P® ¬almnC>ĂŹÖwăä˘ ŔĨ&5ŠnóźźŘe#Ô¤ŁeE\˛šŔ32ůk&îčźT˘YَĐ'A ąúËő$› ő4©0\™ě.‹J—óe5G—j-QüľÍâ~A@$} @‘`Řků1…ý{čÖ˙ßľu wÖ@JOfźÉ·G>ĂÉ>AˇëoŠ'Â…1p‚śŕXFj-H%˙ B~‡Ăćđ{!xy˛q$8Js˙á×ëęs;âÁĎgě QhÄáţ š7Ř[ż˝)қ­µ8űŕŘŢÜr¤*fwŔM ‡4H×ÉnŠtˇŔě‚íŔ Ă †}ú\FĐŚ•VŽü,°~M?˙˙ě˝i°eYVö­˝÷9÷Ţ÷ňĺ\CgŹnşilą‘06S„Z‘~€¤@02H„–Ć!qXl#ăŰB2Ž@aѶ,Ű ˇ ZtC‰nş»ş¦ĚĘĚĘĚ—™oľĂ9{ďĺkí}ö9÷ľĚ—U™Y™ŐwUd˝{Ď=Ă>Ó^ßšľĄsŻPsTE“!8çŔ1Ŕ= G%„Čh ”Á?Đ R™`ć@Ł(%®I~„‘AŰ6ŇŚT¤$6 “-ĹŔ`Ä‚3!™Ă¤×;ąă“b-‡•w9Fꪒë…ŇőĐ­JU<”Bą cŠż'·ĽhÂa _€€ą q2ú Ě͆Č!€jČ2tˇŤÔżˇő-n^»ž;<XĄźÓĄ)óřz÷´đ#äq¤?÷ĺň¬˙“¦x @–Ž×EhđűŁ“aŃ“(k°–Ç&owś˙aČŞ,ë{ őÔEŠGď1‹¶uw‡ĆXefîÚĆ(Vm “¤É7†€ť;wĐ4-öwwĺh ş@˛ëşĎ:’|>†HK”Š@çfcҸJW¨…QC,FµB!ĺdVóâŕV˛Î­µp•E ť›>ĺe1 #! 2‰G—Đ4°Öb<™HhÄZÉ;Hű€€CĚN='‚18WÉŘŚĹb>Ăb±ČÜýŮ­^¸ÂswĆ|6ť[^~î2úÓµMוÉdE,†vÖÖÝcŃ·ŇIn^w‡¸ř˝˙9]Ł"ěß)”żsţYź%.ĽĽ|¬ěĺ ÂĺW^éĽ=I^’NčHŢ%]ľJ@wÉĂß۲Kę\~ď–Đ•z>ÄŐpśß†‡.«r7€·Ăŕ8ą¬ŔZą`ŔsPŻ€%‰Ű3 a°t ŚňÝU•„7’Őž Ńţg¦Îf%k`cÇܦug-ČYX­†ČůĆH ă”XiLľ/ăɣɤ¸'’2Ź‘ĽÝ˝+ž·|‘ďco]¬¸ĎzG#Ś㎡`ŐöĚ0ÖâęĺËllŕXőÍĂŻr­76¶°(żáŇ÷ţń:ě1šl`´±™źŮ>_@Ď'#KbÄh4AQC?WŹ`\uěńN"«ć„§5Ap ÖňČäíŠó?,ą_)ŕIÁL!Š% Á0«›ęʆ$ŹQ—ń_Nhťű–ŠĆ=ë Î]8ŹÝ;»8µu ńn+îmćžµżJAč‚—`,Čř`”†7)îDîîiL}ył'„ŔQÎ3¨ŐbţĚŚ62hsK_içk¬•,@Ćď“7HÉhrą-ęJľ"ŔZÄ‹ç‰Q×5Ú¶C,]KFţBĚ슣ŞBKŔ|>—{KÔe“ŻĐĚ~cڶE.'ő2$:e"ŚI ht·DŕĐŃĎgS¸şĘ×`ÔŁ1óů’B.ľ,ßĎUĘżošÄĘůhĹt®9«÷EěÜąŤ»ŰŰ÷'ű醱±q Óéá˝ßńă˙€ŤÍ|ŽĹlşÜ|hĺ>M#ý6R.3˝ÇÄîe“%-3Ôµ2fFĐŽ&2ČXŚjh cŁ®,b4¨*‹¦eQ3č35’x"Łń­ôHpĘřÇ&š|J  m9}c´ĘáŰ ‚ŤRćčI» ŞkEĘ÷  p8_Ă”cÜč¬ç›=¬7´H4‘Á¦SĆ9Łtqš±Ţ-HáÉěďŽY¬‘ÁC˙^¤řż¸ŕó3—Â)Wk^śWy¬Ôë ™/pűć-3űSşÂÇ˝ 1żďý÷e ť‡ďұ*ţ¤ňJk‡KôýI ŤĹľ¤úC®U“DĹu?ąňŢ9 (k°–‡*O»żW[],Ń >HJťQ»Ň˛¬.@Ä L;«eh °8Ć«şFlZ„&Ŕ9‡E;GUŹ@dŕ*Qć¤őb>gW<–Λ őř^)€˛@˘®UpR”€Ş’ŰěćňEµ¤ŤŽ11Ü…‚˛÷yÉx4ÖÂÂHĹŽÍű Ťfô:e:ɨOc7–rWD"+ ‹H`ĂŁY4ş®ś]q˘đ­ď%XfEKČ´ÇIqIжlͬ·ˇPđÄ’6Ŕt)”SqP$ݜƕAZŠ{”Ëtżą‘QˇĽS­!Çň9Nç^nß]Š <ÁĽ0sî·sĺň«0nô—N÷w"ýĆÔý-”ô`Ĺľ”n|F©Ý—Á@úĚ&*Î+s1iŮE"hĺŃŹ•áÜőNQřCY€µ<YĄřźÄ—ć±#úr>+¬o†´\“6sŃę5f?)ďdÁź={ĆYL&Má¬ĹĆ©MěďÁĹîÝ»8˙ěłU/żř’ŽC­Ô¨<ńś,G+ß{xÍĆ‚ôĹ4µen59Ăĺ)–żh© ÖdÔ<‡Ő`„łß2#h›96š‘ŐrOÖjĘŚ×Ϥéz1F/§B€Ä–<Ĺ[ňjĄ3T @ťeźSH8")ü”茳ÂN÷Oyrv}qsË"€•uÖÎHUśűsţ¬Úą_@şn—ĺźđt«n_šŻ);IĎ\÷»5—_ţüńďAoż+~K`‡ŠďC–1.´ˇ·€űë.ďI«Kę2(čš[ ÷C(ÂŇ)=sף5XË[’ŇŐ˙$»ÇJ—>đÖÇř@ŢŤÂÚË_Şt’@~'î&xf…kŻÝŁĂCcáŹč6.śĂŃŃ!Žŕ*WW8ÜßĂÂI]|J |lűµ$l{¶r°IąÄšgDę%äBY,VąŃJiaô @d­pĐä<+1y[Uđm‹¦ńh¸ü}đ°ÖeĹťŞ˛€Ąöß‚„)¤cŔb>µ•U¨垀SRôťeŘ)ýT‹Đ„4şŚ„tߍfa¦rAV‹]€Á”ő—Ĺ30°)»°÷Ý×éš'=©—…Ňsî%sgmÂy˙ĹRĘŁhŔĂ€!ÂöŤ7ĐĚ›ľŽá‡.ŤrďÄŘU€a¨đ‡ŻP –ÖMdN$|Ëy8"(Ď7–gGzW›%Á<˘ţ!†¬ň.®Ë×ňŽ”§!Î_z&Ţ6),".±Ő¤ż§4ČUăj8vícrŇVä\÷żÍŔĚ ´Mŕ}îĚ—¸ě»â)ZßÝ)Ôr'#ĺy!z“Ńmĺnýś•άۉŞ˛ócڎ®–±Ga8 ˛WV@ťÇ9)iá<€ö­gÝ^,X‘ş0G„Đ"F §_ˇ|I=-PČbj=…\łś—!J<ů1Řýr§˛HĄĎŃÓv%é ¤©ÂP’,é5ÍĘż=dr×Ëzú,ĹÄŢv‰Ť0{Ś.4Ýő0DŕîťŰ’_Qȱę~Ő% ĎBňL ·,í~: ¬Â×yWÇT”žB˘\±ýŇHŢ´<í ‚k°––§)Î˙°Ęq ‚'•’ €a­E]W¨ŞJÜé!ŞűLĆČÝgh›×ÉĆőx‚Q=F䀳Ďazp„Ă,ćsŚÇcŚ760=:B;·ďŠĺÇÉN…ęŕ[ďÁsFk”DÇH{ĚngťO##h3ź4Cç·dµ‚;*ß|˝¤˘Š5b RΔ'€¤ ~&đ Sřvó:w ^Q1®cýăB+qJ+"ucŃÔ0ş2@N,€zťSŁťžĺž!–·Q®€"čŘ‹1÷¶M&ö'ôĽbśS†]]"jě‘Ă… źŠp@F Pă·»^rL›Á pŔµ+Ż‹J,ڞ IDAT÷fé™]!‚Ö–~O¸$-§Á6˝-z:ţ€°  w\RÓ0ŮHa–˛IŃ0ĘĐ—›ËžF…?”5xJĺíPĽOSś•â?É5{4 ‚ťź7mjŤA=Ş1Şk0MÓö\…ąËrŽwž¸Ťµ8sî,ö÷ö0®GOçŘßŰGĺ,fGSŘĘÁŔ8+<ö—zâÁ ˛<)‚o„Vč‰CHśďÝ1;ĺÉ…‹]Ď,+ŰÎ{AčÂI ËgBëŰě‚ > źaŠ…ëAS ]é1IČPoc@1ó$+ż›čÓy$Ę_ä}ĄĐ@ÎYK^‚Ä„¤Ái?éµe1”r*ĘâĹnu˝í™Š¸óű˛­N$ň%OEqń‹v%|X˝ wŢ—”ŃĄ* Ë^éŐA“źűČRfcÁj%­Ű ACč÷!@ŕÂ˙ĐA&ÝyâXN„+ •.!§d•'·ja·Űcć„'q<©¬ŔS*gOm r„sFIf¬r¸?(0XőĆ·ę›yĐéÄ»sBĹßb’¸ĎÚI› /+4ůë˝G»hDiV~}ťÔsCšB çB0­(4Ҹq‰ż›|şë*˙FuŤŃx ßxś>włéT’ŕhŚ#Şz„ŤSXWáő×. 8Hç•bř:Ńv”¶z9ćce´Ó,Lݲ¤4“ÇDÉ|Xď7é$\¨%Ů6y¸#©,­Ô7 ”ɸ¤†Ýt(*?y´¤,eô§s([ôć’BčřłĘęBi9uA Öç%?—ÎŢöś1Ű~8˘a—˝ßmłDäS(“\ü(öW‚USlCr|**”±§ •¦xw{»{°Ö”;_–•ŻŻü¸z•bt‚eĄb/Ŕŕ+RІüü¦m¸Řéł$ž°âDŽsWčˇŢÂwŠÂĘ<ĄröÔŐ]›âŽĆ ô”/ %•˘L&ú•h^Qu·*‚ô»Ze ô~‡€lMj ÝşI´CZ;Wj~ďűcäűŚQŞ»b¶űc$Y,°›čf9•L=^4ßŮ’Rv5Őpu @hq˝Ö¸Ĺ/N7ąĄIť­Ó§CÄĄľGp§Oăü… Ná}6Tő!tťI»ăQ˛xÓňţ ‹‡ŠÚň¤ŕÄ.ć{ĺ+ ˇ*ć”PŚĺyŢ+ÝŚ»Ő‘ëîU'@h¬4ŠA€­«*ő|H^‚«k°+€+qěXů˛ÚčĘ ąŔ52D˝:e•@y“ÎŤČ@ˇ+7ěŮîb(®wńµ»~…ç§ëĎע<Ăpŕµt,ÎăŠĹ-ňľĹŤë× ĺ_űľ˘Zyił¤tő«nÓýÉÁĂ 0Đ}HçOy˙ą\ÔőJ ©čÇśćHE«Çö*kđ”Ëđń}Đď]ކ÷)ÍmÇŁTxo{î‚LćR#Ż|ů1JŚB€DËYçéź#vnßA]׸üŇ+0Ö˘i¨ëZÚńzç,¶§SădKMęÇ\J éXąĄńÉ_)Ám'dDĄ×yŚi»Śę(µâĄâ÷b]ů0ú·$+ĘîכּJ©Zľ ŔV::ká=@NJĽxłç|MM˛ â Čç ĎCΓr˘`ďQadËż—w6¬Ç×´KfĚ72_ŽÄäW˝|”_•ż§ëšTHR˛âp˙W^}5‡H(˙ď+$e›.kżX6ŔĹKÚíë¸ńĺýSßch§Ý}H%•C«ضđ­Ë0ŹčIM”Ö`-k9± _ěbµT’‚ÇbŢ „ŇKµ=K”‹Ź…Ś‘<±ŕšĹB›ę,šĆٱ„ Ú[çÎ"xŹ;7·˘ďBř…Ý*ÉLV-ˇs‡k«_ĺljSÎgiÂEg[#•Ăq7ő&%&†qIÖ˘l“ÓH=‰pҬhztëś«ŕ} pâP/O > m}öJ¤PAťH9 BRăŻvęţG2üÜÖ—‹{Üąúގ°K>D$MŠWÁ§Aj‹‰Ć^©’"W¨ĽHJą,+°† ×©SşM1©żwcpýęë`De3|@ácGĽ´^ďd–^“ű-ăĽ(çÎďíżJ:T!%’Ü_m…úď ăMÚ'É#zRe Ö˛–c䭽إÖ/˙HÝĽ­¤umRbÉMuőéx‰§ÝX Žg/śG­yĚ÷nZŹ"6·6qgű6&xßŕÔ™Ó1·-Ś5ľt‹ĄLÖŔąJyů#bEć’¤ÇHzGg⤨µ#EäŘuţVoáţG?H¬d“~ˇ|»ŇşnÜĆń°•ËÝí¬uµX4MAdşßXÔ×Sň^PVs`xHĆîK§wë’NűŃ;^˘»n‡€Ąnűä…(Ľ)™x™ËqwőÝ&Ýg‚$r–@5倽ÝLať{sş.ß÷U?qvô˘&«@Crý ö}Ě—î;żż«ë`ŚމˇC!•®đ¬<<íĄ€k°–µ¬‡ůbO˘ÔŤlŤ…«\VěÉZM3•Äh00Tׂ1;:CZÇěďÁY‡#ÚĹMłqx¸cübŠÉć¦^]ôc'bÔΡŐoH+Z mÓĹ]ŐÁçka­éĆŠ¤b(„Čm›» z–üVĄ&^t}Šąś;«?µÎí)´Ď®sź*)ŚF@»h`Ť…±ťÇŞ‹Tu ÉŹÉvO@HôČrÍĹëbYSdKvżÂ ďŠůş2Ŕ4ć¬Ó‡›¦ÝĘ»'C×1sď¤}őI  ¤Ęž*ć‹9f;St\+äŹöq«Č!»˙Ę z îa†a•·Č@rÉcP€ĹÁ‹•¨żÍ QŔ;­p ÖňH$7GŃ?e–˙CŢ]Ž#úy/6zâ’¨6_Ě 4)ˇ“ @Ś cµ#k2_„5Ţ{„¶Ĺh<ÁÍk×Đ´uUc6;BdFU×°$a€č…Ôçŕŕ!xŘʢžŚ°Í™aŚ…5“͉ÄÖIÉ`ŚđD+ĺĄÎŃ8pĐ2=µŔ#G 'hÜŰc-!x4ÄMbę¨×Wpry0•\Ň]ŐBap@Ććdż„ŠĘćg Ś!-u…”ů˘\ĂČ]|?5ţ)•ű_•§¤ŔČŢ™”·`ôyîéŇT ›rYľ˙úÔ«G"ýZ’-AĎ;sBPá] …˛ä2‡*’;>ăę•+xćągĄ•îqî˙ă€Áq?·ţŕĺ^6îiiY>B $p0đ*ôw<ô&r¸eřóđuľç9ë*@ö´Yů÷’5XËCf±Ďź9Ą^Ô=qű1[4ÍçRnx8<¦q®Fňĺß·.ý (+82ę¶=KQÜţPćB'ImĆÚäŰEŚc,ś!\¸pwďÜÁ‡>ňĹŘßßÇů‹çńůĎĽ<ŢýŢ÷Â:˝»»ŕČh›[g·”.—1Ťq¸WWĎćŹG!bww‹ů\řţ ĺ&>â  Ţu2V’ C kňĆXë`ŚAđľő˘4c@ Á3 *%Ô ‘BČ^Ą¸©˘•rŔšů<[ęVŰ ĺ”12Ŕaꢀ¦®&źr˝®ńĎ5rja“XÓśşÉ) Ń4dżË}Ě &Yă)öŻŠ·óę¤E4†ň5 CKĎ#™®ÁO*÷K^ ’›AÂĹvůşę[eW/żVT–Čţîő¸.Ë1Űô”rz¶ŹŰľűÓŰxĄ!^Ě–!D-íĘ/ű^âĐpQN•†§qŹ\’xg(üˇ¬ŔZŞ01ľč=ďÂßůĎţ"ĆŁşKÜÚÖcg˙żý™—đăźřĽđŮW˛…ó¸äńĆë¨đXÇ1ë,ꪂuR†}Rú ʡ 61»ú›fgźGGSC8Ř=Ŕů‹ptpp¸wgĚČb<ŁŞGX,ćpÎa:›Şkßb< Iehć BđpJOśřÄšŐ˝šČ1ĹĹóé‰2Š1€YË5Řb„/b±<Ó÷Šš|HčŠűţs2uUËzd••2Ŕr…Ńx„¶mÁBëc#9ÖŔű€¦Â{”kË ş`ę”x×z7QđĚ‚ ÉöT¦Ök_QČ'=pRŔQ(·4 §#‡y'Ŕr ¬e+UoîŢľ…ůlö!öI·Ö—}é}jůU€`¸,=X˝T­÷˝ŕN˙÷€AŃ„G SEó=ĐĘC•'ąX€µ›Í°ł}Gů8qÓG/L‚G‡‡чÜΩYLęÄ}nť…qÎ9ĚçóĚÄg­Yn= śły˛•ĽÔR6vą Mf4’« Ç!(6ŕ|möĘ m$Ľ$ąmÓ"xŹ˙d‹fß´…˘×ĘHVpÇ$«‰†E¶¸dëw-m"’éßąÓ‰Ť† ËżÓę ĺ=f Ăť®ďyÉW(‰ĄD>tiIů›÷]€†ä‰Ďf¸ł˝-@2ĺC<čłĎK‚¬pÍ÷– ÁŁwüâńŻ@ =Úß„ćr÷ŔGߡoGô$ʬĺ‘É?űôËř?ć—´_Ě(ÔKđ#ßűŕ»ţܟƯżđ"¶wv ˲Ş2ŕ~RŘ)Dń4ˇ-Šâ4Ér*ŰĄI_>ÇŃ6mŢŚÁÖh ŁńHš UböÁd1ŮŕĆő뢨K 1ąŤ¨Ű[ŤÓř}Űz@77ÉŤîArH›ţÜňÖ9X'z)xŹÖ·’ż€”Á®/ą…ä<°(ń4Wgvş&Ű綇.ćť\ăđr^Á{5B5âž{*¨%_päňÄž•©Đ„Ź‘w˛÷LôŔAwź;Ąß)ëěaČDKܧ}F˙ąâTÂ) ĘżXž†Tn\˝ú:Śsů÷ |O ’ŇĽWŘ ý|Ü»Q^!=Ä´J†`ŔčB:éíč5*˙ŢłtMޏéń ĺOČ\}őĺ΋”Ż -]ŁR–žf:ö—Őë:`’lĘŠńe¸ŚĘť–ź’e_€’ Ź€yOSKˇHRŇz‚3ş§¬šžÖÁ5XËcŃŐ/˝~ ç/ś±ą9ÁG?ňA|ęĹWá}Ä×~ů—âK?ü>üřĎţ2®\ż‘«.=w_őŃ/Á‡Ţ Ueqcű.~ý…ĎâSź>°&Ô‰0‹Ň:˝y č+>ЦmŹŘ@Ţr) ®VN9=vüÎäC¶ŤZ¨±°(řP^W>Gޏ{k;FцŇÚ2ŘľµŤS[§ ‰P Ł–îHFQ)Xˇ(®«J<ů<´ď}ŚĐřF8IęđmUi˛ť†`aZŮYŽS×5ŞŞRč=ŞJč™77OI.„^›Tú<­÷ŠŹLÖ Ţ4łZP·jť›˛÷SŇaä”H¦×>y8%Ęć¤Đ2éłdp§CXóô&/ %KżHťeĘÝö„Ľz‰fŸußeź…@pä5tËîŮĽuă ´‹&˙fň9JS!ÇCăâ—ˇ._ń9źÍqŻÉŞĘeC0ľ÷śĂ}$ÍPÚŞý¬Řlő˘ÁáďĎň´(üˇ¬ŔZŢ&‰Ź*‹fxďóń#ß÷ířľżýq|ýÇľ _ýeż»ű‡řą_ým\ľ.v×7~Ý×âŻţůoD]WxĺĘu,ÚűŠŹâ;żĺOăgţż_Ăýwţ>v÷ó„Âđ/}čřÁďú řđŢ‹?ó)ô9\;y襀C *ąJ- X'ĺt©t.y Ś1Ů-ʤ\,„ÔÄš®ßXŚĆă{o}‹Q=‚÷ ŚýÝ]llN0=šâ™çź…o=š¦ÁÁŢ>ĆĚç ©Śzc‚Ńhß4l%—sŚbYFőŔpŚ ›bĺ]6»”/őÖ¨ĆQ¨ŚQ—4ðAËR`´ŃŹŐ뻪’6Îbäśdˇ(‰’ 5BˇŚ &D  ;Úĺrg~…¤Ě5śA “ëţőeŠdŮ ­oH–Ę˝@čÂ#Äťµž¬˙´V†DúůiÉ3Á…"Gç™éŔPçÉp2Yvtt€˝Ý-!]!9~ŹÇµ'…Ąťľ®řE)”dÜĽ´j:ąÁr*ţ_dŚQw -˙¶´ ;$äSZ:řÉ;Eáe Öňh%eĄű™† ţđWü~Ěć ^şü)ű2†đmßřu88á[˙Ó˙Ż\ľŽÝ#03ţŘWýüŔw~+>ůO~?ôc˙×nŢFäSă1ľţŹ|%ţÚ_ü&cđ×ţÇ˙­o#ă]Ď]ÄßüŢď|ăw|?ţÖw+góÇďÂx4ťs¨*&R‹Űčüfrř„ٶ ÖéÝVÖdş3c<ăâsĎâě…ó8ŘÝĂáÁ!¶ÎžĆáÁ> .ŕÎö6Fă1"Î=ó öîîŕp˙ź{“ŤM4‹ŞjZ,ć-Îť;‹×^|‘dâ4ÚQ.†•©%˛PJ@iÍ›¬kë,¬u "Äŕbr›ËúŇöX“ ›BŚXĚgđ>Ŕęet#ĺŹăq Ŕ`ćg¨¬qĆŞşBë=‚÷pÖŠľ°mۢi4ó…„YQrAťŽ™z¤_sţAAIר÷%÷›‡€#bĄgň.~¶ňyŔ >Ab\Ăj‚ćKŇy!€<®˝ţ:Ś!¤®Žĺş1.DO˝OÉúŚLŞ0…żľY,Zé„“ÝŞ‰Ĺ-Fa°Sk»YĚ… 0D`ľ€±‡hš|ëĹş‹ c ógÎśĹí[Ű’¸§—ÔűrýĘë¨]Ą\óť]ÔU…™÷ŘŘŔÚJÂV<ŢD!#ެv”<Ź&ŠÂ…g•IPřý“Űşv {"ĄhÉ›ßX§çR©ˇ\; Şj)[¬+­† Qľ¤@ÓX€#le1r#ŚĂH0Őa˘0¶pU ßz  ú,d]/×˝\–ž•¶m%á0¦6ÜŔÚ_Á‹×ưxÂđQJŽb%ϦSXmg $ —1źMř¨*ë%­–‹páĆŐk8:<(´y_ÁĹ1ŮÜÄţŢ^`˘ÄČŘ\48:<čĺŕ¬<-}H®ŤĺMt•ăÉw¶·%é´ěŽ‚`0¦˝˝]„ ;"BUŹĐĚç÷C=oZî•/đ$ʬĺ‘Ř;śâĆöR“…888«×oâ·>ý>÷Ú5É^'VeÁxéĘuĺ‹|Ńű/™ńĎ?÷ęJĺMD¸}w/_~˙â‡Ţg ž9ď~î~ňż6 gä·&'ă Ţg.ţ2 oUUA˛Ů­ę_q{Š"$k% _]·U‘9˛žąc-b M±uö Bëqúü9ÜĽz ďzď%„ńdŚ ÔŔˇő˘8ŚÁÍk7đ/|řŘľqŐh„­ł[xýŐ+ ź1Ŕűş.{Ć"!J¸Ei‚ŤZĺĆq±'Ď+dBn›…~Žm# |°Ďł9Ç1˘µÝÔDD0¶Eë[Śph2d˘Göm k-BŚp•sa>›ˇ]´š°X4˛mä]dE«ĹŽEĽ8{’BF™C`r§ľČýě %¦ç%yĹşŠŮłŃPuČd:„ävĂŞX4ŢŔŕ`oG‡ű [Zög3H /=)ÎĎh˘iÎgIżW\Z®bV,ňvyvÉJ×J¸nŹér$7[†FFčˇű"“ćm“ńfäiO\€µ<!~꓿†Ź˙ż?XE™übŚy‘Ä| 4O Lç]s’s§·Đ4{‡‡iš^’"¶wöđˇ÷_‚s§6&¨*‡í»»÷Şb>‘<8ŁWá:MM A¦ůÇY‹j4‚oZ0"ŞQ S(˘Ô‰/ „€Şĺx´ŃĐĘl6sŁń¶r¸së¶”ŰWW8ŘÝG=!8ćx9QŹÇđľĹÝ;wĐ,¸Q-Â,ëvÉ鲛ą b`xŤă{ůsydŠĎćŰČhG-šĹ)CŢ· š6€Č`vx(1€V˛‘üÄÄ [UOĆ0d`Ů"2#ú€`-Ú¦Áěh ëBŇ„ţ5DiśďIĎőLú,)AP˘Ąěh— CÁu,Őś/ňX,˙ś,Úěr*<ÚEč?%&Ęs’Y ôw}O’ ęĽ9‚"Ńú7߸˛¦Űń=žČŢzKß„KüÄřw üÍ`y?  XVş<†ˇâ.R±Ž˛<‚M%ş±·xţPÖ`-ŹD˛€öŹWKĘZ+n1§žDŇ$yż—Ë&V9tŻř¸ë,¬·!J#µúcŚjGř˘ĚŐóÔżoúL!&Šz:0éťĚĚxJÉs˘\ŇŐNűOÍŻÄ»¤r˙t/(Đ ¬s™Ú7ß'pסtĄŤ¬ˇś×/_‘;>Óç€ĘP†űío(÷ssw@héĂ×*„ ¨ň–‡Ş; \çĎpěöOu–¦[÷„ň4ýÜOÖ`-ŹVňűŘ˝„oFnďěaTU¸pć4®ÝĽŤU/nĺž˝pw÷öѶ{GX,Z\zöâ±óŮŁwáe­ŘÓBËŰ4W?€6ÉmĐ,eé5“ÜĘ€&Ż1H08% IDATÄé-TuŤ­Ó[hÚ‹égÎťĂÁţ>&8ŘßGĺj,ć3L67păę5ĽűýďĂl:«żr°ä°hć8sî ÚÖĂY‡­ł§qtpW×Ř:}»wď˘{Üąµ čXb†AVnÝÔ˝ŻĽŘÔ»…«=ąŽÓÂÉĹŢÝ٨Љ%_ŔąěXpÎ*@2š1Źb BNŞ´Ć!‘!%ĹĐ6Ň#Ŕ’Át:UŔŘMč˘čŤ©)çâŢ1%úߢý®Ţ39ýfíé®GB±{Ę„tŮ é5Đă˘[aHŢd­ĹŐ+Ż €*<˙ÇľaQę:÷z¤{Vú˝Ąsđ”@wĹΗ‚ô«.‚„á:=pP ¶ôĄk+híă®rŞśŔ˛đ4+ýRÖ`-OĽ^|í*bdü«ż˙#řťĎľŚa™33ăÝĎ]Ŕ‡ß˙nü˝řI„p{gŻ]»íŁżŁşĆÁŃliŕ1¸đĐör> 8+5üU]É<S;[#!cł ,exQňbÔd2aŔŰÜÜD=¨LÚíF śÚÚÂdc‚ť;A]ő ďŚ58wᎎ`ťA… ŢGÔŁZĽ>`<™€LJ< m+V;±Ć1X<:1‚¬…Óv’ĐWčB5®%/śĂďÖŠ%fťÖHÝOŕÖ0‚„´Ě-)^c!Č5“äǦmłë=UvJXÓő…đ(xďĄÔr}­1ٲuĎFn€¤<;˘ž\ާ ś ”@D¦ÖňŔňŃĘűâîŮč,˙´ť,ë•Fáîťm̦ÓA<źď©·“ío†®…U+ž@–ö’ňh°Î @‘CK;-^‚˛gCË š¬~.l—ĽIĹŠ÷”ˇg杢đ‡˛kyâ…@xůĘ üÓßýľůţ0~ö—~WßŘ–ůF-6c ľĺOý°Öâgń×a0ťÍńţWńÝßöoăŹ~ĺÄß˙™OfT˙8\xyľZµUbÖÚÜŞ7%|E¤ŠŢŰe{ĄŻŐ}îîîJÖµş†C+üű©ż€÷’µî[ŹčĹĺ~ůĺ—$ń2ĹŻŐŤFp•C]Źp° ‡1°DpőHí* ©° *Ý Ş*Tµ(ř¶ia¬ĄšB†0Ů r•Ää íuíŔ†P×#µÂX×’p8›Ł]e3€dŚGmä*Ť˙¬n€Ę8©Ń7N%őžŹ'“lu“µđM‹ńx˝$#Şn2µŻ$ýQR zÝŇ5$Â̰ÉĂ ŞĽ3Ű & šD÷@‚"ťEÝ)żD”ęŮ›f;·¶ĄDł˙PáxĺÖA±ÔĄđMÉPßf‰Köß“ßW¨ůą+— €B$Ë»~ŔĺŢş“¶/K‹¸${^K’5XË#–â'߲üJhš?üżý~ôżřNü­żţ—ńC?öřĚ+—bŔĹ3gńMßđ1üŮořŁřŃ˙ëgđ{źM,ŁČřż˙ŃĎăŹ|ĺŔőÝ˙>\e±P*ŕÇ‚čŹńzFbřÖcv4GŰř.ß­ŕ)Ź#mkĹ !Ŕ· ¬s¨G#TŁ1öwv˘Pár”vĽŤ­X»™@đ‰ĐA9>JđV鸪†eęĽVČ~B 0šh¨c$Ƣś)´FÜďéÜÔĘw. Db9«@ĹVNô&%«­ô»‹‡Dč‡#Ń0p´0N›E ŁŔ¤2!ő7E6Ě’Đ­oşŤ®aĐ1ţ%w~W 䎹 "3M–aěͧ¬»p "íŐî>Łă»WXŔYŃŐË—Ą!Ó>‹¦řűfĺŘ÷™˙†ď~9¬JăĄ(pao[6P2¦´¦)6(.îR, @şźŹP†aĹO ~|˛ky¸b„ŃowďMëče‹ŇÁ¶m—Ţ{C„ßúôKřË?đ?ă?ţ ˙&~ôoüG88šˇi=Înmâh>ÇýÝźŔÇęÂ>§öÝ˝üŐüüőżôďáżűOţ>ýĎ_xÓuĐĂŇżÔhĄÜĂK®_ń^G±Pť(ĽĄéMJ´cŽHS˝sNşěµçÎź·wł–>`§Ü«ŇâBĄ¸¨*˙Č9Dc„o<šKˇP–!“‰!‚LR ’‰Ď1˘Y4yěĚŚĐIŰ^9_9î˘Yäóäൣ ˝¬o˝*{(d”JµĚ-˛V“DFhŰÎ9Ôu ©á‹(…^B'‘„ŕH ÁY'ËŚ×< YE¬÷d=R_ůsě®)+ŔĘ·A=Mß‘ť ¬8Sł!SŚŻŰ«ô' ·\yő÷ęgëú×9FŽ}ź“â-â«Ö-Ýó÷XNn@ #!ŽÔĆ9­ĎÝf0…Ň IĽü@˙ýňžäđÁ¬ĺˇ 1á•«7ńMßó?ag˙pĄ÷{µ0._˝‰çŻü7¸˝+T¶˝ĚbP$üú /â[ľçżÇ‡ß x÷łpÎaűÎ.~ď•+Řľł°Ô#'Ę×oÜÂwü—?Ś÷ľë9ü/ßóç1]4'Ń1/vZ¶ $މ2¦ŘdĘ1€€ç*€$łÝ9#řĘYŘş–Zu’l}Ž 7ŞŐšŹ8<8”߸ăĽď’É:Ć<9l˛ňSć9ą[&CW+ÖŠ U g×u7! 3ť!€¬oŕ[)/4ukť˛ j("S•›1°$™˙©N~F2nfXV˝6§ˇŤ°±±H„¶Y mZą^M2!§aný/gć8fE˘ŕ$Ď‘x!$¶ŻŠ>ą•âł×{™“‹lýBń§kEśJ ‘˝†’ÇD×O÷ í(ŹĽ[Éřßľy‹ůâ>uüÇýV„ŢrQě*9 Ů ^Ś$tŚ·lş@”]Ô@ż§w­<]¨ňgz€ůčdň´—®ŔZŞM¸ră6idr’©Áˇ Wnl¬´ĺ}[KĎĽđąWđ;źyHqSbZÁşeŕŰ€ßúÔ‹p•NŢÚ‹Mż"QëĂ $›żmÂŹŻ }˘ČĹb ĘiMTeÖ.đJj‚űÓI…›ąě¨—˝:)J·á4;ŠrŻ„Ć=«nUCŞÄ BđšGp•1V”jŰjËá2U]Z‚¤ĘŔ:0GÔŁ‘Ĺ8›‹ŐŇżŃxŚj4@ąç@Śh­÷°Fú 2đM+5Ţ, ‘ŞŞĘěs!zp#×OȖچô:´§ćČđ> ·Ľ—ß+ç­Q¦ÁDć“ü˙ÉY’Üüś›Ô°Ž‡SŰj..mVĺ˘Ů#Đ%®—aŽt¸[_r,¦GSěÜą«`&i·b×'yďá•zKŇłŢ K˙´ôaŐĆýe媩ˇOŻr/é´‹ô~v Jˇ{§ô{Îó¦®Ç;­p ÖňĐĄ{GËÉěţb¬OşçÄ&] ŚŐŇ®(®Ý{ľ‚bx»ÎCďŘŰąü/'DiÂLă”ă„d¤ä,„ ż««›”8z©»g-%o@•S‹ź‘˛ďÉP—‘ä\kť–Ó‰uë}Ĺ®.u¤ZŔDR뚌¨¤:A“Ł‘ć%ř°pߢŐvŚAC`ŔŰmŰ„ćß´6 pm@TŽi#,Ŕ˘4ša’äCWK5„1‡qZ=PŐ4I¶?+xá V(…@pÖh’e@ë…_!­—Mp˘®]±xÉ8eVWsę"(÷\Ô˝í–e§KČ^"#k6\»zĄŕŔ/~_c~Ĺ‹ôćsŽőX 2Ž;ÜŞ Yt`ě/;î{á=(÷§ź Eß„ž Ś%N"ďäRŔ5Xˬ<®»KşÖI_ăÎŁń®ŞÄ‚(”Q":‹ZÂf¬E ÖVÚŽmă‘Ü®UUgz\bh[^‚¶úmŰmăQŐUf Ţc>›<­râµ-Z…*uđĐ’?µ§"ś…#kž‚Lĺ"kE‚ĺ(\^Úô0EXďĐ6Ťö~QÜÂ×nŕÄDçŞĹn« U=“YS1ČGąvÎ*€ŹAöäş…Č`‹_( €—1±$–üyr–¤îbQ˘ŰR%dm294ł+1˘źř•“)Ósfa’§@ÁB>őŻQO$Ětů•W4Ü´J“ŢďYíövjďQ„î…ŘW¬ÓÓóĹ9 ˝ĄŰЇă?¤g– ëś ĎŽ»bËă&đ˝ţPÖ`-_`ÂŹ9^§)$Ä6N† ôľ1€‚vK ’4§›ČHSRd@lś>ŤĹt cXi”%Łýôąłhfs,ŤxŔ¨Ş í˘Č ®+ %„H^Y ,ȰĐ·-ŞÚÁUúÖ•ô&`"ŘzăÓ§QŹ7ĄŽ*L™+Őă"Gűh¦G‹)F]ʵ1”(ÖÖF“ÖL6Ć ë¤Ń‘—‡”2J>Dµy§NÁU5Bôâ˘'’$DÍľŹŢöv0ź #dp®‚u]ŤżŃ±QŁ÷$á¤gÔTT[ } ů»^٧ÉÚ^ÖÓ?évX ňP9Ů0éŐđĆh[źŻŰP’éاŻówĆůCvG¤č7ž˘o(ČËKE® wőd‰¸ěŇXě÷ľŻ÷Ł{˙źä ` Öň&ąë1ŠĚGTĐü °$¨II]"—!C…!“BÂ?Ť%vÎŚ3gĎŕĚąsw¶·qçć6ž}î9lnnb±h¤Eo»Ŕ™łç0›ÍCŔäÔ)ĚŽŃĚŘÜ:…Ůt†Ńx ß4¸üĘkÂř·s”X÷T}I‰ZTÖ˝ ő©S¸ôŃŻŐž]ŽG×Ň ZǸňż€…o–ŮĄP®rřÜ/ţ,H“%öźňrűÜŃŢ÷ĺ“›—Ú÷r9ŧÜyÂËżú ´‹™TO!Ź; ’b&BU×°Fbę)±N‡‚–, GCHaîşôĄÄĆnâŰďbţŽ$sŘ@Ů˙ôşĺP§íM±Üŕ`oű»»Ňäç=˛şó^1¬TĹX¸čÉCl[ ‹¦BÝ&}Š©K$é1'đY‹ UČńřäŠ/”CŠë€Ńć&šébۉÝ ç,Ł"3#Ă9§Lچ¤{a.?IKd ąz!*ęęIÎI–2Št·Ň'FŽĺPç=HńrńÜ(0ᔿ’jý ‚6ů±)î?8g”—ÍęO!­ř÷0„{ú®ýţz«ÂűŮşďŤs’kFţ2L‘Í_¸8†@!•dOźé}_ľoíš— ř(Ú/?,Y€§\ş©´˙ý¤ňĐńđŰ&[5Ąőľg«äÁ·ŞđX·Ţpńŕ{çšţÎĄK©‰:bÖ|JřăČ1ŕň«ŻjÂ$Á#‰Žtß]–zJ2Ś1ŕÖŤ›wnßáĚŮ3xýĘe"ŚÝ=a×3V2îMG$8ÂXɸŻRx„7^ĂâpAËň ÇŠć3řĹ\’Xg`É^ńş ż@đ­&JB^rŤYxńéOţ$ęÉ&Řh ˘–ě‘uŘ«ť/w\s 2# É­{ýŐËŇŐpĄO÷<Ň÷ o^V˝u«ÁďęĂňŠĺ©˛§űFÜ%ńöu}‘›‘}lé{ ‡y ߽愧-Ap žRŮ=śjéN„š0Ĺ(zë&¶7Ég*żR¬¶—ń¬¦mé÷\§¬Ëc^7íSŹi2,şý嶲Ý>ú®Ňr26X7źKG Ťq`e{Cď…äŢ2=PLî¸RŔűJa`ô8Q kY Á(SKxQď AĎrůYQ€h [gĎŔÁÖ™3ÉąąŞBh[UÖG‡STU…Ăí¨űáîöťîü±Ďa­4Ů1ĆŔ8 o L´]˛˘s:A3üüÍÁ]´ó©T(Ď>ÄNCôBędk‡Ńxa ”Ľ1__Łe{Ň«€ž'äú-fGÁŁ>ÚGë[dZCpő©Ě@®žHm€- @*Bľ/”IaĘü ŇßR ŮB{ŹĘůźunPńěCß“A@ĘB:Źj˙NÉ)y‘Ĺ×®jč ,Ç{=Î'ŐÍ'Úń›Th÷ßpżËn‚ŹŇř \ô˙!é6zŚç@0Ř đńFůý~ĘżO›¬ŔS*—ú‘8đťł2q§2Ą,M"ę|l¦úIŹó ăysă˙Ç?÷s¨ÜęÇţŃ•v( ke®Ę#BxáYAśéÜŔŮ%^`™”ÜGl0ŞG¨'RI0ŮŘD۶ŘL`ťĹŢî.bŢ÷ÁŔX‹?őéleŠCˇSši×!Ä1ź ×€1VąpĚA8ţgs¸Ĺ©Ź@3›a¶żćh*«nĂČ`'V(%ĐW$ŁĺĐ€f±Ŕö­[]ܬ·Ę’}0łľŘćAĺ$ŰôzŠMŽŮvXßż 0¬ ĺ>–ĐF±ďô@¦_…Ďb‹–ö doŰp^x§ÉĽĺI~XKĹźäíďcEô'[‡¬µű©u®–‘Ą8r§EéÄä MtÄ aŮ#F ˘DżiB[ë᪠ÎUâÜĹ €ж LĺDai ®kŘz –Óéu=Âó—.aŞmgÉŞŃ&bĺÄ5ĄtđÂ3Ďbş·X¬n0@© /ď=@Ľ(kXpôŇ xP+€€śC]W°u C„ŞŞĄ|ŰŠă$µô0Wj &h77%±nŢ`1¬¨ţUOLç)–dJŤ_¨ńLîCĚÄ]R`ş©Éň'î;+j‘Đ›éY¸śV&ׯ_ÓŽ‡iŤĄş&Ąvś˛{Sűľ×ľŽs¬/«ľŇ`™Zů©Ä َ%ß@×ř'y×pڇayhOňú0e ŢAň4<´o7mćă@ôĂy,ÍK1)µÄSËެ(Ő5,[ NPĽlţĘwKŔ™sgqîây ăŤ1pöÜ9Ľńú5<ó®çpăę¸{ç6|+´¶çźyçÎź±㍠|Ű"†ÓgĎŕÎť;Ř:u o\»† Ď<k M­sgQŐNź;‡éŃl,ĚĆ9˘!\|öY´űÎç/žÇîť»°U…Ĺ|Žł/Hn€ë—ŻŔi˝kśł2…p 1HG?¶F:…v*ëPOF ‚µV­±đ!‚rg)P…WęX'kpĚ1ҵŻX©ěŹ/D 3ÉWŇeŹVVy×e€ky¤R*Ő'¬˛úß rŇĐ…sÖVŇuÎIW»şŁŞbĺS\ÎaL p˙[+ }–2ÍlŽýť=8ç°»sU=ÂĺW^E]׸őĆ-Ěs0‘fîOpűĆ ŮW&›1xîÝ—pőňe4Íłř¦ĹěhŠ˝=Tu…ůl ďnß܆÷gĎÁN=&ďú ŕÖµk@sŮÁöww1Źa ěěîâöť»ŘÚÚYÂŃÁŞQŤůbÓP&8BL–ł$’Ô"¶ä=MŁCE–NŮd­0źÍrDăp»{íľm䪉 GÍśÓ…ˇďR&Ň…ZµPWľŞeŚ)|‚”VĆÚüOÂrşĚ9 ŃY/ÍćĆ677Á̸{÷śs1âÔÖ°dŹrßÇmő 1lnláÔ©-ĺ>xŘ".ó­­Ó˝15†nţă€666‹ńŻĘÓ{"ŁO`5™PŐ#ëî9˛‘§=Ap žry’®ôr¤±Oł Çżúş]—"ŢKŻmf‰ŕ=¬!xĄľĄ5Pʍs#ÖřÖgOfđ‹ĹU]Ă·-&[[h v5Ű_Óí"˘mH%Ö:î¬ÁîÎ]0Ö´Öczt˝}řŕĄv?)G–¨ţčî]l\xĎ}‰Ř˷޸ŠĂíđ‹X;á0łĐ‹ë“1ÚçźC==Ä8N0;:Y›Ç"Š”‹Lm)ë"#I}ÓŹ|16>˙ࣸčS® WU0ő8Çô÷noăp÷.BŔP˛ŇQr«rO =@P܇n#€«k´m“•?!ń$x´‹¶Ş`S{ĺň9Čű•żŔŃŃäćł®ľ~† Nmmáđđ wĚĄ‡éŘ%÷–¦Ó#Ŕ< Ŕ,ă?X5ţÜŐŠ%!DLgSÂZsSž€"šĹ\h¦0‰g)FIR]öű?ŕ8źB…?”5xJĺI~Čž”8˙›‘“$ž\ÚÉ2sŔŇ4Ç“‰Bş ť"ŐŠ€ČŇ6¸Ş$‘1DĆůg/âÔé-ÔuŤ¦Yŕ™gźÇÎÝ;Íf°Ö·[§·˛‹˝ŞG‚#ăčđĎ^ş„v±€u`Y‹[oĽ˝Ý˝.+?— @óŔ»wńÂ'~aqx(D?Ţwy…D€‰@ĹÖ˘yĎ»`_»‚h-bĺ`ŚSú`€ KkâňYáHŇş˝t áĺ—s ]˛ÎXi7"B ííŕ…źý ¸ŞĆŃŢ.‚—VÄŮ•ä{@ĘF“‡ dNS$ćÄAhĹ€!Ö}‰— Ř‹`­¸ÉűN5ěůţ2 ±˛ďëׯÂ8§;6HIš4ĐFevÂ’,iĚtŔb‘ŃkLfů9~Ż&§xĽˇĄ±Ż´¶{‹úŔyÜabX2°$!“L¨Ń»âbI Ść äl V4T:ˇĽÓ:kđTË“řŕ=mîţGîÂĚܤچ¬s5śł:o%śŞř˝÷âFVęÜŤÍSpĘíżX̱ż·ŹÓgNcçÎ]TU…[7oâ`g0„sçĎcv8Ĺl>‡_,°X,`ŤĹl6“ÄŔŞÂťím4‹Î_¸ŁĂ4‹Ţ{É A“ÜRLW'Vßb~¸‹fz$×*x°v/łÖÍ3"9QhÁ7N!: ŚF˘ ť]¸3#ÜĽ)ŢŤ÷ľńîpx I‰Q˝ VŔ‘qµ«A‘1Ź0›Í1źÍC@3źˇm¨*Bб P䚧׿ÔeúKR_׆ş_䇜´[pN$Tő‚Dő”ő[VQśŻ``pýęëĹń8;[–hĆ1+{N:YUäޡ·jˇ+)–˛˘˘b8”ţ˘ăÂÜ_FË›¦Gé§Ä?M°$˛ŇîrŹĺóJ”±âtčX#ŕi™ßî'k°–‡"OŁ»˙qąđň޸ë®GdQW¦`ŤË“|Ó´đm WU¨Gµ\ÓȨG|p-~1Ç•W^Í i˘Đ¤B`ogWJoĄ ޸X_jĎööĄśÔĚçsP”¶¶’ŮŢ…!—>µˇ’"M%~I÷˘ő°wîÂé—€·ou÷e_óÁ ľřĚbD†ůŔŕľú«ŕ_ü,âď}hĚ>üaŚ®]‡Đę(#aĎ%üŃ)ĚŽŢ0ŔF9÷Sµ D;‰ÔGA3gŻL"2NĽ &_˘tWúÖ_ę0‡ţşëš×,ś'¶}ó Çĺ?!ôşćQ±Ż´î“¬ŚVŚmióuŇśŇűť‹JB…N^K+KŮ+­¨˘<|!tÖ`-oQV)ţ'ńeşďŹ Ż„"Aoßb6#ŘÖĂUNşÖ"|ÓH§@’Ř-‘ɉ€ÓéTŰü<éÝ`řĆŁŐ!ŕü3qçÖ6FŁćłBđŇ.Í|Žj4Ç[WpĆâččăÍ Ä±µu !2BëqýĘ ů¶ ¤-j•zU{FiRľy26`cá޸‰đá‚pÇ IDATŕľôKa.]†yß{`žyVžˇŤ öì˙ĚgÓ§`_y°ŠŐxC€3ílŽŁŤ*ë@Ƣ©+CXĚĎçčLuÓŁłEŻaPbÝKJźŐ+2ýW9ä;ĂTöMQQ×ĂAŽLDŔěîĆÎĺ}uh†ĐWL+ü*%yě#¸ĘýŢs…Ü{ű‡!÷3N:†ˇ‡KpÄ˝×-;;†¸aŽ8fÉ‚¬ŔZŢ””®ţ'Ů-VŽóń€”U“urűB’—´ lbú >€C„·!F EpęLgŚdX·­GđdőXZëßâÂsĎ ]4â5p…pçÔé-,¦S\|î9acsĆ:Ü˝˝ ă fˇAU׸pń"ÓŞq…ť;w1Ź`¬YEíT Q:őž$ĂZ.*l•ÝĎ`Ť¬0Ď_‚ąt ˙?{oŇdŮ‘ÝůýÜýď˝x1ĺś…©T»ŠěÖ@J”Ll“–Ý[™Ě´h3}€ţúÚjˇµ´™Ě¤ŤĚ´ęMŻ$ĘşŮlŞHY¬( @N‘1˝é>háî÷ú"22‘@E˘âŔńîäׯ_ż~Îůź)–Ť! †IvDŻµËŹ>B!ЎNeX«i›@ÓúŇż8Ý’ G‹wŽlÚ‰@M,,$dĚhAĘ>׌]˝…ÁG»Şąw ›  ˛ŠH÷ĂşľŠĎgŚöă"LV8ş _eŞÍçXĆą`ýľŘΛú:?ĺqáeĹp.^*8¬l¬m÷©Â»óŻ’^ůkŇŞYń:#˘7Ŕ ˝2˝Mvţ7ŮĎMöĹm-8ÝŚĘž•+Ł*Ď‘N ¤ UňĽÖ©ŤĆh ÎŰż•’”ĹŔ—–Ţ]m:™PUG‡Üľs—çOžĐÖ ÖZ†Ł-ęzÁÓÇOŔúЂѩÍ9źRXIÉńáĂ­wďßgv>áüä”ĺ „0Ş&Ř`¬ ÷ŢYĎőÜŰmYc™üŮź‘??@!Ű–üŃ#řĎţs¦!í.¸ÓSP 1ŢöB¬Eţč‡ó3°»µE}˙>Ó[·xç§?őI‰ĘśzćyD–—Ţ©˛ihŃć…•%Ç<áüh €hŻčS19€8şküÎ>m3Îo’Aó÷†gňAU׬łJ!ąÇŇ)+óěMUű¦żá«´Ń9«‚ÄšoÄeHFrţ’]ŕÍ?ďUü®+Ý7tez[ěüoJ@ąčĂ~­¶˝zlÓŢÇM7kR*˛Ě!dŽc5¦Ő!{žCY‹Í™4>źâvĽ˝M9(©F[´nąűđ!““S¬5äeĚ%Ű;ŰH©xöŐc´Ö<|ď=¤R<ýę+¶··چdYŽsŽ{ď3Ź9>:˘®*ĘŃČwßZŠ˘ŕěäśăŹ?â·ź~†Öş´±4MĂB7 ˙ög´Đţ韢0d-( ĎäEâ¨e‚ł_„żC໇ůŃ1Fcę†âÓß°÷Ĺ4ÚP(hš&Ô‹yWLÇ›"Ä/™ öżí‚ŰĎO§÷ÚX´…‰međŔ§‘ ó‘ÜGŇ…-ö‰žÄ’Ł NP×Ő:űąč;Ú¤IżĆ|ŢÔzWščÂOřk2-·öcůĐÇKďçH‡5aSVoőf}&ŢöPŔŕ†^Jo“ť˙M (oôĂé_źúW·5s«QR!$H‘ˇ2_ĐÉŤ6ÖCÖÝcXěPS·ľD­5–˝[·P*GJÉwßĺđŮs¤€űď<Äá8}qĘÝ»;ڶ·yţä1ĆîŢżĎhk‹í˝]ž|ő%ĺpŔp4"+r|ď{śžśb­e˙öm2•ńâčáh„µ–˘,B0źÎ±ŠA‰]ř‚TÎ8¤5ž‡8›Oçđř)Ü˝MńGär¨é*şšŔ0e(”ë śÎĐź|‚;>EYďË ¤ÂYK¦$j0Ä×@\řč†"ó ^ ”Tg˝ ó!dşŐkÉňđ¦©p>—˛ç/R†ŇÄ^ŘSʧđaHI‰”`ŃĆ0(lŤÇ Z‡đC××7pt(w,3µĚ ^l‚Đ»ZŢç6l-;Äő— ‚‚đ5d4ś_¨ż“ PI/{ddő”Őň铸ĄÍdgą¤O«cćhüUnł<đ:ô] ĽnčĄô6Ůů#˝j?ß쇽äÂçŁ Ľs`µńš©ѢµFŠŢťhsw>Ő¬Ö†z± &•ůęóß2ʱZsřěp G#śs,f3d–qv˘|»H°Žg_=ćŕůsP%Ď?ńŮç=; iĆ[cśł,Ş)EQŕ¬e{oŹĂçĎqÖŃ65ÓéÔ3ŰL`u, AŽĹŕ͢mQŰc„”úOo)6É١r„Cno#šÖC&Ú€ĐŢĚ`}’Ł8¦^ů—!±Ć‚łX)12dY0#ÖYŚé˝ř…AčňNŤRĺ`Z7ľM«řltFŚ0ČĚ‚ńmkhë™ůŔ´ŤŤ–¦nÉó"ťÁ˝Â7΢”ÁÇď0eŃÁQ^ƶn%UűëŇzbăn±áx"<ÄO s-eMHXňř'9LJ˘„»|EKŔw9đF¸ˇŤô¶ŘůżN?ßř‡Ý]ÖkXÎ…ôµ6h˘ÎzíR/@ é3 : ]ť˛úYëKíĆÄ4[ĺůů¤ ĹóĚJ{ ÝhZŠ˘@ë–áxD]k˛"Ł^Ěąuű.U]ű<GGڶÇ4‹Ę;V;ČňŚťť1mŰ`­#+ ŽȤ$XçČóÜű$A+ *WÜ{đ§ŹSا2qe‰)˝Ó˘Ť0żµă” Â;F»9‘eŁqZ#ŚA…°H«5‹Eĺý„ňD€č#"–¦n0ÚжŃLD'!h˘ă8"¤VŚřŇű}b!$łé$ ŢlaŤŁ®+fł Y‘ٞśL€sgý˙łĹ”,Ϣ#pÎ@[ŁŰ:řxÄ@7%şi‚2Ű3´č/qĄÉwÁ‰ÎŚn±şőyVĎ»ŠŠü6}Î9Śö~+˝ŮląţNÎý­SďĎ‹nţµÎű Xg—‘€NŘ ]"ČGÇÚPIéĂI]çňąv§Őgú®‡Ţ7´Do›ť˙uúů­Ůë¬cďţ~đÇĘŢţ>÷î= Ë2ËŢşú<A#ڶä>f=0%yY˘u ¤TěÝľE^cmŤhš!%EQ`­ŁZTH%QYĆp´ĹbîKHOĎ'ڶ·É‹‚¶iy·©ŽÇH©|¶Á˘ŔhK^ć~Aµż†zYäĚ?ý+tkBĺÓÉ”óÓSŠaÁ˝{÷8== ŔYŻŃ;ç0Ö"Ą7‡(ĄhëšüĎţ[lŰz‡G¸Í0ÂńÝËéqáȆ–5n·”nÖ9GVd¦ aţ"g[;;Śî~ŘwRzˇN ¬1ě J"‘±Ĺżřţ'ʲě…Pë(󜪮;5×Ů$C0eHÁ'ięŽ9/\tŹŐ—±ĹąŔ ;;{śťťřg µ¦ť‹ăÍÁŹ!üďŠ)amĆŘŻŢĚa¬cP,ę é|őĹî\ë 9Gđů y¶ľá=ůţ‡wćť3†{÷˛űŢGÝŰŠQń[sÂ3`Ą5–;ţÖ¤XyQ2ÚýK/} tť×P¸n(ĐŰ’ľ÷ëú#\µ€Ď›%±®Üw&pV¸>ůŚ\±źş„Iąvg©•_<ŤaҶk(Ę’¦j0¦ÎvoÝb>›˛-Ľ _{^ëĄr„RˇpŽÁąś¦n»â4@W¤Ç9‡Ę¦†Żľř‚áÖ6‹é„ŹR8=9eĽłĂógĎü; 6t#%ăöw˝÷cô8;‡¦ńŢe‰ŰŮcˇŮĂ#śŃ` ¦Ő,Mžg”8|Á!»Şo2Ô€Ľ¸Î0ľVˇÎ-łüĄÁö°ĚňŚ%›W´ń•O˙öpf|› l/˘3d¬X'úă{N3Ńu~áyü9ŢT‚‰OE;˘gpB‚tď»(‚JN —Ě-é·SĹ<•ŽĐ9$ă':XÝ÷)˘X±ł/”XvĘ´ř÷G6ŚKÖ§ŽńF˝żd_ôĄ„qö÷îü—;ýf¬+´ęGtéF¸!€5ćÝčşäp 3| )9}ţ”Oţýżĺţűč÷ßó©}3ÁÖwÂ;ŞuĎŃń¨|F­5h\ŁáŮlŇ-â±ňś7w:˘Ď`–ç´M…sPäĆY¤R´U…1ĽŮé´¨ÁhP’˛,Q™˘Č ŠAIÝ4Vwç áséOϦ8áˇűČ?zä\ç|ýçhu‹üâ Ě÷?ÇâŮsěí[°żëyˢ¦xń‚zßk‰UŤ|ňaC^ëµŢČţDDHH2”’dYÎĎţŐ˙Ž1šjľđeXŁĎqŢD¦Đ3‘VP!AâÝ;;;L&Sż/·ĆňŃŹÂăĎ?#/KTž“gľ `U×äeIQä…?–ĺÝđżý÷˙±żż4ݶw¶™śOV˛®ĚńŤ‚/ŮśqĽ÷Á|ůĹ%/8}ő^ëí\D~|ĆśźO_ţ]†Ă2®_o¬ĺĂŹ?ćóßüf˝ša*¬tűÖ8ţÉ˝=´µHF@ž źťĽą0Ę„ŢFÁŕ÷~ěüoęŢń÷ęľ5ZÚíRˇ˛ •eĚÂQJzŰ7€”>®=*"AËR˘Ź-—Ń)3T–c-H%ďě˛kŹ˘,Ď+ĂMSăśŕî˝»<úüsv÷ö°Öŕ€"/™M§€@*AS7ěíď±W]©ac ;»» Ű»»Xcކ<} ŔŢí»ÔŐ‚VkLSŁňśéŮ„Áh@–ç(™aڦ”´Z#CĆ`ĆcŞŁ#ďÝcpvJ}˙žgâ!Űž”ز`<™2/ ÜŻ~ÉxgŁ5Ç“ŕç p©Y9Ŕ4šzˇ)%ş5čFS·-Fĺx˝5%hîŽ^pB@(dŞ] _˛)PřpAȬđy"ú$B:DŢ­ĘP*C¨ŚEµ@ĺE·-B‰`¤Âˇ`´Ĺ`k«Ó’ťÁp‹VŰ^PŮ4§^n6ONěÉG1F(%6ťrqĂW¸źsŽĽR”zý۸PV^9 .>&Ś 5, •qyoŔ ﬩2¤đ¨’ř|ńýľ&]Ą`Řu_S#Ýż‡ôű`çS÷‡Ż™Ô#B§ÝFřk-Nv€u€]3Ä;ł9"<3ÍÇäC•yáa0’mýüDc¬ăŕŮ3îÜ»Ç|>#Ďr‚Ńî6M[S–ŁĎhš–bPt¨ĆŢî~wďł“ŚÖĺCćóEYP× š¶fĽ˝Ťn ŚÖľ±6(•ŃššĹlî‚"§5š¦nhÇc>™LřhQ1ŰÝÁ…„B±@Ž3c-¶m}öOvw©?fO ,"$Ó –_Kgź÷Ε>;˘ 6éÎÉMŕ Ŕlx§Ń!08‹wöj!"îwú‚Â]=ąŘHĎ€ 8bçłéÔ#3É$pýĎ~Xč"\€ąE2_6PwČmÚ™’ˇEHA)’óĹúĄ«Ôu÷*B@hoÉÜ’XłÖ›Ëç]zĚ.o‹îŔ†kŚÖ囀čGóuémŹű_Ąŕ÷® Śţ2ú]ĺxŁ^\hÓuĚőÇşń¸`ËMlˇŘŔ \ÇW:?­¸ ËäôśŮdÂp4B× :”ÇB’çLJG´şĆšžaííís0 Şyťp!(Ęgˇ(KTž‘ĂÁłgXmPYĆÓG_z4CHž EŠ´ńŽXŹ>˙˛ Y”AI3™ >ţgź|Šü“?Fh_qPHĺC¬ĹYĂd:Ç<úűÁ{XGĎč¨@7 ­IŘ4MSc”e‰nŰŔ ĺş¦9˝tH׳”.ÁRšX—ř[,›|:ÁL$BG°,3ڱäJ†Óżçĺů!@‰·řM´Ńobđ)]  »„źzĺ_|Żţś«L˙djł$r]ĆăÓ.%â±( / HéE›ďIĽĚáĂ$Ż ô¬Ň&äď:®›ŻC7Ŕď ˝-p?đŤ (ß6„·lcŤZdßş|ôÁQ đžĐ˘ăüÎu@XÄ;{Űlďí±ë6Ď?áÝ?ŕó_}ÂŮÉ1?ţ'˙ÇGGLÎϸ{˙‡Oź‘9łÉ”íť]_Hgk‹É©wÜ+C¦gç ¶F ·†ďA.…`gw—'Źżb82ŤśźŃjŤs)Mc¨ć ´Ö!._€R·şBř!ŮdJ5™RÎfČí„´ ˝?‚÷p7Ĺśv1ÇťO¨îÜ&{ôe·řËĘŘY_Đk›l7‹b8  N‡ťó›Ă>7€ i€]÷ž"ź ď ú D©#qŚX@۶TUĺ&ą¸·çé˦YĘč;ŤW¬W×]ixąÉřD=’qąíýŞđýzgc~ŠuŹË ýÚ Á'`ÁŇÍ㿇‰Ż!˝hµ.o)JWAxŠ!€7a€7ôVÓďFż*}ŰĘ·áu‹łHXA”Ă–‹<.˘AkŚ PÔţ“Đ.émÎĂ­÷ßyČůÉ)wŢg>ź“—9÷>¤ 9;9áţ€¶iŕoăüô”ŢbďÎ’ů˘f÷îmʲäá{ď0źÎPJ±»żĎŁĎ?g0ňđ{ßăŕé3ĘaÉůéňcúÔĹŁCZô ”DŽą—áżýK*!hżxD¶·‡mZňíĐśźˇĘóř1¦nP?˙Ú˙ňźbói|v˝(„óE–#Ą"&NÚoQ¶e‡Dž`]ŚzĐsűżŘźCF™ż’Ę‘‰ oÂĚć>iR|}‰‚Úß!ŤAďM =óMÄŠ•š=ťŁâĘ[X+÷‹m:_Ž2˝ßU¦üU}ĺ:Áh­›ĎíúÖÓŇVÇÄSTˇĎÉĐWHN…„¸OtLwC±ŠÂ\ŢÉď"łßD7Ŕw”~Ó÷^ő~đ; ‘.ý} +:…–¨‹‡ŹÂ‚đ6‹@ÇńÁ!gÇ'|őůoĂšî°Ú"¤äŻţüßűş×g_= .QŔ{ÉC€ľy‘#„`z~N]WČŕío­ĺńo±ł·ĂäücZűĚ…¦Ő´şĄiÚnŃő׉ŕă @e0ť‘iÄ"ëšöô”ę쌽­-ŞĂň­1JJ¨jĐ-b>Ç)éC»ąáÇD©ś˛(™Â:Ö *+:Í\F?şŐK b"SŹţ˝ćOg:2*ţë©d]ĽÎż&‚łó3ň˘\f:Éą.az"Şě.„§EćÔ)Đ«ŚŢŁ>ËL=ý-–:x‘< ŤČ«Îý×ý_rÝ:°áś‹‘NŰ_RTÁ;xöţ2~eŹü­Ţö -Őą®t#|Çčmłó_÷Ľ—Ń« ,qˇ÷‹‘u…ç,M[組łÄħ.a|ÂFDŰ3,c Úřüű{·n±»żO‘ç<}ô÷>ţ!źüü †e ÎOOÉB~üť˝=N_#¤OŹúđ˝ďqđô9y‘űđ˝ĽŔácí’ÉdÂ|6'+J¬Ü~ç}¦“ łłS č¶AHďL8Ţ١Şf4­Ed9­Ö¨§Oąwçµu` őö ĄPG/h›šq9@ Tź}u…kÄŁ/MăsşgHáb>CÓj¤ˇ2¶vďçíôÔgYÄů´Ŕ—[Ž)»y´ôčů„<%uŽ^÷<Ű7Pוw†Ě –¦Dl$Ů 3ˇc8‘٧;ĺš±`•É»uyMÝĹ®Ş _EťOż*°Ôˇ«O›w¬ 2éŔ&ĹČ‘ŢTŕe ˙:Żż‘n€ď˝Ťvţ·^‰Ůo|¬Ţă<ىZ¤ŽaK™ôđżŁ`4 ˇŘŮŮáčŮ3ţń˙ÇŚwwB¬´`0±»żÇŢţ-ž~ő%ű·oQ”C¦çç|řńGĚsÚŞaďö>ß}ŹółSî=xŔb± Č ň˛`v>ĺáűď±ÎŘÚÝăéÓ~řg˙Ójľü›˙‡Q‘ńŐo?çν»äyĆŃá·n˙ŁŁ#î<¸Ď/ţţçĚţá¨ýBŔ;ďĽĂŁżüKΞ>cçÁ}q­ĆÖµ~´kQżţ4D$¸(@ÁΧ*ކ™QŚĆü‡˙ěżAřĹ˙ýŻXśźxgŔĚ!•D7-mČąşËŽ€HVzGą HŕřĄwŰá4UEŰúě€)FŃŮĺ]rÝҵ~DýµgźbY=Ý lž`«ósŠŰyŔ­Ů6´wńî‹éUTřŮÔVZÜ 0XŮĎĘľQévő/#Š@WI°|˝Ť •n€ď]÷‰÷68"^ĹAđŐ)eý^·Ď˛ŚbP†ęx®cřÖ9$­C:ÔČü/€ €ĎŕlÓÖđüÉŢůŕ}~ůłżÇY¦Řż{›ĹlĆÉáű·o!…âł_}‚Ę2ĘÁÇŹľ¤ iššĎ>ů”;wďP×5ç'gä’ápHµă,cyöôÁî~µčÖđůŁĎ±ZóŮŻ>ak{›ů|ĆÉ‹c¬6`t‹®kÎŹŽ!“üň˙ű)Ş(UMőâöüÜkčÖ? sáÇŚrĆ%Âúm UU‘ĺ%˛$xb4­AWŢćďÓĎ‹­-Ćčeí;˘Č!J.ľ§(śőŁÜ§¶á-: çççÁéP$×&ü&jťKü(ŢaUłOŰ…Sí"í}ĺ˘MLuS›W6\ÖđJ®äp—0˙ŤęřeÂAͰ,$¤xA' ¤ÂÜ’śp…Çß”üëmIôó2şľtÝaôëěřŤBx«eđäB łŚŃx ‘I\(^c|ÁĐ}źbżúDç8 Ď|^µ¨™Oç|úżĽů ćV·aU‹E2‚Î+űEÔ9ď=đÜଣžU¨Ň§Őő _x)Ae¨Ńv°mĂńÉ1‡G4‹ÖhŽŹéL\+°8¦çgLĎ'ľjžjNĎÎý¸fo»§óKµ}śśĂű±)$R*ň˘$/ Š13_Q”äy†¤@jE˝X„RĆ­wR ­»`Ž™~˘P+-Â…çÖgěµáĺŃ•“ăăîE;g "8 ĎĎŤ‚¸Í`Cúcg»…efFo+ŠdÓB·ÎH—äס)Ö™%kÂĆ ^•ś7OŮÎ9ň lěĂćťÎßg0«çŻn‡)nl¨ŕčŇBKeý/Ńć§L˙mÖň/Łŕ-§ë|ČÓG_bŤé™»ł)ö™ězÓApěË< éŮ*Y!)GĄ÷BB°eKĄ@eEú€ŻĆ'JzŤË»µyąě ěžÁfR‘…ZBśŚ9ňeňÜ}Ţü"$™‰ŰţµëŚL˛â¬Ĺ_N8Č‹˘>ËÁ€˛(BpoÓYźHJI—Xôú9ɜ؏‘d–19?cggë,ိŃe9 + Š˘@Y^y‘ˇ˛‚,÷YĄ’ŚďŢegww íßÚ“—E|ř!HmţýřC¸děVÎ3ĆqűÖm_B D˙„W`آ‘­ń6ă­q7†—µÖÉ8/»g¸ŻsŽűŇ4B¨ gJŠn ·ďŢÁu€äyÉh´Ĺz5Ŕ•Çů=„ŕ­Ąë>!ŻÜżŠ:¤÷›îăĆ–śë5< Öt«YĚf^ŤNe"(űÎuĺÓţk°¦őKŁ•hͼ´ăŚ×4­íáÎh¨A¨ö«˙íÍÎ) c° ؉P†Ř×9ˇp!ĽN·4mKŰ4^ŞďGĂĎc-Ă်®şg^5!zč=eĽŢł?2eąOT$)+é˘%„a‘™P|ˇ 0BĹŞ}@SŐ(©(ŠÄ:ë5Fç+ ¦}É2oJ¨Ş m4Y®ŔI””ÔMrk1ÖQÄ8ň0úyč·tŢ9qzt±¦7Úşe29)’W&Ó扵tBw‰[ľ ćNŘÚqtxĐ=ű¦vWoseĽÎÁö|Ćdr¶ňnß ă ]}őĺW+Y/»Ćňâčcb AžçĚçóŻu|§čFx‹é:0×Uş.p\ —ěvv™ńł”ŞaˇčŽ Ú«ô ©(|ľ|ٵ?ĹŞÍąnĺŤy\Üçš«%SĎžv5ν§Ľč4¦>“`€e»2đ˘KÝuÎ'ł©« ­u@+ŔXŤŃ>k_>’oí%ŚA˘„Ŕd!Ł_|Ćä×[V ß®™†‹B@ŞůúAë`ţxMÓ´($­ŽţĐjĂb>§­Xăł":@*ąÔ¦÷öµ¦®›0Ć˝ö‹ţD/ňL*ÎÎÎ8=;ńůä…/÷[7MeűĘ@bé©C{R!„ě‘éJöĄˇăPő=™W뿣ŻBĽf•Á[ RúJŞůâ˘ďôęßs6 )نoëuÖők”¨Lőŀ܆3Ó}’'†pMŢŰ›/´Ô…łâu3{¦t#ÜСk—wŔ%–ľDţzM.'Ťąň‡WyČ9Ë m}[ť¶ŕQí¶žy‹$>˘­i;!>ŁĂÇ™÷Ě?š‚Í;^Op$ěeŤîů¬uĐjśňµšşĄ®©(Śe´ßvʦ2…*‡dB„Zďý ě¬Ć†Ě€.0§ť°Äq– IDAT`{˝é \ěp,/ĄBf™/ä"%RĘŃĂѬ(ŽFÓ+˛ !mÝv€0ZôăDď „ډD<5 9Zkž#…ÄJžŐkR»r”Ň’qíĆ7ŮNdĂn§HŻHąxϰşâ˝n™Éw€ţ’#c¸iHR_!Rş!®Â—ś– m/ ˛żŇ˛°IŘÔÎ Q˘dü—°µ{ý5ę*~Dוn€úZtÝěüKLŮőyÚťshój 9.ú°_ďůÂé< o´¦^ĚlŢ3$S!=#·Ň»q‘ݤ°ľMú×yĐ€ Ex†ß;ĺőŽţšĐXÇX|Y]E ŔźmŁŰ›sýXĄĹŐ:dÁâl/, úĚK JŞŔôú'űG˙é?íµúľĹp­ŕĎ˙Ź˙­źă0A Y˘"Ű9 zű8J÷úĹ] É`{‡˙âżţďÂuË÷Š&á,ÖI„„áhĨ,0Ö˛BV^ä Ę!Î92Ą°@U-(Š,Łm Ćúd>22}éŁ p–ş©É¤b4bŚ#+|&Bg ĂŃ{{{!)‡CĘr€Ę˝łRz”DIň\Aí×!€ĄźťŇ.ŇŁnĺú䤋Č%—mbľK—_Ćť_rŹ«Ň•>ˇTňáůE¬ťŢíŹS¦±ÁGB,7ryÖ׸ŹĐćďz |]şnč•é:ŘůW?Č´x‡Ź˛ňZ¨s`‚&(íEyßůF?ěI>mIJmEN9˘”wVóÚľÄ9µ« m«;Ř!¸}÷/Ž}řZŕäŃd ľŤpgçlđ‰s!ڰ?7"iOd¦Čó%U¦Ľ&śçĺhD®d¨„GXk×ç€÷EpeNžçg“óŕŐďJH› „w”‹UĄH|VHĘîŃ˝oGČź·ĎhŞÖ´Xăçڶ,ěÜ·+˝vo´ˇ©*Ś”ăCđt«éźĆhÎÎÎŘßŰgQW'0ZٛÇMV“É”˘,1řyY© ™e^h‘ŢW!` á=,§˘Iţ*łďĎ»¨ÔßÚkL‹z´™}ü˛ëD"Ľ f¸.Tö/eu˙ę>±Q Yą®ÚĎ·]ËżŚn€ş2]·ô˝=ó1żÖ†Řßţúüîâ‚ë{†źţýzÜٵÖZ)dÝ Ă=m`ŢÎx(_k®óŚLlŤŕ|Ĺ@ß.ĐŮ=#cĆšNĎ1Ö84Ŕ ­vůŇťS¤”äĘgٓʧŽQzr@9‚Óüü_˙_¨˛ô¨@€Ě… ÎŽÚ—ö­«XCžeÓŠą Ú¦ćżú˙ˇ$˙úůÉËao»ľĆjćłsţß˙óĄŽ:Ř](Ĺ`0x,u5ǵ5eY`´Ź°Î'jµ!ËĆZ¬1[Crçu•)ćÓm«>Qđ\Áu']Ń nŤ‰nř.ŢÔ§r%=bUŔ¸Ä°ş#Cb3/ëN˘Ptw˙0üUşnčĘtÝ ®Čüśuý"…€ ýYýlđţuż3I>ć˛÷Fwoç¶ÖŇ6 _Q@ĺYZlű{XÚZhćR)śq9ś ÁfRíŮŹ R%?–»lŕ~M Uó˘ĐjMS7 RÖŕ i˝6ÝÔľź˘ŞrHSč˘ý?V2 ą´i=’ŕÂ3IßuPą D°Ă‹ ž8ŔÚĹśóşEfŢL‚Tť¶\ JŠ˘ôŹRT‹J€µş;ĎJ-|ž’¶Öřč‰Ö-ĆšŐ Ž”’“ǡáíů*ď$­Nř#=Ň™ä–+VŠ&.Xgp¬#ţ/eôKÎKÇ:ů÷"3ŔęM×”ůzőáü Ş_L ßp‡ţçZ»4}ţ ˝yHt>4KĎô-|ö×9n€z ]7;ü˙Fćo¬ń€^FpŃ"*Ôąß$/"L.şReľŚo–e€đLHk¤T Ę‘×îăsĎgT Ťsމ¬ Ůż{›rPúňÉ”éŮ9ß{˙]šŞćčŕŔŹ‘ŚÇcfÓĂ­Óó aP‚pŕ:acĽ˝ÍÉ‹L­A.r˛Ly;¶m4­h|x`©óĹěDMŕł­`¬Ćj|/lČ_`±eéaďÎ`đ í;·˛ĘS€Ń+ŇŕQ„đţ¤H™rĎ2ęąAĺ…sÎŰÝcÉ©Ŕů‘őĚއmJ‘ĺ9Á(ĄĎçlŤÇ´ZcŤfkwڕަ®i›ľ_±đ/ÖŁ"Č ÓOÓăÚ0)Öő’,˝Ż ’ąŁc}_×Y·r¨7ç¤mŻ_˝|ź(„ů#žŃ.%ş*um\p ˝·ËF7ÄnĄ‘ţ$ďÓ"hěŰaĘ«¦ëH7Ŕ m¤ë`çOi“˝?BţĆ:¬1Ţ!ÎŃ—†ýşĹ?â˝_K€žçˇ'ľ˙c}¨›5!5¬µŰúqAШŁÇľĄ, ´Ńěěírçţ}¬s<űę1óÉ9Ű»»”Ü~pĄ‹ů‚»÷ďqvr ŔöŢ.“ósśł C¦çöďÜáäĹ ~ýóź3Úóâŕ€Ú”Ń9ňť·k;*WdYîCô„č„”čK`´ˇ™U,ęŚĹ‰ţyuXÂBD‚†ćD@Gdí„OH„5XÄ2#U^{Żަ©Éňś¦i|őAĺÝŠĺ }ˇ)ŚČQ`ęŞFHIŰ6L&˙LĆ`ڎš×,f‹ŕ§ő{•€D°ŃthsÖą–Ë~°Ęß öwsnłßm/1y±¤ý:!WZ…¨^F›„Ś ôšËĹ%`C'lx±)aîÝż=„ŕ‘‰äůWż×Ť¨Á×§·ŃAđF¸ˇ%şŽvţČüă‡íXăż±b±˝ł_Múô»~-b}x•űÇßéß×çh›†Ůąő©a`ŕ¬E/ń› şŐÁŃÍ1ŻÜUÎÂáłçśľ8fgw‡­ť]ÎĎÎŃGG †%ÇGŚĆcłşŐĚs†ĎL§3¶w¶)‡Cvw÷8:8ŕäč¶iÎaB<ˇ°Ţv.$¸+?Ú·e¦PÁ/’łűą‡DX‡qÖ3§ŔÔUśWQp8€ /Śč›Ě"šL…6D9p¦sŽŞ^ ŤeXhšÚçt‰yŮW˛ †ţřMŞ:Ž_őć ęŞfľŁ‚I &,’ŕŢ2âhs§űŰżz^tO—0˘ ‘ݵ«ĚŢĄą“޶Ě&Eň_ę¸ÔŘFÓŔ%Ü<ő©Y{¦ŻIť}!íKz,Ý%–!G4ŔxÇؕ־ƚv•5á:3ý”n€Z˘ë$±†OjÉ'µőcĐ­ ŔrŮ-Â2‰’zµçzÓI=R ĹC‹C„lu> „7]Řxo„žđżv|ůŮg YkźN&8çžťyÓApô›L&ÁÂř5Ök˘gÇ'Ţ‹/9c1ÎńŐŁ/±Îver۶E.*@tů ÚĆ,ň|łgTJe )ýqĄ˛0ź|8ažg¨< Ŕő‹|ôÓLźh" [ kP¦EXĺÓĎ"D4őD-=awA€đ»Ľ€… /† NO^u3HŹ!'€°"hŃtĚÎsZżý˝]Ow.1|»şórfß ËÚüf€uD¤‚Gwń†ůíV«í­4´ö@oHXý^Ł0"(i7şŐ"Ř˙–AřSbă\™ľk7Ŕ ];JŚ×˙ żĂKk şőÝ>ŇËvaUš–ů#şôžß„Ů[ÚPcçúÄy†lűętpÁŻM[ Îř0¶í;·Č‹’˝Ű·Ŕäěś<Ď©ëŠcĽ]?ć1ĐJ!†ʲ$/ĽŻ€µŕ¬e8ŇT5Î9š¦ńą:c@Ú™řnzE|Y±ěçFęhç/ő\]v­ödľ ż¨ż_UUTUŤP‰ěćP~ÎHő‚Öż4EB˘Ą¤/Đ+ńéyÝł®jř©Ě±¤Ý;V­öýCĹk“Ť%h>¦8vÝÜ»qżäAňéˇ 2Ä«“»tsůąW;’n†gí?¨Ő^Ú×›0ŔúÎŃuKß»‰ŃéĎ×ó6ơ#óé^=<îżm)űd;ž)DFCĚüQk}•·oÂŰ´Î:‹ľÓ…ŽęZŚĎŹÚż HŻas4×%Ń9~ţś•M8xú¬»Ż5!uݱ!(%;Í˝Š|®T†”&+ŠĹn,­kBúßĐGŮW04Ć€ńţ ±”jׇŃg 6ř=´m Î;áe*ëxUôŐč5ěřŘyo'|RH¤”eILJ…đ&)(ĘBCÁĎ •)ÂnçĄ/|ń ÓpŽ™ž±łłĺYçhŞ”Ď€¸5ŁŤĆ˙ŚĆhm' „ÁěćRŤŮ ą.1°žaő¬?»\r]wúé!ĺÂ+BĘą•bĺ\±ş/.Ň®{SIĄńú´r ѳщruŁtÂźNĐ ľ^KÝď”n€ß3şŽp˙:ő‹‘µľ¬g« mkBĘV×9žA`Ţaˇđ9䣶lł"j’rÉ$đm_ßH l .\´>gŔî° ¨ů†śĹpČx{›˘,™O&XgŮÚŮöŚ_fÓ)mÓ2 9}qĚG?ţ‹9eY0ťLŔhkD]U4mËöÎM]sçáCţ[Ć;;|˙óřË/ýýŠś­ťmź=g˙ÖmŞj@5_ĺ*TË{řî;, pŽáh‹éŮ9­ią}ďÎ:Tž‘ĺ9'‡‡ŚG_ť.Ä‚đ!‘É{™%0T!|9ŢľĚ *xzFÄ@fáKË~ĚňóKáë-“ç>o€T!BŔ:>?€’ •I¬6ţĘ$‰ěÖy™ D¨Ă-Łę·ş‹zoüŕ¤ç6śç°”Iq#ł_žu=­{É5«ć€îĐTůoăÚxŹ—7«ç8ňĆ{·F—şŽt#üžĐu†űSŠk?ř>kĐÚŇ母ëŇ»BXä~µu]×Čü{üü ÷ő*ăś¶"yócĚ{ot&áíđč4"ó÷ `4Úâá»ďжš‡ďľKĘŇľ8<ŕý|ĚŁß|Ć“G_b´f0(Ť‡8§1Öńô‡8g™śťqëÎ]ź?ăÖí»|ţ鯔%?úĂźřě’Űwď˛űĎŤ·xďű€”Č©bP}0B‰1šňŕűrvzŠs0ŢŮâö˝»¶Ąi[ŢűřCŞEĹl2ĺGřc†eĆáéFeŠÁpČp´…ĘŹ>ű Rd>{BŞ‚™Ây_g»ů˙MeŃŁ Żb pÉß«€›»&.?w ±~<̡n4R‡Lbq)–‘š+ŇjᱸĎßöú®­Wˇŕ;Hoť?öQ)_UJ‰Ö†ÇÇźśRUM=÷ R™çäyĆ ËE(©*şť3­Î‚7:}\¸”Ś·F ‡cň2°ÜćĹđ"›ÝëÜ«šĆę‚ĺĂćň˛¤”´Z#usŢY.Â>.ć6čě"są˙îCľűRdL&çÜçž}ů;{{”Ă’ůdĆí»wAćł»{{>{F]Uěîßâ~Ěäě k}z[Ą|iâÇ_<Â5 mŁi]Ó…řuÎs€čś.óɧ"·Kbř…ÄZĂp0d1›v żmšţĽ†!˙%&Ř! Cľ˛Ëm`Ň÷Ę? éŁ'|őż0ćˇ˙Î9Ś´ś2TOŚŃţ–Ö˘SczüČ[¬•K…Ą˘Óiü-]Ł8©—ľ+bö ř°+hŇ*ĂďTŮK’m¸<†l&C‰ ßTg„şŔ>ľIąŕ.ď_–x^ˇŤM§Ç›ź]¬mD*u©Ľ­2ü· Öşľtťíüľ*źě˙“§Ď8zqBÓj¤ěďíq÷ö=ň<o”´ÓŹ6áúăüŁĂ–u†ÉtĆt6ĺ켦m[¶Ç»¤ËÄ·ał[ÎçŐfĎüÚĄŻˇi5Z·ťťŇ—ş•8ââq€ňŢďÁsŢXÇóÇOp¦ççlŤ·9>›!…äî{śS-ÔU…цÇ|Áb1÷ůî…ä§ńď0­ćö{LOĎqÚĐ8R -%híÍĽ 1$L°ţ¸®šnÔ¸%`pÖˇťO)ěÓ÷‚ŤŽy(ą3Ý{Íżł_ÁIJŻ˝/3O<‡ş „ţŤť,q ”ŕäř$‹ă»Š ąčÚëŽ/Aţ,áÓ. Ű)ÚÎDţÚç¦ŘČ—Thw†źĚăřog }ďe@l˘ ›+R`ťV’MB2FKđ}rî@q© ŕŇۇI°ÜţĆ%έ§©4îßçűď4o_=ÎWşÂG*eZąOtđpo{u=dL*ĹózáÁŰ´ ŁŃૡő}Ęň‚LedYć˙ć˛,چáJ˛k.­5u]cÚ„d0ŕśck{L–IŚ5HˇŘżwŹ˘ČFTU…q–{÷îqđě*ĎĐMCŰjöööiۇŁ,LĎĎ‘Bľ~ÂÝxqxÄpk@•9żú»źsňâ_JŘ''”ŃK-jcAeîśŕ\2®ťÖ+şBle^PÄOĹ Ę‚l0čĆLHŃ_Źđ±ü*řŕ(‹˘Ó#ň㜣,ËŔGB¨éO„~‚i[_7`8 PxL-Cą‡‹ER(ą$ŠrŔ°"¤ Δ›k˛\ůÄGeI–gţ}çYV‡ż*ËÉr…Ěüµ[»;ěěě$â„w8ÜŮŮá5µHІ«‘µ†íń6;;»}Éăô>_űsXî˙+3Ů /½1lmŤŘo#zř22Ć0Ś0VŇiçy®Vą7K«fĹëŠĆÂŤđÖÓudř‘ň\qpxĚçżý’ âäükmăŰ’J2ÜÚ Âłé„Ăç Š;űűTłseAUŐTó9RȩSО mZd¦ĽÓˇÜßăÓ_ü‚©MÖ±łłĂůů9«óôuţňőă “Ů”óÉy¨”řÚÍ]@Žťť]ÎĎ'oşa/¸Ă|ľ`2ťv•_zŤ6ÔˇP”p|EJ­í×ÎKéM×ů¦éFxKé:O,Ą‡/řÍçŹŘŮŢáĂ í[›ÚÓRFÎÚďő}nĺ±v®sŢáË3ý>  gÜŻ>f›M°aŻÓŞ!ÖŽôZ±Ăč–jáúxżŮ埏ˇgŕ3ěŐ€q‘eLÎ'Ľůâ°ńćŔÔv÷öřÍŮŻ°Úb­ĺđŮSŚł<{üśŁŐÚ?Źó$gÇ'”‚f±ŕřč¶mŃA›vřěÖřh'@!ĽżľP«˝ _`göÚ™ Ě?Bá†XěÍÍüĽ7ôfŢÔî^°sÖWE (łŢĚÓü!1M„(€Ä~.¤âřč°C zasęŽÂMG@Ň6‚č|Ň!ţRőţńN«ĎÓŁ ~ÓÚx†G;®Îô#Ţß#/Ý“4ÇÂn®Ą÷]jäÚĄÝbĺ[Űç“&yA«¸/°ą_EöX˝L8áëJÄ˙7ö3˝a*¬G#ľÓ+tŕŠô¶‡Ţo1]§IűŇ4-ő×ÇÖhĚ>üاK ŐáŇ7Őţ»ě¬NčßůEP°/…űÎÉäzĎč=c`˛đ…í~˙Őč"I~3óéčĐ;#ůżÖ90!=/ŃÎ"L´ł{&ëÎCHLęHHÉ{~Ř…Ż•ÖŢůŕ^ç9ĆZŞů‚ďľC]×|ö‹_!Ąäý|ÄxĽÍßýő_sďÁ=Făm´Öělď2ÚŢfďöm?A ´1č¶f{wʧĎhۆ˙ŕ?ůţú/˙Ęg´Ţ” \Ď<ŁÖćByaÝŽGu~~ °„B…^@ ďżü>RG9A‡B,˝;,˝O©8?;Ĺh{qŚzÔţSá#íbú*Wn(âĽNo(p!úçOÎéč™3ë÷XëL_tŔßsă´Ľ¬ŤTh m¬ž~A­ śXÓt IDAT+Ăç”N…˘‹zwŃuĎëgt‘Bâ?¬.ŇKZĽ OßŃPŔŕ†Ţ !řů/~ÍlŢđý÷ľßŮÝ{~LôżÁU~jăKűâÚ3xşí ¤Rţ’Ç:ńďĺç7Q °ŁĐ—^ˇŠĆ$ N‚bÉI11ë鼜Ă9Ëp4F)ĹÎţ>/žĐÔ5ß}—ăŁ#Ś±ÜąçÓÓs¬ulmŹČЎ$Y–a¬e0yç P9ďýŕ#&§g4UĹ­ťmę¶ew{„`2™P†ěííRŐCă[×yč#ÁjK]UŢüˇ˝ŕ Gç !Ť˝ÓXŻÍ÷ʢDe ‹C·Ú×5€éÉó<^K´A€Şć‹YŐÁúý{I‚ 1\¬ż?wÉę”á ´DA&=g™Su—‰ŕĄżthiν„á_ e/]Ű 5ńÎľApXeŔ=u}żWŽ¦ĹŚ{Ůîő2omzś>čTtŔ†GiÖ{żÖ±î“pé°­žű-D ý®čF¸ˇ×¦Čd§łűł_ňý÷?ŕö~ľôˇ¤Ěx3ôź2uđÚşL~C ů[fţëmö‚B´ý»UXF<}ł•×).ޱ N–ebŹ6YźČH†ŚyÖYśµ¨ŔN¤=Ľ*ŕÉW_‘g…Ďřé§^Á ^ÎÖ¬łDÜWî3TuĹÁóçH!ÉŠśů—Ź99™óĂŹµ†žiłÂčĹĘ>AÍG¦ˇ˙hpÝ_ż/F ÄĽń2Aú{Ä}é±®,¬ű%ů5Ó•®ŁČ ĎĚś!/ŠP›ŢűĽ+éĄ1>˛^Çx{›V74UŤ’wŢ{—Ľ(YĚgśź•·oßćřčşniëš˝[·Đ¦e0˛Ď)‡ľúí|đĂŹM¦äąâôäŚŃÖmÓ˘2…Ö%űwî ukÁůŮr@9,AHęĹ%$jśű‚?MĂü|öëO¨µwňł&TăËȲś\e!ŽD™ňˇxĂÁ˛Ě‡>ZŰ—GcbŚfrvÎ|ľŐ ož:¤ş¶–F7Ú¶Ĺ:ÇŃÁAľF|\ţă‰3Łăźé„şŕ˝®0á%´)h˙h„HŘÍŠĐq1Ĺ<ĆôÔ ~"($M$ťZ{UFďwŻpíôŇŤś3aöń˙ ńę&¸Ké˛÷Ň!#qÔoôď\ďťš˘ŕ°Ž"DÇżôśeóÁëzňżm2ˇv‹©X_Wĺą?Ă9Ď …¶)jö'ĺpHąb´…¶e{ź<ËČŠśüäÇ<ţío‘RńţÇŁ2Ĺ‹CŚÖڞ-~ô“źđ«ź˙=Ő˘ö µŐâřčČ—Ő©EY0mަăś»{ŢѶ-[[cóĘg:~$ĘAËöx‹¦®p¸čÉ0(s”’ěÝľ…6–ůlFÓ´)2„6GŰj„T GÚFP ˛˘@Ú9¶†#dĄéS*w%ŘK¦úµşsş©xCß)ŠĚĽiZţâß˙ŚŹ?ü8!:/őŚľg¶‘ą/3j:ŰmoË_ôű E .7'ô(C<·{aâëŹÁë¶#\źë^7-MćËÔVn¨kzű~Źhkpˇ¨OY–TóE°«k>űĹ/ąuçuUóŐgźÓ¶-ăím„<âüä •ehÝňźü#~ú˙Ž“/Č‹c O}Áł'OŽFEÁżţ Łń6ĺÖéŮ)ăťm>ůĹ/Ś†Ô‹uÝPWŃóÓs„đą÷‹RJ2•ŽÉé“É„<Ď ˝Í!Ń­¦ ɧJ*ŠA Â’gJ Ă!m«©ëe,΄đůřI’ŮXkhę‡í2:!Ľ …Ů|B°¨*Ú¶í+ÂŹó/“„ĽŚąÄ‰¶k„2ĎQó—Éy©ŮiMyGŃe˛›jÂĆ— }62ü^.qápš®ąďçAżTgąK„‘d\Ň‘%Áâ‚f_—ş\iŘ-ť~®K»ŢlÇ^ć xťM7Ŕ ˝”ŇĽý§“ ÷wźňŹ~˛ŔAżĐôÚř2^eä«á2I(‘ałî_EROđĺ"˘=2đzϧ_©ťŘµĐël°Ă¶ĄŐš"WřüőăJxÜÚhśµgČ”O<#„ŕäř8đ_şöěř„Ńö6ăť1‹Ĺ‚˛(ůűźţ Ű;;>ż@Us4­FY‡®Ş.[ťuŽŮlĘpËkę·ďß§©ĘrČłÇOČ‹c-eQ˛XĚ@ŰęPÇ/€Óé ‡Ł,JÚĆĺ9Úht«oʆ_Ó6 ÖtŰbŚd>źń˝wßÇZË Ç`4b´5âđůşŃť©”Šá˙ĎŢ{>I’Łi~?î2UÉVŐÝł3»{»s·Ă%yFăŤvĆúhürK#íxv«Őč–ŐĄ++U(řáŕđČČŞl5×"aV‘áîpŕyßçUł eYŃljZŰ1™Śé:KYVĚöŔYOŰ6ÝşÍz˝˘k;¬·Ă’@˙5ŕG> ·6'\ďÇ®Ś{ÝĂ}TĐăřÔë@2˘z¦ĺo]j ¶_6ĆÚ ľ{ĹÎ~†˝m_~ýć|·]~×ň´{Ó\ĘŃ[íľţ]çđýúâ“đ”×ŮţĽ~űvę‡ü÷i7ŔM{mËË ?yö‚O?{Ć}ř“ ˇ…Ľiˇ“˙¶©˙Ë6ü]Ô˙őłý]6' “ĺŚŔ0RŕËß;|˝¤—Ö«ÖP”%Óé”őz…v–ńxőH<­ÄvŢ4-]Ű2šŚ™nf(Ą( Ă­;wďíQŤÇtmKQĽzyLQĽóÁű<üřSĽłĽíťµüŰ˙ń/yúč‘Ôb( ęŐ’·|Ŕj˝ÄhMłiO'T“›UMYTŁ1m]óöXç¸w˙-śë(ĘŠĺůMŰńňésn±w¸Ďâ|ÁŢţç<ŐhĚââśůţÓÉ”(»]×Ňmjöçc´1Ľűŕś·â{oÝÇvćť·yôůCĽ•gŇv-‹óĆôçĽÇ^XgJŃ´ /_S…D!Xq†L8“äŔ7ĽË«´}y‰$í>ŮMŘ}ŽňÁ13—°gatÍ™Ą Š ?ü!H^C¸†@źő±µůę¶ âŃĚuťůň¦Î/˝¸ë]GđÂwďĂ­íčăKLëď;ŕo·ŕ¦íl9đ+Ąxüô%ź=:áÝ·ßg?ĂqzÄŽ9ŐĺçÜ#÷“YÖÎmę?ÎĎČ··+v±˝Ń` ń¦{Ţţţµ)o€’ܛ͆Ńx,&SŕścłYS”%ggçTUE×4Ôu÷’ĺPĺŮ ·ŞßĂţ=©×’G+öŹĚ@H¬TBę^ ŢÓxB Ď üâÁ}čšČ‘?Pc†rĘ•'ĘZ[>„@*eśÝ) ě:Ďn @ćĐëçΛ§Öeußď*L¶©íkNÔŰWŢw0ßwŔßn7ŔM´řă÷ǧüöłcŢ˝˙ťw%)M/Ű䇴©˘ćđÓŕ{˙[üŢkë*[І¦hŞQ±ď~’Fˇ# "CpżŠÖ˙:üZGy ]Lk‹<9Űmäą)%enqř.p±ÔŁ«ĹBęšk)TŤGüęţQĽálęg[Ţyđ€ßýę×Rr×;Ú¦•÷j ZIÂ&ĽC=hĹd:CĂloŹŞŞĐĆ`LÉg„sŽł“WX'TűéËW,—ËPXGJ7«gď=Ż^Ëß^4ĄăĎą}çÇÇŻh)ţ?ů Ô¦áéŁÇ’ź@iŠőb‰¬·x‡TÜóé=ÖYÚ¦ĂňެóĽ:>ćââLŞ6]eŤ2:ĄvVräe$>!ĂN‡ł0mŹv|˛q˘YŇ^é{.yP. đľŹJó2EQp [ŻĚ˙……;î”qr ú’dĐďuM ľ*éŇÎvU§Ůü&ż«rq Ż«É pér^}.%â {˙@@?o7ŔM´\ăUŔŮĹ‚ţÍ#Ţ{ç=¬wRö…2^ ŰzdˇWaqŽĚý„˝N¶?)Űkđń{4'äűĺ}¬ ©Üë_ţ&}ćřKáĹŘdÉS,~Él>ĂT%Z™s,)|µ6r;NŘ×YçířčWżćäŐ1ô§Â{?ů ÇĎź3źĎyüĹěěsz|Âd:¦©[”ŃśĽy*Šaá6E!i‰ÎZL``ś*B,żÇ”%¦xĄĄR`*ý«$–ż( ´çż®m{߸Ä2 (EÁh<˘¨ š¦nčÚ–Éd äã=jDYtťĺěôŰmů €Ŕ÷Ě™ =Oo»C+Mö˙­qćUćt78$€xV!2öśôiŻÓ®r ;Îť•ŁńX’úXË{~Čoţé_88ße%Şma)¬)>+Aý ·×9~ŰŤđ#nŰtţ»1†żţű˙ĆOß˙)­uaaó(ŻńJa=(ç“iÔ¨Á§kµô|ů:Ůţz6 šúl˛˝grŕ˙jŽ€oz~onŮIŁ•÷t]Ëb± éZ´ŇÁ+Ţă•Ç[ŹRŁ ©.g-Övh­Y.ĆŕśgµXđ䋇hĄŃÚ  ZqňüEU˛^Żi›†§_<ĆYKTĽuŰĽ|ń …f2ź3:;Ą©k:Ű%ˇPĂŮÉŁŃHľźžPU¶łtĄˇłŁ eUPP b$+ Jă•Pîăńét JRůş˛¤(¤rYŤśŤA™Ú dăxJż, ´)8?;c2™Ň¶-Jkś÷¬VK’‰J™¤J‚\1&d؉ p™mÎ\mÓďÝc±ě§;–$˘(({ůľ—×Đóč_RüŻŇž·ô°W[´úe ŹsńZŞóŕÔŻŮ˙ËdăÉ©H‘Ľv˙L`HA˙Ó·‘čűč x#üŰ.Ť?˙^ó÷ÍOŢT :gđ^ábţzÖKĘU’Î4XXňĽŃF˙¦lą¶®¶˛z!îsyĎ÷2_ď™ ĎńeűT™b˘RęXďS˘‹öâáźŔ×{śŃh«©ŞJ´úQ (ş¶ĄiZ¬·ÜűfűÜ»ŹŹ~ý[~öç˙†˙úW˙7Gwî°p@Y|úűŹŘ?:˘iŹŽxňčQő·<ŕńÇĚgs¦{3´ŇˇlđůáëĹŠÍzĂťűwyüđ!·ďÝăĺóçÜľsŹ˘Şxůâ{űhmB©á†¦iŘ?<äůÓgÔuÍ­»·îĎŤF¬Wk>űřcFeÁjÝŕl‡R۶¬]ź†Uë´µ I‘ťĂv–ÖtÔ‹u]Óµ5J‹łŁ§Ľň¨X_đ|µľR'U齦Á•zfŻ1¦)ŽSšŞß;áĐ.:Ý;ŹR’ő/fŇśĺ ĐĎqM]±řÍCł»Á>"zk»îšndë{ú÷z{ţWoŰ×ÍűdBKňŞźgßPűľW„ŕGŮ^çŮ®P|ôÉGžĄ,Ú†Đ9PNPŻcľz%ż›AńU)V“H‰ő“ăuŮţú˝]?2IłÚöˇY îźOĘëy.]ÇAđşÍg˙ç_ cJ ąU u[cŰm4…6 8´{y×vŚ'¦MKQJÉÝ®¬0ERžŁ;·CĄ<ĹĎţěOńŔ|oOÂG>üŹbµ\p˙í·Y×kţÝ˙ô—,Kgg…á˙ţßóđăOxëťwyúř1ďýä&Ó'ÇÇÜ÷–‹J´6R@¨,ą}˙·îŢf2›2Ź88:äůÓçĽőÎ;ĽxúŚÉtBU•Ôő†¦nŃZsëömžµĎ°ťŁ(äeI5A(ĺëťg4aŚ Ž‡%U5Âăi6I•ě,›Í Ą ĺhLQU4› ëő¦Źŕ5Ú«Ę>”ľĽYő>©ŁÓµŐ$43!$ŤEĘ>xĺĐ|čÇ{‚~ÄĄx]±Dv˙ŰGÁí–λş*ۺپ‡+ú|ť9ŕŤ-ľ…«úÎwJFIN#÷ÇP׾”j%@¸~4m—ÖżkźŐfĹ«Ó'ĽóÖ;ýX”ekXśÖ‚mÔz…rPjůMG- şhW×§ţ{ ď'qđQËď űżűĎŢ<ĐŰ8Żz.ń;|łžş´č ¨Ř®cłZŃ5’­ÎvťxŇ+EŤ?l‰¦mZ mX\\ČsP)ŕĽEżů—aľ·O×ţžĺrm-Eixůě9Ć~űŻż”şőĄxOśµkŤ–Q”´‹Á9YF… Đt^Qx/ŐßTŻŮ÷ók¸HőÔżÚÚ6,ÜşÚˇpř5w˝Ĺ2\~6đÜ[ÝyŔZGŰ4t]‡&zĹ÷5ďÓÍ…f»ç=M˝Á:ěţŠj4áüěg=gŻNđÎÓY+o%»/î×…ŚxZ­đhP›D“kchî S˘, R[×a;+vv÷2jÚ–fłÁuݬĄUxëpťĹT!:Ŕ+ęőšłł3tQŕ˝§­×¬V5•ň(Ą’`ťŁí:¬óč¶Ą®7cPĆđäáÓPŁ€4~¦íŚzµÓŰţ}ʆ—Ăp QŤ`›Ů”’نJźňK`|t)ĎŢmÂőˇŻKoNçëĎ08×. ăK~nĂďŃ|Č|¸ľóťî»Ŕ~ǵm·$¸\±¶č×­9;ćäkwU—äŁtĐö=äŻq»ókNď\ë˙ˇţv»~ íMvţí¦P|ôéoą{çV(#+&JŹ ţEĽĄĐ­@;č”8Łů°hăH ťI śł_†Ăg2Ä ®bÂj° ĘçŐ…}Ăš‘eČźÍ7ž«{» µőeKů1…a<™âqh]0* ZëčÚ–˛Q”oeł®Ĺ;Çd:e:źSo„ân›†űďqrü<ŷǬw’;@}/7ťO…ÂM59Ä!ΆMۢuÖ1)Ź­Ńa1ě¬Cáię:Ô˛ż(°u]s!~]9lăŃÖ‚‡¦©YŻ7A/ţ®łĐ)6ë Î6:˝k8ŹŃ˛đŰNj",..‚™Yˇ\°÷†0JŻ=»\÷zđ‡l°„M[€óL d—í«zU‘VŽQ+RÎąţ~,yHň9ć^ŞKüfĐß ÚۨÁ2›źĂăvPőW‘ŕ·.ŐvV—»ęű{Ťç˙VÚŽnÓú4PYÎZ©§PHŞ^ŰŮŔFX [¸w’ČZ¬łp7…dßK‹›Čńޡ…-aw˝7Bż.…"Ňŕ™˛gĂŞHĎZë0 śG·–¦ŮPoj´ÇÄŃd‚)5Ţ ‹ó;@Ś6´Ćăɔټ }9 c0FŘŹé|BQŽR2!ç,xŹsc EYb ĂzµĆ9KQ•tzú{ę2/śY¤Ülű\÷UĄŻş‡ô-a.išJÓ ‹dőĽąŻű&îîWľĘöË~ŰĄáGź6eQrŢžcJ1OhŤd2T qŮˆ4ľĽĘL*j.×ëŚ*{µRiúĄ(1O ËŔÄz>˘lÇPŔŘÁöizÍŁgvkú»ěř*Çŕ­ýSÂâá‰wŃâzřcôrIÉ(2čF‡5â’r=|łß.=č×Ě-źÝŰ›˛ú¬'5Ü_Z\Ţľiŕ›¨ň‡l7Ŕ¨]—îĎ›÷žőz‰¦#ćń':ë…ďýÄ­BI[/oŚP„± EZt! K’o„ĹD÷ú€täŰĺŁÔłý]]>8~Ď©˙ţ_uš_ĺ ¸í|US[Ä´ż …) &Ó)FKŁEsű˝ôoŚ‘Ĺ,ĐâŐxĚx<Ć–ş®AIQź˘,0¦Ŕvx´Vtťd´ŢŃÖ5mŰ2OíÍ)ŞŠÎv¬—R^¸m[đ۶lÖkş.ćčóĽ+­hŰLZIBž¦®QJLEş,)Ű ­äüRç@a˝c6™°^®Đ¦Ŕ;K[×’ČG꺦 ¦ L^y´68k0Ącą\2ŹAASoŹ%‰’Ň kăŃĄ.¤@P˛&M0˙Ç ¨çZ¬Ďr¨KĂGëá#F»DÖMy5ŘW w—`1ŕĆçPąĽqŮ~f{“ĎĽ"_đöi3VŕŘg]÷‡Ş+LęRĂó˝ rw'Ů!Ŕ\ľ^ř‰ć™áá˛ç– b_Ł}ßCo€@Ëéţ/;đŚ1üîăć­»wpŢŠ–9Ú‹eA s&ä#÷ÚĄ%˘PPĐ9…őB°Zm 2uőlIK¦Č;.¨˝ßź,}qźžöí/—Ťë›pôéżđ9XUQaJÉŻ Â‚e½njuĆhLYѵ ¦()ŠR4cÍ*ž˘,)« סéŤÁk%ˇr¦CY+ÂA۶Ź»ľ‹ľşWäµ0H&QůZňĆÜ TX+,Íx2¦(ŠäGérď-Îk¬wŘ@ŃkĄP¦@i‰ E%¦­ *« H MYŰbĐűŻ5çgçTŁ ç„iŘŰß§( ş¶Ł®k”ę¨FeSI‰a20ĐŽ IDAT):ŚÝŕě.Ž‘HU)2ď{Ź ×ä5i[4Ą8/é…}¨˘ďbÁÁ0oçńŃî2cŞŢśhĂßΉĎFxv}ˡ7űĚŐlŐľ˝ăźłç]_q@Á«¸×ĺń»Ý. yéŃÔccҰ«{řJÍ:‹sb»nsNLeÎ…\ aԔϮězóů‡ x#|ĎŰ×tŢ{–Ë%†řű@űFäNöUâOÂť©°Ú+ĺńXŚ’?ÚIľëtđ ŤHŠ^g‹C,É’S˙q[¤ţ{›>Yv?•®?ż˙írÂya «&ú›&öםԺPTeEQ”U…1Ea°xÖ›¦1éiŃ&(+˛x)mĐM#yĘmÝ`m‡1’ŃÍy'Yő:ˇÔe±“[Žţ¶“ű)‹Řl6ض ÔľPţZŤM'”Z1?:Äý‹ íöJ‰_€÷Z•ˇŚI€¸äÔ_HY1ňJ€—?·™„ŘúÂÁŻßöÄVŕ:OÓ6†M‹/ea]ŰšşŮ]ď%žńá‘‹ćž• EŚ6śśĽâÁ‡?áŃçźöž˙VěűŢKő<G¨d43%ŻH/”xN%eµĆă9+€W”Ř' +ôÎbŚ,ëő¬eÓ6"xĎh<ĆYËj±ŕüě”q3ał©C:%×…Qâ¨3 _G–J‡˘Vr¬Î·q2™p~qAa¤ JaŰ–¦mYŻ×”Ö˘ŚçƢ¤(K¬łXç( /ʼn´ĽŻ§Ož°·^őš¨÷¬Ö+ÎOĎa{üĄ?wěwě¸#gżs–ŮtÂăG1Ú\C»˙rsŔ{ĎÁţ>gçç2¶rC¬†o:ák›í,ăńO>ţ8řŠĽąąÎňüç޵6řŃ@YT,— ¶3Śn·(LßTĽißŮöud×uřeű4Á)r„Á tđ*öŕähUJ ő§p”€qŠÎ)şč4ćzm?·ÝË™ÂB}‰úďmÂÖÚ >iřZ‹†fL!ąáËĄL¶~Źř- ˙%ÉGů&11?B¸gĽH%>•*ëÍ.P´’¤'Ţ·CkM5*ńέ&lIÓL¸W/oĎťżŔë¨Ë©žI“Nţ:]—6Jü:lKS[ĆMY–ŚF•PőČ"kµC«čµďéĽKš´ÂcťŚoťłĐi۵x s–őjŤ©¬PŐiáő<ţ\‘đŢ˝óIŃŰl6â?P–L&3‰Đb~ăÂvc OŰ´ÉŹ#‚;ô¬@´€%{~d‚Đ”(# :0hŃdó$v!†“ęZŠňe!%ŤťĂÍx6aŻŰOĎß¶-eap@Q€ŘÚŰ®Ĺ{Ďń‹âŚB•–eYa´ˇ¨ÄI˛m[´)Î'8;ÂyOUx­“)¤,JZŰrŃ]i%TĘäÚÄ ©| ËöÄNő€ś­(¸ę¸oě‘XůMŢťĘţĘŢT ŰË4Cúô3Źý+O2®…s¤]TvĚ5ŃyŘ÷‘ŮőűἸúô߉>š¦Ó;Ž˙ýŃ};•řw±Ý?ŇVĂŮóWěÝ{ o]H¨˘ĺÓô‚€h­ˇŞ†wY\â*¦Ľ}ł·d;L ëµ˛tĘ`˝˘óĺ‚c_´Ů‹L€W¤"2˝ý˝§óóâ@9Ý/ËľŢ;šĐGzđ˙úĎmWdŔîÖ/@:˙%­dý"ě}żÍ“ů$řˇ–/¦ćÝ÷ßcqqÄÁÁÎ;ž?ĆóGOř“ź˙ś¦Ys~z&ćŻOÇl6Ś6Ě÷÷جÖ\śź3™MQHm€˘,9{uĘ˝wŢćřůó `LŔ_9çhë Ţ#Îds„űŞśęT!ż÷ŃS÷ŚK¸g)Ů›¤‘äD§€ó‹ Ú¶Ă(ťÎŁ´]Ű`•¦©‘ĐÂ2¸Y×éٶ­Mi’QŠF×4MX‡>dOex%˙tđQ[8_Rzą¦>p@MŻXa—’ŇúŮVîÓ÷ü†ű*@ĹŇŇQdą ô!é•Ď-"oŰ€ż ě_ăS3ě+ę|®f·Dćďđş}`W˘ÓčÎ0ČA\bČeΫ˛[ëřfÚuż«íFř6ď=Ż^3ĎmÄ%ĎůD.Ä“KZ_ŚěWN„6 JÉôň`Ź)'´›rˇµRAĐ _-“>°‘Ö9ęŐ:3„Ód ¬Đ—:ŰRhrcúeÄ{OŰŠ 0OBmú/?éŻ*ôĄ¤zž‘Ď~«˘„öŕ78o¸o9—ĽŁ˛ŞŘljŽnßâÎýű,/.X-—Ľ2“Ů”;÷ď2™ă=¬×+ţě/~ÁGżţ5 ¸˙Î;<üôS~ú§Bk;N_óţŹ˙Čoţő_Y],©F#š¦ćüܱZŻ©ŞŠj4Ç6­±¶ŁiĽµBď‡çâv~%@ě:‡ŇžˇĆ­w¸¶Ł©[Ö«•´0]+¦¤ rÎŃ5 Óů,<-…6™0OŘ?ŘO ş6Z˛:1c˘‚%F©´Öҵ ›M-Ú{ JŇ8ňlŤ»@›gH%Ŕž|Ďh5ď(°gĂ€·>űÎ0@ľ+ăôăź~JáSýÍě—@? đsŹ^ú{—?·ßGÂ]`żőwPÓ[‰7EŞ­ÝwôřĺÚŽŁ/]bź=›Ó' »˛źk´o»~ȲÝ?¦µćńŁGÜż}+Ů—µ ŇT9Ą=x‡‚€t ˇ]JG-$†Ş^ ć‚Púm˙čęÍšĂ;·™îÍxüůçÔë5EUqvzĆŢŢś˙üźţÓé”Ĺůź~ô1]×ňäŃ#ąsď˙í˙ůĄŕN۲^Kq˘®ł­Ĺh™Ć“‰„+vŽőzEÝ9FeIQ),Ë„p=ĄŢĘ˝ÎÎÉł¬Ę‚Ş*QJÂű\YbJˇé«q…s ­ĺtąd˙č0coEi(‚Mż(‹ŔBxl×ŕ|Él2a¶·OŰl¨Űç,ťíhë6¤=†"8ćĹäJŐ¨GĹÎö™ăÂÔăÉŔ_P=GÚtP˛÷hŰbR˘!ůßă|®Ögí m?Fµ třh-¸ú—»ôť$’9$m¨éů±1Wę·hŤŠNÄ‰ą»ş]˝ŐďüĎ;ř÷¦¶u ţ gľnűľţv»~„ÍĂfąÁíâŤM4 śŔ”#|j” aiĆ‹ó‰+ŃţéAkˇu.řE@’µ¬-pŢłX×(o‘ްÁÍx"Ą`ĹO KFWiň9.yQ”e)Éiš&Ä<«@ ·¬Vëťő›Ü˝·ď?ÂB)isM ű…á°‘>w.™ĽęŹ·]Ëł'OP(ĆÓ mÓrqvĘĹŮ9‹‹ śí3ě˝:>F+Íj±`2ťsvr"B“Rśźžńđ“OA_ďxţřIHňăóˇŘ˙“çĽďw޽ҒÁOÉ0Áh-ć{ÄŻClâ.™4…)(Ş’¶íë h­ŃJóüŐ1¦,)‹Šj4N@c q«Şă±]۲ŢČ{źÎfĚfęŇPvëŐZĚAF)cN,J+Öë5¶łĚöć¬Wk¬]§WŁ{µ]Ć„ęCaŁ ž,Ô-F$5>Töţ.;źë´íŇ JŔ?Ôö#‹úŤą=cGëűŇ—ëľÖ;˝^°~đqIJmëzňmŃů'ţ{SřPě:ß›çô.ćďűřŰíFř¶ĹrAUV2_ęH«Ç…MĽn)*ÂÁjńpQ đ˛@(´ ţľ×4˝ĆűŰÖ”EvžÎÜŢ? ·—ćçfó‹ŕ7Ěú7\€z­KţžĎçśź_`­KëŕTšZdD\ď=¶ëX^,0E®G„‚Íz“Ľčcfů.`ꉴ0śźžqqq}ú>xęż”Č>''|öä)Ö¶LçSšşĎ(Xe‰nŞrŚ™JńťÍf#y"BĚ`¤x‹˘ smonÚh@ńUó†ňŃ4SŃtuzîŢ+‰ĚÎx^Áń‹ă1XI¬Sˇµx廤ŤgHĽÄť;ë$ţ\K8äj˝–çU#ÚŔüŕ=C1’CS”ëăăcĆżř. cR2&ć@›>J Ł1e!őŚr*0V±P.‡×:Ä´$¨đ÷¶ýđ RĚí.mß÷ăěuá}9čÇ;Ćě%Ŕ÷ů†$ŃÓK ;ŔőRÇŰ€¨.˙®mxpţŔ®“X Nôkěú ¶×±‹ßĹv#üČš6š®nq1Ó^ŚÉOtmđäO|@‹ŢD„üU`0>„†EÚx-Ő; 5› Ji´Ďď˝éŃsl-¸-:ÇE,YŰSä}ˇ ¸ż,űű{,—«˙>y\0łu[ ń,Q…­2ün](ĺ‹ĺP.WFŤÎ`ptëŃlĆŢ|Źşi¨7kŽîŢćüäŚj<ćěĺ1gççL&cÎNNřŮźýÚşe4sq~Áh4˘UB·Z3ßßcµXňއđčó‡tmËźüüĎůí/Ĺd>C+Íd6áÉŹŤĆh­)G)PŻWx‹óűű´m‡sŽý}Ú`VOĆT#)jÔµ ÷îp~±#9 \Ô|UČÇźL ˇ`±QŚÇSĘQE|ďE!¬Ńd2E#@_0Ł kZОdł©qÖ2ťĎ(LA˝®iş†Q5˘¬Şţ=)É=?*Ł)J‚ů|Nł©1e‘ňSxç¨ĘŠýů Ş,vÖINü`›WéýúÔNB…@ß1[Ŕß WŮ Ú~bv4ź}ĆTČŻĄőwţ.€O׳KcŹ_ł.;×Ăó DőĘĘ5HB׎ľ”éázíűč x#üČZ˝©)‹2iř>‚r^‚8&7éib•hÁHňŠšé@ʞ™@ ˝,ĆđĄ5M·BľĽb\Hf˛(Üă ¤´éKKÍ‚(#™Öęzť&Ýt: NąŠË‹ °ż?˙ĘĎm[přň‚DżżW€ó8ĺÁZRͦałZł\,ůŕ§?ˇk[:kŮ;8ŕĹłgŢ:ââôśőzÍd:ĹÚŽWÇÇ…a<óüéS s‡é|ĆÁÁ!¬W+Žnݢ 9ňďżó6«Ĺ‚˛(„^׊Ů|ÎĹbÁ˝»÷Đĺ8;;ăţý»(ĺyuz”HźĆYž/ ]k©› ^9©` ]§hš–¶±´¶ĄĐ†Ďz%y´_€¶mqŢáĎ.ҸI•Ľi"ۤBˇF72Š‚ b3ť±\­¤”rĐň%KbĂzÓPTžÂ˘ }…˝Ţ@Ţßęßzż9đ÷úˇ”ęŮFi"IđĂQ—9b$sDý]´~ý×ţĄłäW—чQ ß}mĂŁ‡mÇťp9Ââu-ŢsXÎR˝čĐĂ7€Éß÷J€p#üčÚŮé9łů<+ËKźŽH8“M઄pDO˙ƬeD%ô`=Ęąž 0ú®» 9´S”ł`źŹŢĹ}†?Ą4‹Ĺ­űű{ýyĂĽŹă¤S,— ¬µě©¦Ą ŞŞ7÷Uq˙ňHľţÄŽ–Bńʨ|ĐtÓâ`#†âd[F"x`u~Á?ýí߉ŕ4_ĺÖv<úěˇdĺÓŠfSÓÖ Ëĺďţěńc´ŃĽűÁűüîWżˇ4†çŹžpqqĆgě¸Á!4°,Zkž|ń”b6›¦¨Š‡ź~NŚ{Ď•\e4x….„b_ľ·ŕůó§Ô›š˘0<úü!ą˙¶€˛ďř”ÔIőflY»5EHîTUUÚ`tHá¨J—BýkEY8 -Úú¦‘rČŢ;É9Pi”ęBĹŘř› ‰­Âv- ŘfSSoja4‹“ĘŽ¦m$IQŇŐ&ÓŽOž˙0„zŘV=ž%Ěߡ%Ç”ĎůrÍ;Ű?Óě•Ö©DĹíN“±_oQúWŽâđ_Ž&Ä÷‚Ă ©d÷[{Áaו  L ^Łü5(•V˛ěY5ŕ˙ˇV„ŕGŐĽ÷śžž2źďő`’iő4“¤ťŮ-Ó$UŃf#›}p" ßñqAÇďD°®•TŔĆrŚf·ł‰”ŰőE..ÎŘßßOžŕ=˝Ż˛żĄÍf3ĽWśžž°ż¸U4čúĎľI OŽ‹yý‡Ku ]|ö{˛Í¦ÂuEűzÜQŢĆx>c23ťďă˝ăÁ‡r~zĆó'OÓZZŤFtm#”Ɔj<âĺłçTŁŢÁźţüĎ0ÚPV%˙ř×ĂŞiqťíĎĄB–ż(J).."đ™Ŕ^„4ĐQPQJˇ: (¬s8WłĽ8çâüc u[óäáüÉj%Z˛ĎžµďÇ\2)ym[S×% Ągµ6(ŐR·55ĄëÚP'ÁbŠ’1Et]—Ř”<:Aî§·*ý¶†ůM9> ýČŕ—^p(zŔŹRłĎŹbHíď˙řýöö NŁ@©úÄ­]ú/~޶Áŕ‡kÚĹ:\ľ˛ŚŃÉwR;ΕµAfżđ·ö×3¤gOşÝˇ[@.Ľą}źhý/Ón€Q3Fł\ŐÍŹ$KÔú=p'ZPŃ@Dzĺ.Ůĺ}§ˇ‡mÔž ú®Á6 #ŁÚTˇ˘ÝĐFŞ”âââśĂĂĂ`ďo˙®ëxöěÎz:Űá­ăť÷Ţe6›†:äptt‹WŻ^qëÖ-"Ą{UűĂRxůę3d!ňÇ5ô(śĹ*Ť‘9JźŇŠýýC~ţ—żŕâěŚŐjÍloźçOźrëîfó9Ë‹ î˝ý6Öv¬–kŽřüŁŹQĆđÁĎ~ĘŰďľËéń1ŐxŚs–őzÇü3>ýÝÇ´¶€ Ú0*&& őä•Áť@_BÖU(fCđ‘áđř6ćöňů‹ T¸ž=š­¦|ö­(„PJQ”E x#=b6źq~vFÓÔL¦SŚ)` ťíëČ«0ŢSĚ?a¨g!rŃ©1?FĄk#ůaÄ—ŠP9& CQĎ_v<´N;‡Ě6đoŘŁhşvý×·] żóä!šw đ# µCłWé×|ÉĘç—đ•šO˙˝ˇĹçť^@:ÎďŘíĘÓ}ěßw±Ý?Ş&€â•N“ąŮ {l1ą“Pd+ D>”ʇĎ^Îö ńç*& ˛T“Ţt40ĽŘ[W«űűű‰ ĐZńäÉđŠű÷Ţęµ­xôĹc>ţčcţüç?G(kĎ­[Gśžžptt”îőŃ9›ěÔx0Ó™ä”ĎčVOă6:Ńţ ŕűöśł!ő¬\»sp˙­{·+ŁQă~±DAŠUA•âň÷X.­Đş¤ijöö÷9;;e˝ZѶR•Ď[9»Ňg­÷̦sО`ą\Đ6RMŻ,Kö÷%ݰ1Xg1EÁx4B™×¶t¶Ő ŚF#ʢLe}ËŞb<6xFĂjeŘÔ5JÎĎĎiš:Ť˝­‡ŐW'L?DÇ5ůEk#ĺ=E‘’µ¨Ć“ ^ŃäÎu4¶C)Ĺl:Łpťd4EA×¶!„° ŢlL§…a˝ŮH©aßkóÉT3°q÷Q˙1ě/p0Y¨|;y>‹­É•#YĚěw%đç4üŮN™”®S»‡ü¶€]N¦Äçł4 ŞkÔĂăwť'µíT \±[ş€-ÄżJŔčă/ø"‰Ű×¶ ~ŶíGô]Îp#üŔ›s.$M1(]¨§Ž—„-QŰŠĺy}´ű\čęň¤VńżliŘ©­ĹԾѤ­ńĘrŽź&«´błZ±··źŽMţ6ÎŮý,Çw]Ë/ţň/ř×ţ%żřˇµ–étĆÉÉ ‡‡‡Ăëüm»”đu'ö@Ř×]–ŁÉB;Űѡđe‰_.QűřĺRÂĐÂŁVŞw‚ÔFstç6ôÇ?c˛¶MĂŰŢăÉĂ/h›–r4b˝Zr÷­·pÖ˛ŮlÍgśźŃ4k´ŇLgŽnߦ®¦ó9mŰ0™Nůçżű{Ú¦ĄnÚş‘J|V4çl ëkTŤuŰYş® Ąy3XTRáŃu-mSsqvX‚-Ŕ˘÷7‰Ď,±ňô‚A×YÖë­¶ł˝Ł “˛Ŕ)2ŕ]Ěš¨¨ŰmC!)§°MCŰ´¨ÎPë=MSă|)yJ]k5kíPH c/JL†”Ý7Á$ PˇÖĆźHk‡c®ü~»ŹŘQŠÇW—Árëy'z ôŻŇňs:?b~Ţ JM IDATݰ˙íëSY;.ýJÁኮ.ťgkÇÁc _˛ąô ,;Ű·S?äŰk7Ŕ´ĺŔźčnbˇ’WĚî–l—şĎô–lť˛‹´-ĂčĐîvÜNT˘ €1­kY%łä¦GBŔ0ÉĂß{°¶CčŮ^ÖZŢx)q‚uťĺÁűxöô9·ď܆@™ÇăľĘDĽ*©Ç¶GđĺöšsyQ”Š˘d6›aŞ UtÓ)íÁ>ëW'âO]–!Ý!(śPqńŇ çăôĹ+¦{3¬u|đ“řäwńô‹/ŤÇÜľwŹ“—ŻčšŽőz%ą÷uÁzą`<žĐ¶ ÖZîÜżĎjµäţ˙+˙ř7‹ŃšĹĹ9ËĹE ÚŁ X"Äă^Ól<±`x­Ńjł% É%·ťĺäŐIć;A^"$Ó“Š ý ÂřcZŞę@(IBŁ”"L Šj4Â:© h Cg;qx,JŠ˘Ä{Ź) %üeYR•%Ú cŤÇX×J®ÂBˇ‡Ó Ξޟ9ż€¶ĎŠ‘.—FÇŔ pkî$L˙°Ź řó »rfô~®é§űč몼HPĽŃmU~ ‹ł°‡xÜÖ¦´ýJÁaűú/ˇ?WK ąx”qp…ě›iů:×\řîl7Ŕ´ĺes{ë·_˛}o/h™“+*Ö’.TĹťăOëCďQiÓČ22Ňň˛p{§‚ó’Ł(tŢł3‰ČóâCŚ~÷Ţł°Çgź>äî˝»xďŹÇ4MMYV_úů}“>űâś§é:V«Ąwűwi .+F÷îáöçtOž˘¦3ôzm"ĽaĄ¤äíb˝fµ\Š“ăŚĆVËç\ś]ж ËŐo«Ő Ťb<ťrqqÎf˝a2óŮÇŁŤáŻţĎ˙‹¦i¨ŞŠu˝4¦łBĽů5€†;wďđâŮs¬”ú“±b.]_x^Z4éĎžq˙­·‰·Ii|)P5´Ő&A@ Ř;ď0Ú çlt´mKÓÔˇ>„â\‚‘AĄvAŰuÉÁŃY‡µ 0Ö„p3‡sŠ®“Ü8źC éF.eeŞăĽŃaľü .iäqâhđ—łĹ%çľlĚ˝řwʤ™Zż]čý}úÔĂô>(ňb[ Éólýkú ďôÁ=Ĺuěňšµ»ĺď'Y/w›ŤŹ«ÚuB{łĺ÷§Ý?ŔvHĹÄ:b?ŹĄtă1Ńľ¬úď0XŚŃ*‹c‹~¦íEÔWa[´–E0Ä µ4s1&âQŘ®Ł0eşŰőöţ>ž_ĄëíMň›sž˘ľťS!IŚĄŞ®˛ľyb’|†2ŇuµR´ÖÂĂ/ţâá™jL9‚ű÷)<`ý»ßăOÎÄ©.°+’EŢz÷F“)ͦćŕö!ëĺŠélFY–ÔMĂÉËcöö÷8Ľ}‹łW'üîWżb:Űăťďrxű6÷˙ýWîÜżÇt6cS×Üąs—ĹâśŮţľ8•)ÍůŮ)xE×uŢ:âńʍ×+Ţy˙}6› §'§DFďĽ$xŠwňĘźžśĐ¶˝ú—ÄG Ď6IöN“+€Bě×:.ćBë{ëđˇp‘) Î"ĺ‚‹‚¶mÇdR x«XOŚ)±ÖѵMŰ'˙!hďmŰAUÎąŮl$1P4ť%ą%Č”3r‹˝0ę¤AčÉnîňřŠc2făĽÜ2ŕ7*挾¬Mç5˛„ 9|ë$ ĽôG…ÁIwp—nig‘;ń…±łµ‹ÚÚ5ş( ŠľĘďÝ z‡Űd‰'ńĂKßŮĎ7üÝi7Ŕ¨]w@FJĽŻR–”8z­:›_*¨&RĽ=áM‡Ĺ$´č¸«uďŃ ę3´¦Ds„Ä®‹łß6ťŻY÷ě4ŕS1™ř<śë˝ç/?‡oyb÷×ŰĄĂ˙Ţ;ěbş˙j őŁÇŚŢ{4Řósô­#pŽńO˙Ĺ?ü#PÂxD¨­‹ÓŠĺbIYUX۲ĽXpqv@Ó´¬W+”‚Ó“‹›Ő礄nÓ4śĽ|Éx:aq±`<ťŇ6-›zÍéÉ)eY±Ůl$´MĆXk™L&XkY^,)JĂr± %€Á?0ťĽb]o¸8żH°ÚZmĂH )§e Ä";ý  0Zh>°¶KX IöiEˇ lgѡXÂ'ç9BaăĹ(ĺńNI•Ë8”Ă@K /3:GŠdÁ˛dBá@0Wřě^˘ć»vÄdAžş“ŹZxĚqINČö fšd®É؆TkPeťl›·¶Ń9ţ®3Ü—Úĺđ¦‡\şŘЇÚúůŇ1žPurH»_­¶űţ6bŽI¤ Ő× [÷ňCüív#üÚ€"|Í ŤÍT6ňs ~ř=č/řçyö‡ÇÄebř J…ŽšE†>‡HŚđÁVę1ZK¶6E7iBęŇuôÔ/(Ą(Ś‘â¸UUĹ ń‹÷ţ[”äwŻFE%öć˛2ş , J<ş,Чg;·¨î݆µÔĄ/ŹĹŔ/Jf?űíéĺxÂh4‚Ŕäśż:eyqş`6yu*KśĄ›•BqŕÓZ±Ů¬ů죏đ^lâŢ{>˙čcĽRś˝:¦Ťxúä Z‰­}<So6lÖ~űË_ł^­(«żüÇf4SŚ*ÉáďĹ?ďŃFá­Ç†ÄSłůŕO&LgsÉ UYPZkfł)e5&ŮĐ•%ŮýYů‚VŢuŰłŽvwĹIs"ˇ†a€®×›á;V ­şô}4§cUHí›ňä«čo"‚÷PŽFڧ“|H®§(„u¨F…)%ëˇŇhS„Ś€‰˘(äúŚćđđůţ~3ńť^ŤIo§jđ‘:Vŕ¬co6çđŕcŠÝŠů®ľ®řs»y<ÎyCt@~á›zc7WžĐZË|6e˙ŁňŘÄ"RîÎYŞŃXrŤ ¦ŁĘô:ľ˙GÔn€ďyű2 –ô’pö‰vz3@Dţ[_§g dqŚš|X¤Sf5¨PˇjcF<‰Ŕ¬MEC»^1Qć{s‹Óét‡Ŕ‘ )qÎ;)n<暦aooďŇşůíIň»űíÚ&xéwPYçˇ_‚uBőᨱ€ˇ?;Ĺ[U!ů6 ¶kp+/^öś1Ľ÷łhę:Ĺęßş{‡ă/ĐJ˛őíŕśĺîý{<{ú”ńxĚ'żůú‹Ëzą¦Źřü“OxđálVkf{{ch›–»÷ď±ŢlĐ tQđä‹ÇÜľ{'Ů:­sâ30qňň‹‹sţý˙&Ž„‹Í’§O…w-őfĂzµR`Ű–.„*®Vk*››•bś~č)ŮŽŠ&8Ţ4ÓŮ”őr…2ŃwE/ţ^xČJÂĄÄT˙wÚĆxŰ4l6›TsB© ¸ł´M ĄB9…ÖóMÄqö×Ţa˝ăôôë{JÁ+ĹáÁggg;FŃuóę}`­c±\rvvŽ)ĚîwŤáŚĹzÝţ©?qvvF ŰĽt9»XŠk6ë,Ëő’óIňő‡Ë‰lgiÚ5¶“śŢyl!Ń*o¦ľ~ŰN%ţ]l7Ŕ÷´}Ug´AňČCŤxÍbkŽßĺsčá:ÔĘ#(÷'°V M·J pô÷!ű'&5›4·nňë_ţŽźţń‡)Ó_.ôö[1śťťsűömb;Č3đÍ´íPŔkµřl˘P–%ăÉ]ŠbÄŘyôŢShĎŘ Ł)Š’ÎÚžVO¦ÎNÉßDeűő~ Űŕź„Ž ¨ÓÂčT!S§EŠ‹Ť ¸„äBqĽĆ99ç$čmÔÄy–Ůđw•˙Řř3Š‹Ţt—Rs‡9®ăµĄ}ó~ŐĄ?‡oo$˛˙rßÁ4—2GĎ{ qéV}¸E#çşŇą0ď ÎÓ¸¦ąţ] ¤żűś_˘]ÇAđ»Ún€ďqű˛KśEC‰álmł=¨_MýçSp97˙ ó>Ś1)–ZÂ7ÖFÇx<ˇ®7ŚFc¬ířđŹđéÇůÉOßÇ:Űű'$_9÷r±dľ7O6˙¶mú‚1\6k~•¶-Ń%É>¬Ő¦0Ś'ŠŞS`^˝brű]T´Ţ2~ű-tۡŠÚ_×LoQŤ&xżĆ%/ź=E›çOźR'ÇŻčśĂ;‹µŽBk&óźţţ÷ÔőFĘŮę‚'żŔ”UQQMF<úě!Óů ď=ă±ä'X,e…2Šć¤fµXŇÔ Ő¨¤ŤCč]…ÂsqqÁt6á_ţîď©›–˛,™Íć¬7śµâŤŻ˘fN´É80¦čía,ú„hcPÎíł+ĽŽă§7OĄQ ?e„ĹĽÚ`/ÎÖ×ă;\[}ń0^g$"(«>c_ćüvÉÁtŰ®­T–$0źçýsÉ…Š|‹Žâ„—ÜÉI?QóY9đ«­S @żíŰY;hëĐKť Ŕ^ şî°}żĐŠŰŢämż}»Żî«˘ţUáÁĂuô»ßn€Só>¤@Ťŕ­PĂđ3: ęLÚî?2î“6\¬"`EAŰ6éÉř'ˇ\ÉÓYI,÷ůĹ9ŁńXě®eÉ»Ţć·żú=?ýŮO(*ťĹ(†çĎ_pëÖ!eĘú§8??çÎť;ÄĚ{_íq %úŻ4©óCśQbhZËf˝F·ň ŠÉÍ'źRÜş…šŚ±›†őo~7ż^b­gd ›ĺ‚®łxçčĽeom4«ĺłWâ¬ĹyÇ|>ăĺł—LnńüÉSööö)‹’NµÂŔprĘÓµZkl+YňF“1eYrxűVZ(?üś{÷ďóěÉS¬µč®CSmŠę(«`X­VĚ÷öQzAŰvtÎĄĺ;>Ź$˛„iŞčŢÉ”DÁĂpź(<öďf8–cČjŽÖJ…ßŐđťć‚¬GR 'HĎŞË‘źK…ń›®źŢă? ËľDPjO»ÇL¶e{'§RҡŘ^üŰÂC| Y:ëd€ÔŻýĽżţ¦űŰÚýN°ĎŻí5 ž¦ˇşúđ×5ĹW^.]Ę÷đ·ŰŤđ#j.0}@Ôd#MÖkř9¸#âöś ČH f¶]Ŕ>Ш š¦c21ˇßŕ7 věÍ÷8?;KĹ€FŁŠ÷?üśĎ>yH×ZĐŠ˘P­1EÁ{sč~Ąŕôô„žĺPľW v´o»Üç¶îáĺ˝0NˇçsţöŢëŰ’$;ďűEDšc®/ďŰTűéé`H€!łô˘…µ¤Ąý+zŃô µ¨%‰¤h K % áf@.¸™öľË›[·ęšsŹËĚĐCŚ<÷Vˇ«§{¦MĹLőąÇećÉŚŚoďoďým3™ˇĄ`2Ú‡şĆA˝7„îvşaÚď»Ä6@›†SgĎĂáÇV.2źĎŮŮľÇŇŇ2R z˝AĚţ ôn߼őÇB2ÚÝăÜĹ'ŘŢÚB (Š‚•ő5ćS×:·šĎ©ç5Ö4ěíě‘ÉśĄ•%®]ąJQ–NG:ŘięÝÔlnŢEH‹Ö–ŞŞ°1Ă_D0"ôp×[Ä˙…¸»ĄÍm=ë¶g_Ř\k¤':5"ă+şů-ŘcŰ\Ňţ-<Ń“€+ë[T•ôeň‹|EˇÇ׿‚nFĂ÷m üAĽ‡ŹüP2Dâ ’0.ÁkŽôľHő…Rô ˙A×ô­Cu÷#‚-ĺ 8ôKí±ÇsšfÄ‘Jů~ú Ă~řă‘đ%ÖzýMÓ¤R˙Ézz߬˙öďôµł çĄ\q}ż_†#sۉLźe0˛łłă˛Š…“y=}î$J*ďů‡îtÚ[ănuŘŮ٦ßďÇD-÷»®]]8?l ĎŐsËd±TyFi@Ż,±H—ţĐÔ0\BďďÓL§čyŤĹŐ>iŻyo´vR»®]ľÂń“'č÷úĽýĆ †Cćł)›7nRôJĘ^ʱO˘Ľqő*këëô‡C&ă ¸{÷·nÝbiydyÎŐKWXY_)OfŁ‘¤ÔMÍők×ĐÚ%öN¸©™M§Üşy“şš:ČX Ćض\\´Iu`c6ëÁ<ŕRüŻ˙|–ĺś2™žţ—˘ !¸yᾥâs€ Šučî0Ç­hí$¦ďáţ{L‰öŢ 5z‚V>6:ÜţÉď7D €´Ţxäü5­iOFgWÉghŻGĚá±a“‹q›ěË?Źo'€/h·ť"öI€4¦ţh+źl+Ťş#ÝhT!imťpŤ˘‘×Ůi‹Î@úúm<2ľTC°şÔ°´˛ÂÝ;›?uš×®‘•%EY˛u{ĄĆ ¦ł9{;;®ÔSwA^„’9iQYćůB9žl˝j©dň<üNgHÔZ{o\"ő.}6ľLĽ:żÍ´\0HôĆíJáă˙íçŹţ3ČřÜÍ•CWą6? Ś'ľ*I„ł'{Ôs;;şCtóŕčţ€|*}?ŮG  Ç{X:f˝ëí'`Üq­I2:\e ż/ůw(ŕĎ~ě“c?*Đ6ÖZßľÜP¸…Ł’7¤Jľ# Ćpl˛ő´*}üÇŘĹĎâxd|ÉĆ`ĐŁŞç8+;Äą[ę~ńyűZJ˙·mM[u·%†ďz˝ăń~ôŇfł)Á°k)‹Ö{ĂZŠ˘GŻ×ÇZKS×ĚçsĎ@H†Ă!R)ç0™Vă ]ÜüŁTlŢşĺ>ű ڇ˛ě~ř…Qy‘ÓôQYNÓ4TU…Ń °&5Ľü÷„‡Ę®]ąĚł/ľČí›·ŚGlÝşĹÚĆ“ÉŃî[·çÔUĹt:ĺČ±ŁŽ)h·=kŮŤĐĆ dĆÖť-úý’ĆjF»#¦ă1BJćóŠj^qíĘúý>›·osüÄq×Hhě¶[7oş;eÖ;­JÄu\w@AЧ?D%?ť×äJa…tMxŠśVÇ•Ö •”Ý Áצ îÁ´(JŔ¶" –ÖRąc”Ęł>Îë÷­¤ôá%׊ąSĎO{OŘäQ©â?$„ĎK îzvÁýŕH Ť~„˛Ýn!~*Ě.U‘ Éđ–ő»]ظĆ6ll¬sęäÖÖVö‡¨ÜI.×uÍŢî.|x ­u—ąé$vs85Žş`źwř=Á–0°˛ĽĚĆĆ'Ośt×d&]Ó¦˘ /Kfł—.}Ř23Ń419ópyĺ||_˛aŚ!S %ĄÓIçA%i‰`,łŠá–úw˘A­Š_Ë*hĚfsB2âl6Ł×ëµÖłmĄ:­n¬‹ˇçeI)ĘÄË´)㸿]˘»Ą¸ss“¦Ö<ě­xX‚ŕĂťđôŘ,qˇ‚,+J9PvGLkÓ˛§–~vRąnžĎfĽţ˝ďąţöJ˛˛¶ÎööeŚ6\ţŕCŞŞŠImŁÝ=ŚöR°ž®v i0ťLQR`LĂţhŚ®›hTŐ>k-Ť1,--1ÚÝŁ×ďTěíî°Ľ˛Ś.ą9â“U–G@‘µ^ßX§ijźźáš -- ĐƲ´´DŮsŐxńź<ϓ޾ cĽĆČ—k´¦ČK˛Üé´˘?©aë%]7A)ť1člź ę k,MÓ0›W4şAč`,‡k’\רoŕ_K5ü~[Lnkűg;Dg"đúĂFxô´­íľż°ĚŘ"đ§Ţ{âĄ[@Á·^ţ&ëk둍^ŘÉmËËË\xě1nßľÍwţä»2wsśQ•ś¦p ©1ë&ZrÚ3@ÓÔ|ë›ßâÂ… ”Eéîokc»gc ¦qóă?ľóŇ>îW%ôYüĹńČř’ m KK}ę¦vžPŇü'<µż"z m7ľö{éß‘µîüÝ.šEQĐ4®Ż<€1šétJżß?Pn'¬qŔ‡K ÁŻ]îXÓ}‡ý#ĺÎÍ-fÓąď ÷ŕńQ?ęč.rţ€qÇUŐ “ýH…1 Fă@t…ńž’6Î+r-”5Ę .<őăÉűkżŔ{o˝Ĺŧźć÷ţŐďpäŘqÖŹˇôąúÁ‡?uc,˝~Źť»ŰXJ)Nž>Ĺ˝;[dEαŁÇ1f“)ŞČč÷̦3ŞjĆÚÚ:ďľó6k\»|•'.^dmcťëW®±¶±ţúęF3™L9~â8W.]a<qń™g8{ák«ěmďńö›oqěČ:÷vFäeN^”ôúĄź—’˛W"…tÍ,h ř•)ô ăĂ)*ËЦ!/r2•!ełđť)"@ ňĚm_J‰6Ć•5z‘)B94šĎ*ަAÄČ‘ĎĂóą·Ö{É#¸C¨á ŐßŮ@üłăχ{ěP`O>Ü鿍tşi‹ŔľŇ‡–żö?IQöbź Â/Ąî^yâÉ'ŮŮÝĺ­·ßA©6(`ˇ›c)-€ôÇ-¬;Nť:IĐG P!„c Fř†fV"sÁ‡—/ŃăsRF1<µé“Źl|ÚUB?ĘńČř’ ś8~ś779qěĐŞý´Ô~,$V%@޲éß~Ů‹¬‚]řŽŰÎp8`<·T«ŃŚÇcúýA‡m°Č¶y‰waŃňdiŚűĂÍë›N¦Őz€}Ŕřô)<áŤŔŞŞÁŠĘŃźÖµ­µţD ,xđO˝Îř+M-ÜgfÓ §Ďžĺöőë,-/±˝}—ă§N#Ądwg›skkśEQĐë•~Ă®ä,ŇçÖ™á`ÚµÔúľ©ŁÝ÷îíHőĄhÝţSĄđDçˇ6´%u §6ţ7âc”FtľYŤÄ "ý ·n\ąĘŤk×c‰ őĄÂş‰×Ż^ëúXˇľÍ„Vµ0č ™b´˝CŢ+ą·˝ó.ŞůÜo[bŃ\şôÖZŢ|íő¨t÷Ągşa,躢n.ř!7®Ý ËÚX¤°ÜÜÜrÝ g3j6CHĺΑôÇ™4 qz)•yĺčh­5eY2źWYµ {Të•1@Ę$1äľÖĐ’BĆı˙Źž¸áz„ä¶äűK“űČŠC@/÷Ä> ĺ}‰őűcĆ[ú~×0Yýřü÷ĹzüC€ot¬Ż­sęä zńl‰F€ Š@xécA&%ËĎţőżÎ˙ő›˙ś˛,wpřč–âKVÖV8yâ“ŮůƸöÓB DÎ_|ď{±úçŔ6Ţ˙ŹâÁ÷zĐř˘ţâxd| GÓ4”ľĚ«iL˘ö€ş ´1üEę?,‚@X6Ż IDAT]ú=$¶ßˇłÍĹpŔp8d­ Ö[čŐ|Kˢ dX„ă¬~űŁ {»űüDk0é mLlÔľ—>~rcq{­×ZÂÚČJ$á éC&9Ţřrë˝ŰŽÄĹČWÖ×ŘÚܤ±ÍAż¦1fAN^€Ő6%śÖ&×dB€’dyFžĺ>ÖębäX‹*»»#„ôűýÖ#łîý,ś¨uCÓ¸ßÜÔ Óé$ĽÖ Óń ¤p-{U1!¨“ËČŹŕš$÷ ©iŐ -ř^ ŇHŚôŕ`Fđ€-Śy—¤¨;Ű ˝Úý“ÔʼnXî!Ů´ťË‚–Ičx»çEZć˛H_ńčôŃâż°÷8!€ö⦙ýí×ŰŮĐÖú üţź6š§ź~Ęĺ**55‚ڏNŔË…LÚä_×őPłŇëńäązíęöŞs8mýgň‘V3@kĂ‹/Ľ€1–Le(%cNŠ-4ÉíŰ›loď©DŁ0l»c<=ü2ŽGŔ—pXk9}ę$›wîpdăhx5.K» =ťÎß‚–ú_ ',&:ŁÁzOu82›Í™ĎćÎZ÷;žN§ŚÇc”’ERY¤!ÁÇ…Ť¦i泊Ůlžd|[ß?Ü)×®Ő¤^Öݢ‹3JŚ6h©#hDę_´çoP…Śç,dš¦ayy…»·7“gŞZG¤=S˝ŐnacŻôŘU5GHI­„µÔMíŞ¨Śeg—¦Ş]˘y†Áxˇ"´qeXÂ%6MCÓ4h­Óc«Ť+‰łÂ‡2:§ĘŤÄkŤ˛oąg0DÚݰs¬óÓf}ÇöÔx€đěR çٞ`‡v ű"1¢JŰ1Đ”˙[Ä{Ă—:ş"Ě€öąH÷Á`č‚f÷öúü=đN„ŕ÷qĚŇ©S§\n„—yV*Ł( îŢ˝K]7 =Ž9†1:2+*Sd&CÁO}űŰü˙ó}׾:˝¦!ţ/î·;śzčÓźöŠ’%™ď$i„ď-!ß{ĺ˛\Ĺďa-Ň:Ł3#…ĆHö»pj?‰±GôYÖxd|IDZŁ\şrŤăÇŽűŚóĹX÷´ä/Ľż Š±Hý/V t7-×+Šś,SL&Sźhă÷­µĚf3´ÁIčZÓb€ż­µľ|Ë{ÖÖwŮ룄ŻxřďÇż±W€#¸EĘzz5&ů‘H,["Ť(ćîvťšŕ˝­»ŘHňşď%XăĂ׼Üręp…ŃZ¬5Ě«»g™Mg. ßW4MMUWŚÇ“¸[c©UC¦üy›”c,u]Q׾÷€6Xkbř&„1b¸V´s.üSŇË&E1ťvŽ…3ťŕ @Z´%aÁOăó ďů[H€ÜÚĐŚÂÜwɧÉIŤű 3÷[POŢHŤ›\Çäŕe0 Ra˘(Éö»Ţďzý1đ@.€ŢŕY`Oś8áć—RH©ČłŚ×^Ť7Ţ|ÓW¸ůźg9/żü2_˙Ú×е&S Łś°˛ÚçÜٳܾ˝é1Ăő–ńÜŢy­+ż|é«_uŔź)bR •;á,Ł "|˙ŐWśZeŰŚ¤s~D0…HŇ,Ň{âÓýŚ4qř‡=_˘‘–ćéF3ô1ÚI„¶Ő‡Ĺđ»@~PíŻ5 ©·ßÖKę†ZđvC2¨kM5źcLEč`mëř€ ‰=ƶ¬ń†@ž÷PJEŔZ}PC€Źp‹âCž˘ëmE«„‡°¨ŕq~qaŇĄĹRĎköę]b3ť¶ÇĆ´[¶ČbľGŔÄ€‰”˝f>Ż0ƸLü˛Ä G×Ď&S–W–É2Ż»ŕJJĺB€¶N,¦®jfł)U]aµ/×2]O[¤Ş†Ńj ŕ.ÉŠc şŃţ5‘nÚîő-Núyrăű~WřĎŤpLA+ěš&‘|.ÉńGŁF„ŁMŘřeK÷h î€{׳ď€]đ¶t˝~ O{(λż!|Fşů}ôčBĽżČ ~˙~źÍ;wڻĸů‹żüK>řđ˙ůßű{dYîCoîý—ľúU~ç_˙.ů!†Ë˘áásQüoiŞ†Ż˝ô2 B#¬+uͤár¦“ o˝ýv§ëç_=>Y—˙ó^ ř@9ŠGă‹5b\ÓÓäO=ů8—®^F©Ă”ýî䢳X¶ž[k´ű9ř<‡żC¬ŰPĘÉÍ.--S–^ůOHŚxlëʤ˘( †Ă=›6ásĐ»Ź0Úă˛%ŻŹ}cű俀ľ2S¨"÷µÔ%yYPä™{, Š,'/rTuüőXâ c —ě'‚±`‚JšŁÉ¶Í˘Ç1(Ćj Ö¶u5ŐŃŁ­ ŇĂR¸ B)ß‹!CfyQRöúôú}О$+r§1ˇ”7x4Vűm[ŤŽŕ»Űd-Nđ“ý §Nź!dß#Yŕ!ó_7ŤKŔĂ+ővi…˛h°FÓĂp8`8x*ݞg5MŁ‘JÓ6©’X[·€-Űdşv!ůţÄJŃţĚDň7Ľnýo%~=˝ľ"ÎŐhlв1t÷ŚöśwŚ”t»śL‹äşt@,ůĽXx)Rţ©´ř˝ÎGIâ,íßáăŃVp&Ť1.'Gů¶ĐůĘ÷P™:|ű~ÓBŔööúçÎ×_z9† ‚çź{–7ß~‹I˝üŔqu_PUs~ü[ßśá´?\•I0./_ąĚÖ˝»®*ŕŔ1…p‰ě.HÖvĎűCŽ/b)ŕ#ŕ :°I);ŕ–c O>q+×®qîĚ Lę‡Sű ‹gůE!.w_ň×R˙B€5!MËg›“xîŽkŽŢk0Rś˙äĽÖĐAĐ}GËę¬×·Á8xŽÂyhű'}c·’oÖ€µ–ŤŁGY][Ą( ňĽuý*˸^şnŽ'Ěë9şŃÝ8‚Ŕ±#ÓéaC5Awť#ú·á‡ú^řp€—˘Éu±ŕ-•ŻóÎ(ű%R)KK,Ż,c„ ;覉*pÖc—ng‹ rĂĆ]!ˇÜo;vüĂÁĐesKŐ–Ó§Ď"”@ýŘŹ#|®†Sxs¬Eđ˛ăjňŤŃhăY ă(iMm4şöďái}©0˛ŁG°wďyĹŕ•‹ĂŐˇEPđďÝŁĐ|FrŽCŐ¦L+ ş–J×H‰ű[°I^”˙iŘÎŁHůR÷ß> #.lĘ߇íQµ d–1íů˛Ü’#ě[ \źĹźýůźóÂsĎ1čőceĹsĎ=Ë«ŻżF–ç±\0$äz—Y8vô(gNźa6›9и0ĄĘĘ—~ţŃwż{˙˛żĂN› ×ýŁ}ĹťŠ–ĽźőyŹ €/Ř8l˛Ţoâ !ôűLg3”RÎłŽq äáď´ä/Ąř»űi_ť¶MÚ#ą±Úăö[‰ű‰l€±-Ć®MâÝ 61–(|óʰŔůG‚řŃZňř°NĘWkMĄ¤ ·Öb´ˇŞçßţ0śˇĺŐfł9ÖŻ}ŕżă~˝óXýoÁ/Ľţ=$6ôS«~’)żč”ÖuEŻßG©Ü%gß’XJdž‘ éšńeuÖç„ëoŤ%ä k‘Ö`´—"6kF7dyA&2PDj>”|!„7Lü\ŚMB=ż / 泍qaŽZjŁźĄű˝IŢńôÝ"”äDŹŢůÎ&$ňY·żăýkCâń{ˇ 0ŘÎďűaŤÎzn¬C–ŕ:ÇY"¤ő]ÝŃ;•:Ľg¬# _šĄ­pň6ÁĂ `•»÷ťSé>ŘĆĄiq"&˝°ěîl» H¤¨°Ö kŤŃÚ—fA%bš¦AŤµ!.Ž#©ÇÍ źŘĹ»Ŕ$Ń&í Ź¨)čYkťˇa=·bMĚÚ—Öb•"Ď™”R2î÷Č•důôY”1áOáĽv§Sŕ ‚FkŞĘ•-Vşˇ®kš¦ˇn,>Lf ÖÇĂřHkiôö÷¸wZ¦%š˘‰¶€šá„y!:†,˙Nţ@śh÷y˛h „ű8|.–,Ëxóťw(Ë’W^{µŮŔoě!řËď}Ź_űŐ_ĄŞk¤(©xćé§ůđŇĄî}—€~şPHĄřúË/{ď_ „ńa˝Ą$“é„ďżň eQ&§'±Ć˘•ä&˝xĂÔÄĎĆßý)/Á©yTřhüPĆÇ6!KĂłjبćw8§jŢ›±]µż–%hWGý‡{ŢÁ´—˝kY…›Ĺ&ŻĄ@ˇE®uükdÚ:Ö†Úíât~ĐńđŞ`Ieyř=J  Eż?¤ô°R:_Ě6^_a¬Ą©*&cל‡Ě‰±(ĄŹöÉň)ZoŰá‡ńĆ‚Ť ¶ŃľÂź“`w6LD‹ˇ®k„’Śv¶°V3)ŠŘA±őŰ\Ś^ŞVnü6•g©‚HŹŚe™ĘČüďsQ?ż¬§Đ˝;í͡ÄŐĹoB\Wç™űŚőĚ,ˇ0Ň#Ą’̆CVÇę2§˛0î÷h¤¤Ô ÇGc’"PÎ8PÄCŰbHę¦a0ěł< µ¦ö9“ÉÔÍokť"ÝyW`ŕéu¸Ëé_żo˛źčŕ•óĘĆ÷şß9Ü0hż·h+´ßS*ăŐ×^wźŚÖĆaŔż``„ß+%ďľ÷>ź|2ľůüłĎńŢűď“…Nśô%^ń pçđ'~üÇ1ƸDk1R`´€LPöúüîżů·e™X„~LdüÂsá-śO ?JŃgu<2ľăŁĐýÚ^xći^{ëžąřŃgŽôrJýĂŕpµż´z—úŰ Ź¨˝•bř]ë9ŮFđîĂ!5ÚçéBŕ¬qČÚř0#=¦ŹşŘpĽ¦mhdŤe:q:÷łzĎ‹16Ş«Yc¨›†ńţľ«Ą×c;»÷xćä ĚçSŽ;Ž1†Í›·¸~ĺ*Ďżô"{»#fÓ©k Ľ?ˇij§ďŻ]Öż~K+ŻΛ ¬zÔőśÉdÂx<ö şJčxđ{W4l'fľË6Â<ß .˙ťÍŰČ,sR˝Ö°:#Ądgw—ĽěĹVÂ.ÁĐu­”Rz#D˘˛ “eŚ7Ö0J! ”ó9 Ę2Şő5ĚňVI„nPµĆjÍ~¦Ú0śÍčĎj”÷Ćew±‰m*0í=}á:(yÁňpŤ[©śŃęĘ}Ú´qĚ•ů8ŕ7QŇÚÍÝht“ŕ+ăµĆs@VŠXD÷O{č“ÎGŤ11äbôâű‡&ţđZŕOŮ»Ĺ}Xëęń…ŕŐ×^ĺůgźsżEÂ3O?Íě7gô˙őđý®E>™Nůéźü)×Ý饬U,—˝rő W®]Ąç›ÝwĆPk—C˘ Úâu7LÜýÇ] >JðĎ:đ‡ńČřśŹObÂ…ď.-ő™Î¦ô{eB÷‡ő±őđŰ’>îńţj­AŃ."-h§ şŕŃÓR˙žÜďR˙ř<‚ř.íóŽaŕŘ sČ"÷ qż߇Řy&ôűôű%˝ţŔIěć9u]1›)Jk@J—Ú[ë×\É`8Äb1Ťfyy65Ăፍ ĂŰ÷îqúÜY¬1”eŹsÖN§®­®uŕ;ŤcL6JŇŰ$ńK¸D°˘,Í2ćUĹÚúş‹±)^)[Ů×PÖ!“ śćľ×†ăó6Äě-¬®®Ń4u¬°MCQ”H!čúČĽđžn[Éŕ ŘbtÖî;Ô9˝şFf9ó•!U^ç9Ó ç1ĘKü*'°TbŃGް:1ĽsUôPY‰ }Âś•]Á«0ń… ĆŹĄ,{4MC(Ë´B‚®QBg9ątźŤą RzĆmĎXK­-ý<ă?ű»żÂîxĘÖö6»{{Héô÷—V–PÂ÷1đűN+Y‘®-p¸c8sć,ÓéĚyâ"Üy÷IĆK˝üÔÁH?“$’cX^^f41O9räój†°‚“'NńŐŻ~ő÷µ–“ÇOpöôićUŤlVrűýŁď~‡çź}ŽĽ“ü'âŽč×­ 'Ož@7Úłb†,ËYăoŘBřĎ;ŕ/ŽGŔŁÇ“Ź=Ćźýĺ÷yůĹc«ŢüńĎĹő¸Ú_ë-»ď[kÉěoΰ—zúąŁÁ&ą Ĺ–&‡˛ťP‚níˇ‹Ý'Z ŘÝ&Ó)yVPN'äMÖ5ĄŻ‹oĄŁs­5Ěćsęş"Ď2Ę^„d^×̦SvwvřŢźý©ÓF°N«]űkµugˇ>ÝÂ)„ë0™NĽŕ“íÄž%ŕ*:„§é5WŻ]c˝z›×€W%|¶ĚP*ˇRĽÇîtŕUÄ ‰ĄŤ˙Śč¦ve†R:‰ŕşâČlŠ’˝Ń™ĺ,ÝůV(áŽMX^P r :Ň çÂęAßiÔŤűŚÖ ¬5L„bwu•ň˝÷QóŠĚ”2·^ßŔ×°·Z~ţÚg*c6™:ăB€°îśąŔÜ_ËţÎ 2Ţx ƅĉ-ýŤű Š^ňɉ·îÜfw<áĂËWŘĽw—[w¶¸ug“Ů|îuđU¬4ç=ťgÜ÷©H­5Ă~ź>üŕÁe}ńĺ Ł8h6XkX]]eww—ŞŞx÷ý÷|·QÁeoĽůć}î#A­k~ěßbo4r «@Ü}řoď÷Říńî»ď9!ŞýfďjŁąýÜÓčĆĺ¦ăŽc4°Łşżĺ Ł˛~_¤Š€GŔçx|Ň“°ižöiŢ~÷=žľř„źôŻöŽí@€;ĐÄ˝őĂŔĽýLBAZKS-őO› `#ăřCĄđ„÷ĚdX8Ŕyś26Ĺ‘J EŽ@şŢuŽň¶ďE*¬7¸Ś¶XÝJIVV–i´ĺÄÉăL¦s¶·61Ć’ç9*Ď. QJQĎç”ý>˝Aźí{ŰH! †îµ~Éd<áÖ­[±ôNřL{Ąe٧č•^˛9sgÖSÖRfôúy^:ák"}o¬ŤyKk«Ěꊺž3›Î0ÚIJ:!ś·ţŽZľV\(áO2…Ď=• }řMĽwsäHëÁ» é(ä'pîę˝÷%¬˙™Ć}Ü:­H)%2ËPBFa#!˙~ćĂxĂÄmC…™ţ'€đ€JRÁ%ÖMCígő‘őuNť<ĹçÎĆ}*©íďsíÖm®ßşĹŤÍM®ßşÍŤÍŰÔuăw|ŚÎNmduÂKÖZgDřVČqrv†ż—›űÖúRŇ`WuMk˝!ĄeŻÇ»ďżÇą3§c1΋/ĽŔoľé®q8Öt?~ě[ߌ- µŃHă*VfÓ9řÇĚ7żţ _ u÷ŔoHXG)%V¬uű•ި}ĐX\»•>_Š!„ , –—‡ěîí±˛Ľ’ÄőSę?­X¤ţݶ"Ýo[í>÷^=6ńčq0 pű¦>ĂÝPB×pHoŕ°‹IV‹…ĚS×L&ň¦v^ŁT.cŮXO3;¨Ş !5¦©ý›y€“;u‚łçΡ­a´łĂÉ3§ąyý:ý çé•=ö÷G¬mlăŃŤ#Üľy›ŞšsţÂNź?Ëho„Ńš˝ÝEŻä‰§/ré˝±§ř']l˝ěô}Ę^éŰ˙ LÓ0Ż*תµČQ>…_fĘÓ÷ań,ňś<ĎhęÚő˝ |I)îwů !Łő  ‡L÷÷ŃŐśĺÇwŕ^”ŘŁ}äÎ.¬Ż97ť\ˇ›FÔ5ţ`]V*řD?gh‰c€ËŹqsÉ0›WÎ{”.i1¶"6†Fk§oX厧ľëâg‚űŻŔ°śád­ĄŃN ë„pÎź9ÍůÓ§QQO°˝łËµŰ·ąq{“›››\ż}›››„3 b Ղa˙˘=ŚŘy°Óe(ľo…ĎM±m cçn±É«ţ:˝óöŰüŇĎ˙mަB ÉłO=퍖/ÎżnŚć§żý“ŃH rŰF”ĘřÇżńĎČ‹ü )!ÚóŘľ~—8ä˝Ĺç ßůĆgąŹĆ!ăüŮ3|˙µ×˝ĐdâTĹÇEŻß—m¤~!v$ źÄě}†0Ú’>o(„9Ąůq‘°ÝPB×ă˙QXóťědďńf*C#Pž2Ö˘ňĚ—§ŹXŃc0\biÉŠůdĘÝ­;LÇĘ~Ź÷ßy—şiȤ¤ď™K•µŐ±t0ÉÂyÜR@ÓĐ?~!V*żoř„Oµ}/žgĹnl ¦SÔµë\ě?ÓD”ŚMZ5ző(¤d™ŚÇ#…Äí+:]ĚąÁeH^TxŚőű’>@ʦZű8>·m©uʲŕâůsbuµďUďŃ7öÉއĺ6ŇĄŐZ†—YFQ–ô—6/-(xż±@–)ň2'Ës@0\Zb6ť!¤`>ť1žŚY][§iö÷÷©›šşž»2@ś§Š;źQ”=ʲd2ťrýÚeŠĽ‡Ĺ˛´˛DS÷it­5U]!¤¤ě•ĄW DPŐ5UĺrmjŞŞFĺ %32ĺ@=ĐÝÖzeŹŃhD=Ż©›šĆoCJÉl6#ĎŤ×8p ‡RJT¦M®3§ś¨„ň0$+±Hě`čÁś0iVuŕVDĆ;B}ň7Öwë±c!ĄÜE‹;Ţű 1˙ <@Ęŕâ˙…±ěOöÉË>ÚX§wź%%•ޤI´mR¬ź >˘eˇŃ4¸<#kkl¬­ňőžu%—J±y÷.^»AV–ěmßĺúí;ĚëĘëö«ä|„‰í˝ţ>éĚbî üéLcą|ů2gNźĆâ°˙ÉÇźŕÚŤ>ąÔ˙>ÎźçüąłěŹÇńzX#ÉňŚôĎţ eY u˘WhŁ ˘Ű]’ŘÚqôE{<íźľ·˙yJ|d|NǧI-úů…gźćŐ7ŢॿâK–ŇI A·=gmm•şŃNmŻ,™Ž§„úë˘Wrá±ÇŘÝÝĄ×ďŁuCżßçť7ßbo6FkM–gŽžĘ—ôą\ IŻ×§( ß#ŔIg™kŢ$„ i„0R8`°4db'4V#´Ďi0.IÍR2ě "<ŔúĘY¨á}őőtÂęĹ‹Hß0‰Ů›;5BzBxĄ!Ö`Wר_Xˇ÷ękHkšÄk\0Âu@DJ?Ľ/Jůăl»8¶Ćp ˘ŰěŤ?M)ó•eänwF3žLhš„Ŕhgáúa„ę—Óν.¤cآµ i –šĄţ_yę"GŹá+OĽvŤë·o#¤$Ď2„đˇż˙E:pa’çEÎ{ĽĎ…óç°¸žgźzŠë7®!Pĵ5üÂßüyŞÚ…¸¤hÜůű?üCövGľýtČ× ÄXŮí"Ŕ/~&µóĂŽűU }–q<2>găď˙żŮŰŮ«žzĐTţ$Fťyâ± ĽőÎ{"µŮn㾆ĆÂ”Ę IDAT_1>J‚ŕCŤÎš´ŕžßDÇÓčQ66%ž–¶®Ćşßď3™NŘ[·o±“ĺô‡}¬…c'N°uű6·nß˘Č ÖÖ×í좛†ůlîKđłé”˘(ŘÝÝe^ĎY]_g6ťňŇ׾Î_üéź’ç9{{#ö÷÷1Ö8PŔt¦Ö:‰ŕyĺĽČŞdĘ •Ómot@ÄëäpÓ©îYíD‚2Ą°YęŤ^bö}:Ç|Śĺ˝ë˝˝3§é•%Tµ«oßߥ°ëëŻ'!DĚútV†ŃČë7iF#2śd˛RŇWHWé€+!Ló^Z(É_Ä×ÉçDú‰O@[0bňRŘŘ]±–óv[ÖÝÓů<†‚üs/w-v…]łćŔÍ##,h—ĎPWNÝpĐďóÂŧřę3O‘)…±‚+×opéúu.߸Á‡×Ż3ŤÉ3_ánfy“毝RŠwŢ{Ź_ţĹ_˘Şk„<űĚłüîżűwąŠéMÓđó?÷łĚć1äŕ«Dţůżřä™ň|zĄ7Wrhő&ÚĹ1śčÄÉ[ą.&6A?Ź €ĎřřţǢNźZ;•ůß1Úţ˛µúg [“RXmě§:ë„ôű=Žl¬růÚ5żp­S«—ÄHâţ6â‡SűëlCX¬ Ô?ţuăŔĹ:%~q{í±tü¤:¸˙řT(ĽÎbc#dyĆ`8 ŃšzVa0X€Ż ŕËůÂ95Ć:h°»7BIÉh´‡Š­;[č¦va%ą·u)wďÜÁb}Ţ›Ł©gł){{{H%Ů˝·’?Úů}Ş™+Ó •NrŘ%&VóŠĆ)® ±?Wu5e$ÚX”VžĐq† VĐ4ŽYM'%)Ë^L¤Ă:Ý€ Ľçč%JaĹ®ć×ß„"wyY†<qä'#c‰ŞŔúľ`·îaoş*‡ŞŃN™ŃzĐń,Iéłĺ]2]¦•n|©RˇË †D+ aÂD‚WŃ[6ŃF “B„%˛i–V(ý^ż Mxv¨Ş+đeŽeńF”ĹüaŁ‘çy|44 ÔŤű]§ŽăÔńcüµo~<ËíŹřŕÚu>¸zŤ÷._áćť-ňLů’DŃn-h5§jEŢ|ű-z˝žc¬„ŕů瞣ŞkŠ˘ÇńSßţ6Jf(ĄÝ}- ą”üňŹ]ąéď=ŮŢďaŽ„›'ŔéWň°ֲ±ľŽµ–÷?ĽĚĹ'ÇM( L©/× rI<[řîŽ2&ąŮäxK†tŤwśÁ'B*uSٵˇ6µ 45eQ­(×Áu$eĎ@‹žW`ታgyňěţÎO˙4ÚŔ‡×ŻňľgvÇcŞş¦ĚsNYňÍwŢćk/˝ ·'źxśkׯ0 ůÖ7ľÁîŢžßcFżźó?˙ý˙…~żO řqDC0=jßlý{čöSćĺŃă‘đ#˙ěý¶’KK­µ˙…±ÓżkµůVÝh¬±6ÜńJI˛L‰^żÇpĐcey‰^Ż@ ëu­Ő_˝Ł‡‡‰^„żWV–QyĆ«ŻżÁWżň‚/×IŔ<ÄěŁçŕvhßzűţs÷WűkŹ«}´‘&µÂĺŘdź6´Š ăŁýg~€xţÇüżÍĄ”E‰Ě\7˝Ě‹Ö!'Ŕ•• !\ć–Ń XZZ"Ësň<§(KîÜľM5źłsďËľ* źőŘŰŮŤܼzŤŤŁG¸»µĹdqŃhĘ­»ŕ¶ŕ3“ÖĐ‚Iřgú‘ţŽâE)HŻ„‰Ŕ ‚hŚÁ`±^ßZKŃďóO˙żßáüŮłßŘŕčĆ:««ôŠp€‹51÷o$ÍDŇ0 Ś?ç|^B‘ç z˝ËËKÔuí¤vŤÁ4>| ­c–HîŃó¸›Ď3«ť„ŃŮ“§8ę?˙“?A‘çĽöÎ{Ľ{ů ď\şÄţÝ)oĽő?ţŤoF!Ż‹O\äęŐë,˙É/ýmćU…ňĺ˘BÂţńw¸~ý¦ X‹/•ßÂ{j¸$ć@\WÚ!ľsqËX~ŠľÓ<˘Ď˛Ŕ#ŕ‡8~ă·~·"ű¦üWFë_nęć _ĆfĂÎ2%Š<Łß/,/ É §<6ťÎŘÚÜaëŢ.?űÓßŕÓW•âŐ ×ăÂůsüů÷ľĎK_y!ľžs¤ţýŤč0Žď|'ýLBNvâř"y.’0Áaĺ~ ɇĘűÎL÷ĆţČ#:1íâ-p%~™Rä…ë»ĺ92“4sÍś±?j™rńr)Č‹‚ţpČ…'§©júĂŐĽâŢÖ]Ćă1O>ő$ŁýłÉk]€R9ŐlĘxĘl6a6ť®uŠBIŽ=ĘńŤuŽllptmŤ˛(°8C+Üq{´˙‰ę|±`!L¸Đ›qrÜ˝˛ěŕ_Ý4TľáThPää‚ŔˆąśĚg\R˘®Ü÷?sš'ĎťáW~ögŤÇL´ˇ,Kęş!xúé‹ü›˙{Ěf3~ĺďü’?G.Á3—‚ż˙ż˙oäYîv•xúÉŐđÇ.W|9e6nWń€gźÄřD‡ă‘đ)Źßţ­?Č©ż®±żnŤţOŤiN9ŘaĄ@I)ň"c0賲<`8 ”ÓNíŹŘ˝µĎţhźńtJ5oÎ+;ŐźL]űĂH]ŻâĹçźă•×ßŕ± çY]Z¦‰b]pŹŻ›¦Ľ¶|ĄŁŢĽ5ÖĹčŤf8\F7 Óý Ą!á¦i(Ę‚Ńî.»÷¶é ‡,_Ć6†Ë—/3čŘľ»E]UÜ˝»M¦ZßIH=L©ŐĽ¤š;ď°ŃN?] ĐľO€Ŕ «ćsĎľřĺYű8ż®DŃέ,Ë]B]ž;±  9qťá ŹP^Ö֟ߪr±hg€dąBX‰NνqôRJŠ^AVËh$XéX˘i@"˘Ő Ľ°P#ßíp‰†yž‘çY|ŃËť˝6ďmÓh'łlŚa8pâȧŽă䱣ś8z”Ť•wćŤF_!c<ŽŐ ţ~đóß-;­ˇN_"Ë\uŇĺ¦Á¦Ć4`ąo®‚N*]BŻ[ki čŞ"ĎsÖ<űŕ ľńŇË[_C–%Îťw= ¤D Á˙úŹţ!Ť6®§„M7N|x)ą° 0iRbX‚E÷ ˙büŐNÔgi<2>…ń›˙ďżĚ…Ľd ż>·ŐßłÚžńJZŽŃrB!˘Ě3ËËC†>RÂl6ĺîÝMvvFěíď3ťÎ¨kßË/ŽćrýăüuábŘ/>˙—®\ekëO>~ÚS×nŤ°ń8­§$¨ö? …Ľˇ5 źwJý6ŰçžúÇGUřčÓ§’ 8%B8ZśL8ń㯫¨Ây±ŇJgvjsƸFA[wî ·¶Jbăbý*ăîÖ]ň˝=ŞyÍ|6Ăb©çőĽâÖć-0P‡Ĺ;¸Š—X†E÷ őĽrs`‚%.†\UŚGGí“řa˛zkq ]ľNHds—Á2›Í™îOą"“ ‹ˇ\ź!,ĚćRś´´tŕ¦MGqĐĽIąiüoČ4uăŐ„Ý1X$ęĆ * R:ŮekBb—ż§j»·tô.őîYă»x:&ź™ŕ•Š6I{. žă´±tUýö¬±.‘Ň— fYű+ŕöÝ{ÜÚÚ˘~Ĺ%&*)9¶±ÁÉŁś/Ö÷:F@´˘Úőžč÷Ęh/mW•cGŚAZÝÓAr5Ú1ŻfĚç3—ä'Ź_xś˙ć×~•żńc4MíĘH­ĺŢö6żő/›ĄţĐź¸ř#Ç#ş/ĹťJ€t ŚŽ ńöřőó°ňŕ/B)ŕ#ŕżń/˙•Ěéż`LóßšŠ_łVź>SČ-š%„ČóÜÇó‡ô=„µL§nßşÉöÎ.;{{L§sšZ»›@¨Ř#>¬”ü SíAqţŹ:‚pîĚi&“)ńýWxęÉ'|Żn}ŚN[ŢĽ*3ĄţUű ş‰wźR˙‡Qţ„ç!·ŕ>7ýaB?źćŤm=!Ą˘ \ÝŕĽmáĺem۸¸i´O +ű%ąĚŹF”ý…,ÉrE=ŻXY_u޵RÜşq‹şvJ{S1cgg;ćDďB$´µxĹ@:ę°Ň”6­k„m›ąXájŰČĆTM…Ö ‹”pe…ĂÁŃţ~lJcŚf8™!Ś÷ÇH.‰ÍDBšF3÷őî:¶Ą‚ˇŢÎßkTŢ8 µÁ‘AIíBßđýĐÂÚbk]ŹŃĆ‹ü‡€hgü÷Ňą"DrL# ;\¤ßGřI"š-ž oj)€Ś,kçéh:fďň7>Ľä’Ťe}e™ÓÇŹqćä Î?Á‰#éĘ0‘.Ôáć`Uë«řĽá€Ü÷RŔ˝»ŻÝ Ťn¨ŞĆ1ş&W‡Á»‡ĄTěmoł~ě8XČ …1pâěy,†"Ďô{ü‡?ř=~ęĺŻńÖ‡˛·?ˇČs¤´8Á Ú„G›śŘ%­@ň\.nčáƱđ‘đŽßţťďžhŞŮmŤýőĆV_q µarH!…Ę2†’ĺ•%–}¬µŚ'ű\żv‡ťť=¶w÷N¦4Z; =”‰„ÎTÎ+4Rb}ű׏;>iŠŞßďńň‹_á/1ŻžąřÚ¶Ţ}ôč©˙Đč‡Ä8H …đ\  í(č+ĄQ;Uť„Ŕ®đ©ÔýßgĎśGěÎQđR™¤Ć^¸9a,íÜĘuW0–^ŮăȉăÜş~ťĽ(Y^Yf>źy-wv&ăýŘ\(,~‹Ju!ÁJI‰–ˇĄo[§¤˘Čsú˝ľKZLâŕBŠhŚą«a¨ćzjĐşvZŇ`µóJuÓ€µhă<ËĆ÷hš…őRȉç-Ľqd !Ďŕď@kqĘwF7`$BŇVH0¸*ţŕ ÂxŁ"Ü«˘ žfAK”hK[Ůź;ë>ëš> ­ č^yCkŘŕ=›üŰďŘdâ$^p|ę’ łLas—ŮßÍĄ7y˙ę5ę¦ÁZ8¶±Ć©cÇřćK/!µćŘĆĆÚ8·ÜmjZĐGF̬µ1áJfôú^ČZćuEÓh¬FňLĹą ¤`gűGŹĐ4š'ž}Ţ…0–­ÍMlUń·~ňŰüĘĎýu6ďŢăŤ÷?ŕ•wŢĺÎö¶Kd<0>B@¬­üx÷óbŕđÇ#ŕcŚý{Řßß׿l¬ůďęjú·ü}oC&źB(Ąč•ĂaźŐ•%$‚ńtź«Wݞuo›íť]&“©“ë´Ö÷d—žRuILVąLfüŁQ +$Úű]3>ÍIŘ€ çĎŃ4 ŻĽń&ë««ś=sšĆ6žúŕ<ĹVí/x xqźtá‰ĆBĘčń=±đ¸¸ŻŔ8¸íóĂ·äò×)ášîŚG{ÔUŹL@ăăíˇő¬µÖ7qq†“‚z:§®j¤ĚÍŚ‰1íSk F»»)™Ś§Żł?;ĎÚ&˘(>‘źP^ézŻ»3Ż”đµăŢkÄ ›šz>g–Ir[zú× ”„¦5´¬vۨë]W4µŽ1cc]É\Ó¸Šá‚îNĹ®kO%·I^.ä…WHtohAŘřĘălîŞ($2zţî–4‘ŇáEá” ťÁíögdk|[!Ľg„uLLj Ćą¬1 ¬ĎIôÇ)-±±ĐÂmęťý¨uç†ň! Ő22íąHgQD€>$ÓJ@)WĄw&ł9o}x‰FH^óMň˘ŕÄ‘uÎť8ÉůÓ§8wâ*S.ďĂ˙ĆŔÎĐrîTŰÎŚ.˛Üý+]bç,„ M¦${ľ1“±[×<ńô31ˇQe9ŻýĹź˘2ĺT§3–†}~âĄů™o|ť{Ł=^}ç=ľ÷ć[Ě«şµáSO?dí-•ĺĎ›MĎ_r ?F4ŕ 5qü‡ß˙syk2zŮjóß˙a—cł3/.•čô¬®.QäŠédÂÍ7ŘşwŹ»wﱿ?ńÂ"IJ&˛–Ąr Ż2˙\bUćúťK…PîźÖ–űŤŹç˙¸C)ĹK_yž˝˝Żľţk««ś9uĘ-.Ág´ĽĎjŃ˙đ B7ÖéţEę?}Ź„q<`hä>÷ٞä#­_Íů»żţëئ!ĎłLđŔ@$NÜÂĺ˙΋śj>÷Ŕâ=\éâĺa>YcąŘ¸s=źÍ}“í!éKőlPh´śµ&ĎsרȋǰĆZډ3P]ҶJp‰áşů.Öcî˝AŹ©§üýťV±ŔĹgţöŢ<Ö˛ăĽü}Ug˝ë[zĺ.Š’lËű¦ń)ńx“=˛ě(Áȱ1‰db `N‚™3ÁĚVFI,kd­´$Šć&Š”HŠM‘›Ksí&›löľĽ~űrď=§jţřꫪsß}ÍŢŐ”]@÷»÷žsŞęÔň}żo­[¸o–»dČSR9IŽżZËü怀;aĎ Ww>_Vą‘7ÁäM ˘é®K‘úÝéžȲ×%UŻňf›ş® Ó€u"{ăGŘʡL)˛Lý!B -šŠ_ÁJAŽQŹ7˙®)dy†N«Ą5—×0żxß~ńEÔĆb¶ßÇŤ»vz@Đ)KTF""xŽy®]šeŃDŤsB,ňĚżÔĆ`„Őĺ%^ّƭËcrčµý¬o0 ”b9Ćş˘( Ľď?ó#?„v»{Ë/Ľ~§Ď˛f@Îi`ĆŻ<8aŠĆiŠ€®hlŻ )÷¸Ë߀·(>đx{auí·Ž--ü ?˘š˘n‚N5Š"GżŰA§Sb8ŘŔÜÜiś:}gÎśĹŇŇ2«{­ ›ÜIő¤ç0w Ţj퀆M4H%@’ É d­Żżţ*ľńŕ×đ/ăý­­oŮďXâżš6+N`ĂžË?üďĹÂâžée´ŰmÜxýné]`đ~“¸ßŁë˘ú÷`ÁIú–ŚŹëoś`'ř —a^p( ó 8>ÂRv’âůG÷ ËR”e‰,ĎĽc‰Źś‡ą;ÉX ŰíaiiŃ1CBoŞ a8@éi–"ĎS}óV––P4Me9§±µ.äMü ÜŐŰt‹˘€Ň„,ĺxô‘¨v-{¤Ă….ćyá“ ±a8ÂXërchl6¶F5ŞĐí÷°¸°ĺ<ŕ­ŃŮĆcł6w‚UŮ'‰˛wşvýIfAëM|z>Ş7ń ÉÇ:8oą‡,t’ˇŐëb°Ľť0c÷É(7qŁc_żTĽ€ŰÍçIŽą "/B+á7żĚ#eĺЮ蝵VîdI`0b˙ˇ7ńÂkŻaTôÚ-ܰs'nÚ˝7î܉©nŹ”˛5çyC»Ŕ©şÂYÖ˛@TUC§ÝĂ&ŕţç÷9gMńĹí‡{g§ÁŰ13•â}?üýx˙Oü(ć—W°ďŔ«xúĄW°¸˛‚,IĐu¬ß9űáŠęś·ÍqâiÂćŠĘ$u‚ĘÖĐ©BBšŚsę35űhĹɇ”ćŚuZihÍęö4Ë$Ú%‘Ş`Čpf;ťB+f¨ VĂ+—«_¤mQ˝‹–Kαóvv 2~,ĺEäS3/Vţ@&Há> WÔ•vLĘú¨ 3ÔFVä.ťDŮ\@ÂżMđź NŔ&·RśVB4@6Ň.@ÔÜ,Q×k•¬<ë#í(÷ 0H’…›óCÇŹăµ#G1ŤPćnąnnąţzÜ|Ýn´ň C§! Ń=\—śM@ľ#„•Ą%EéŁó”RŘ˙üł~miĺ2_:?Ś”q`Á‚C7ěe–ă}ß˙ýř{?ň#8vúöľü öx É&'iň©/‡,>‰áż]˙Dĺą§^Í_;zč7Aô?ŚFőO'šRÖ9ÁHT‚˘ĚŃë¶Ńn—ŘXßŔŃcGpâÄ)śÍ¬=ä| A'5*—(ÇHx©óÇ®o h·P-/{•40¶Ú¸ěL ‹ @´ąK2ÁđŽzç{§Ĺ¨ůY´TÇ™ •×”0H°€ĺ3& d_1­KP8_‚C'NâŐ#G1Ť0Óëáćëvá–ë®ÇŤ;w8ÓF#˙˘Q@DXY^FV çVk8sâzťęşĆĆp€sh%`5ě;ă)//X¬í÷đ‹?ő_á?ű3xůŤCxćĺýxőđahRŰ?…ą$Ů˙íÎđÇËߏ>öíţ©3ËxöżY IDATđřᙤz§"Ĺr$3 R¤¸ě|SS]$Za~~Ŕ‰“§0wf«kkÁzĆŻ53|gǧ„>锦 $%Šv Ë++ŘűřŁŘűřŁ8úĘ‹PÝň˘Dw×u˝;b§7§gP×₾sŰ6\·s')śž›Ă›GcŕrŤwÚôşäEÉR›©ˇŔšCRÖ'pŚ‚;ÓťÂÁ*Î.mŤÁĘę2—–QU#”í×íŢéě”ÍrĄC­!o’h8ŢU›Č;=H*îv.ÄďkPWµ“lYUŢívADHó ĂŤÖÖVajămÖ7żă|ő5l۱eYâŘŃŁŘąk'¬Nź:…nş ó ¨Ş gç΢65Ľ;3ȉ$I|„®µ<ěůć´/†aš"qcÍ‚‘÷%ů°vµ…©+ĂÁ:MştĂŠĆ@źaaLŕăH‚‚ÉŘT!ż đ‘ď1*ĺüäĄgR€Jcm@ť$UîtF(âkĂŐUäÝ ŘŠóaŔiĆ ;2ş9–ť¦Á_‚|să—Řt˙ ýą~ŔFíćh"ż ÷_Ŕ2PJŁĚ5Š<ǰŞđʇńü«Q™;§gđ˝·ŢŠ]ł3Ř9;ă’ç$ ¬--bzvkh´Ć_đᡠâě„ÄÎÄáµeÍBBś®Zúsţ[@Íŕě–ëwă¶›nŔhTáŮPU#Ż}ł‘˘$ŚŃůŃřńP}÷Dü­_}đ±›×Ö6ţtîěĘďĺ™ÎEĎääIhRHrŽŰźžęˇ qâäq9rÇŹźÄüâ"gNĽ39¦Żś”Ż’¤SPš€’:I,CŃjcumO<ú <±çaś=üt·Ź¬ČŃ˝îämuB üÂâä'źŻµ2î(~ÓS}ĚLOůk ‹_XŔéą3U§uŔ!qvnÖr‚Q]a4b5·d5+Ë3łSxĎ{nE«•ŁŞ Ň4Ĺžo>ruUx–cźů ťIÂYířđöQ>¤MľXmUâ|G´V~ôşR([%Ң@5bvű6,--a4¬PäFŁ:ť6Ň$Ň »víB’%0Ć`ŰöíČłív‡†5†3¶qó>÷„$NÉË~˛#Ďô#§“F8.Ű:{¦ľ†ĺ¤„I›ČZëróCÝn‡ÇUě–` z0bcc58O}š&(˛Ě©xm„ÖY‚+ßÎUWáçIçS㤌‡˝UÖBËđ„!‰'Ľ<,ďa,ŞĘ™ýNź>ăĆ—°¶˛†ˇSËK¨Ú™SCĚÍťŇ 'OśŚő!u†OíłÖŰ»u’`4†ń@K¨@]§.ËqĚ=XÚŻ+ů3Ć@ąT®Ć:ŰłËW G 9÷Y &`4ä\ĂáŔŮ<,*U9ć¬`T ŚXZŽF6čúbjqTPHŇ ˇ{3şŔ¤śV]ö’»i_ČeöuŐü€©ŚÓŘŔ6"0XYFŮëqŘem`íä|Ƭ®®rJĺuşm¬¬¬@’÷é§MÂŕ“,}Dжy©65Ö××±şş ­”ωą5¤ŕů+[\·ř%رßŰ­†ŐŁÁŻĽńö8€Ş6Ř9=…ßţčG1ŞFPD¨k†Cg’ßš¨:ďĆ ™Jťy«ÂęÚ:˛4ŤN2Śţ,ĺNŤŤÁÖĄT6µAĺĚQoQ.1¸VL±[•ż5ŕŔ«÷ÓËűłż·çĄů?ÓJýlYd‘MŮ’RF‘ĄčőÚhµJ,śťĂާ™ńźŃ)µPr4­Ö¶8ˇZ2-zP*“f¬É¬řO„(‚ A€w¤łĆ`°¶ŠĽŰĂĆÂ<ý¤*iSÂýď’_€ 9I9©’5ź—|vŇ2¦1áćS“r&šŕéµç¤ŕ…çú´€ ™HÝĎâÉ~ ¤-4’$ĺu®lßągć ´BYćÖe^°–Żvů"Éo ţ=ËSyŽ^·‹ÁpÔ’ťÇ„˘9 –©Lhjt‚âąËE‡siŻĹň]ö?eé•“ŹĽ˙ĹWĚź%š~&O3+ `"ˇµF–&čő:h•Nϝ¾}Ďâđác8}ú ÖÖ7`¬q™Ú$ź5 ľcúYť({}ĽyđU@á¬eIC5”ev–çčösl¬­b÷ő»qćÔiXk03;ť»waq~++kčőúU#ś=}ďyď÷˘ŞFȲŰvlĂęĘ*˛<ĂËĎż„í;w`yy0’5ýüLŔjwT.qYŞS>VŘňŮóŐ¨bSA’ř÷ux’¦Č˛Ś×Ż"h˛4±ŕPHQ±;s‡kÚÖP¬㣄“Äw çÓ:AUWČź! •Bš%Đš3×Ő†O4ÖÂÔĆËŕŽÓZyĎ»9r{QfŹ"°ö,_ŮX^ÄĚ 7c¸Ľ´µôíűP”cR*€¦€5"†sć-GuGĆÇďÇćĺâ$HŕŚčů”Y5@aM’ň~PΨ.ó Ýó 8—Ä/ýÂŤŤŤ XršŤ <üĚs8|řMĽë¦ńîoÄŽ™i>‘ĐđZ·â» @Ĺif¬Š<ĹĂŃU]ńaEƸc#m€O–°ő\\.y˙íč ř] ¬µt×}Ź|ŕĄý›4Q?•'™ĎXú“gz˝Ę2ÇÉ'°÷é×přÍ#ŽńŔ1ý$¨řÓ:É ˛ Zž#kw1 ńŘžoâчîÇĆň˛Nťí;j?’”?źšĽDÄ!– ˇ`]ňčkoA]í„CW«lęwAďH˘9µaľEâ±Aş’ŞH$cGů­ő΋{nŚĹÂŮłśBW'8vä8RgO_ZX„5ŔÚú*6ÖÖP×­Vëë8đŇ+ЉFQ”XZX€RYÁÇĂ®,ŻŔVµ—j-c’ř5Ľxe-Ř‘Ńet©[ś˙ćËŚ(h±>ËN‚’üHZŤ—H¨ÖrĚ9ÉČ1É ¶˙&ßd‡EëăýCS¶qę7çÓ$˛?€×Ú„\râ% ¦Ś  Ř‘Á`myŻŹŤ…ůŔ°ĄIĎ/Ç€[#HłŢ–qŽőeERf#ĚÜzb¬¤?Ž| @a]ĘŰŃX[˛ÉŤ†Ć߉<–š™™Á»o» ÁŔŹaŞŰűDăŐĂGńÂkŻ#OSÜvă x÷M7`Çô4UĹv{—E4ŢnÖů–h­P¨ežc}8tiŤC–B~ýXłÓJhţrÁe+§ák™áŹ—ďJpç˝˙Üťw=ôďu–ĽŻ•eB™HÂR8ŮI†~ݞČqěř1<ńÄĽyř(Nź:ŤÁŁ~ĄˇÓ'­ˇťZ_g)TV@ĺ9ŇĽ@«×ĂóĎ>Ť'{oě{ŞŰCQčÎngF/Î]äBp€ńj0{ ‘ŕĽÂI6š˝5ÖU)“$ţkqśoĚţů8^Tű(o@ÓźĆ42Â: •_§P.†ß†Ň-7ŕ äB®‚Şá?÷łX_oć+±•E^PJC+p2"kńÚŃăxńŕ!dąĆ;o¸ßsăM™îóŃÄÎOĹŔ@s\Ś0i9T1FŁŠŹŮ6‰' ÉáV[¶Jôs-ŇĽó)ßUŕţ÷Ľgumř(RĚŰ™•ČkNÉ 4MStÚ-t;-ś8yŹ?ţ2Ţ8t§OťĆşóčçô© ź[îÔű:Í ó :Ë‘ä˛VĆŹ}óëxäë÷ÁTň˛Ă*~w© ÝŘYTřÁą(’\€HB"˙™%÷ś˝¶济xcÍpîŤzĺUxMÔ\rť|ć9ká"± ‘ Â`c€v»ŮŰ13;c‡Ź`Çî]ź;‹“ÇŹ#Ď2LMOŁ?5…4MYş‡Eż?…ĺĹ%de†#‡cŁv *b˛ňĎűĄČ1¸gm# ăĎŠ˛ĺÉz¨jçÄÉť1‡6Řwś`8äÓűŞá†ŞQIB?ţđ{Ć3őÚOĚĹnž¤ěŚ(żIek-Çř{ îŢ)ž[iŽ(ś†hÁ‚€g’Ößç»`ŐĆ:ŞÁy݇ŤĹĹH‹p AiBäŕúÓ…H¬÷p(HסJiU5Ö—Á…ýE@@‘Š|Č7eEúoś0>Ę!¦eÜś™ÄI'ľÓSSxÇÍ·`9– HLSÇzĤ@Ą ’”S=Ž—B»]â{nĽďşůF—íO9pĚ.Ňž……N5Z‰ćě”ŐÁJx…0XŢNjý )ßŕ›OěÝ>wzéß GŐt:%<8 W'):­SýćΞĆ#ß| ľcÇOb}c¸f[ˇJ9\‹mú9tžCg9Ң@«?ŤăÇă‘;żWž~ŞŐFQ¶Řóźá”2qŇs„4 ČŽ/D–\K˙¬Ť® (VÁyU_íQĺí`ç?ź„­ý\Ń÷ňR“Hdh0[a,r ą8+^OśZwccI–ÂÔ5Ž9‚ŢT‹ X]YÖ –—WpâŘ ô¦űVC †C¤I‚ůůyTŁ •©ů¬gX‚–ż.•j¬[%ŽdJÁĘ›*ČĺgPŽ%)rľ ÖĄ4& r‡iĂf ĆÖ(Ú‚tHďLŢl r¸Ř,µ"(„ÔĆüłOÇé,YŔ(a”ʉŘ2ß2/î€î€ň Ĺ÷Ĺ`]¸?62¬ÖXťźÇÔu×acaqÓˇt<ÍŞ±Î„UÜŁHęg~ę§Řö@k…ĂGŹâ†ëŻG]×.‹Łë“eÇBřQHSŤ4I`­ĹľŻăń^ŔĎľď'‘T5n»ńz>Y˛®a¬śę^×™oB™ç!ĎQ|ĽˇVc“"s›dM]Ă´îRĘŰĽĽ˙DůĘWţdq~ő_·ŰeF‹2úç ×:AYd™™ÂŇŇ"{l^=ř:Ž9†•ŐU¶%%š™šBĄ)’,‡Î3$i´( ‹ZÝžŮű-|óë_ĹÂÉ“Čz=´·íäZĄ"i$˛ŰÇÎ~íoăÄ„?óq¤Á)IxGÖđě;QŢNv~kWša‚WыيŠËeŻ´†B`v,dYGĽ'Ńqů%VW8äm4Ŕé“§ ÓK‹Ë`»§EšĄ¨ękkk 6śÄd˝ä¦5{ —­QŘÚ ISصµ@đŢd%2źu ËG8(OXYčjš¶$m.9ő?±ŁgHq~¤CŇ«Ôďn.ôÇm őđÖ ă áŮ–\8źňuqU óS"ÔFmňňŢA%XŚ–—aëEż‹ˇdlđ h{^i ľ˝°Ó"ŕ˙d….H/"ýĽŻJh‰ż¨ëP†A‘ muň_¤óÚ„…mFé÷ČeńŁĆuř?ňEŘo¬żĂo9*Ě_Ó\'NĽđLÍ˝,@ +gćĐŢ6‹ÁâHÇśÇŮÄÓź…ýÍI†ä=ăe4ľl=#—•"Çv ÷Žâ@Ń_©aÇü­ °ž&5¸§HţÖÂB±_Š›wc,~ŕűŢËšU'ÝżđŇ‹h•%j3vF‚dbôΆćś™A^Eńą EÎÇQ?;Ź×OG+ËńŢ[oÁ{nľ‰#?Ş:ň_cÄŢ(W¶Śű]ËÂŇŰ<đŤ§nZ^YůX–¦ż’e)GôZĄkyO%‰F»ŐBŻ×Ćë_ĂłĎíĂ«ŻÄ™ął0u P‚$sLßyđ'YŽ´(‘”-äí6,)|óë÷ă‰o>Jse ť¤ â¦"‰Ąi뉂Ó˙΋AâxAá2 @Ěm> 0r—m|żŔ0ż%ůŁđ8ęáöăŘş  ŃŮ6‹´ÝBµ±.+Áʉ˘±úř >Gn°~>äŰŘňňt‚ŻÇ`śR[ö± 5““ô#c7K.r@TčľG¬ą L rßőÎwş´Ě@ž¦xţĄ—đc?üC0µ sHNëéÁŠ˘(â²ќ+…DYt’¬ž}ő ľýŇ+¸őşÝřľ[ß©NŰűśąÝî Őźö҉xč†.OŔ1‰A©(·8«t)RWZ ą!EňŹŽČ† $GŽ@˝˘ăý6˛ó_ ÍDĽ±/Ş Ű ±H\"Ą5'µ˘PPGĉĽů°r’śTł·<ŞÁo:„,ϱ°°ŃhÄÄTΤp/ť$Iqúä)Ž—°ŕŇÖ.Ě/ ÉRźvµiQ~ý2›Q^ęBňÜŐn& – ¬uŔEű(®źßEźđ‡x/E&€Đ Ś\blt]ĚăZ8?}ĂmäC…„7ąh}çD'{Ň«Ý)ډĚßÚٳȻ=T«ë D…»xÝRXÉ÷“iE(n]řqv+É·éč…c˘ĆĽÉAÉ»¨@,2ÂĘŚEÚyO4 ŕ€á]5ŹtvىS§°şş‚,ÍQYĂ‘2÷şe-Y°C*‚Řîe¤•ź?N–d9śeŽÍÍăŐăÇ1Óéŕűną·Ýp=tä}đýâčĆů„Öőß%ş¤rďýŹýôť_äíNů®Dikm”śĂ9ŢčLŁ×i#K5ľýäxáĹńĆ뇰¸˛ ­ť}?ϡÓIQ +K¤Ey·‹ş®pĎťŤ—źzI·‡ÖěöČN$‡8źxĚř=Qí(Ţ<$QĽÔ• żhäǢŔ=ü•żbÉąŚ‡Ą\. 8Va]«eśźOßů–Ëć (ÎŮÔ$1J3ĂÓJ%i`\’ß2ç~0ő tÚ¤IćÖ!0=3R„ŞŞ‘„ĺĄe´Ú-TŁšĎ¦'BQPJa0€Ś†í2 KšéˇÓíă䉓¨*N¤ă=Ü7ň đ ×Kr’&–ľĂ2&ÎčöE{AiŐp8 Yů¶¤nĺÁfćîěĐî9'ß7DďCŃ;Č©‚ŃőDŕ÷µGA!śÖŃRsŢŔŻŽŤĹE”SSĐe3E+ Z˛64šď.9ü#B¬§ ÍĄFQŐM `ťpâA”sż°Q,żÔ-vx šô ĆéŠgÚŽ ßxĂMHĽzI’"Ď3÷űp4âwu^ýľź †[…h5 ‘_7Šś¦Ď™ `Rš —v0¨ žxé<ôĚ>üňOţ(Ş!kÎÄ‘ÖŰs. L >_?"k ľđĺó#żţ÷żDW[}űĺš§Şě±Gý·ŠÔ÷{öń`Nęě}|Žtžgť™Ć‰ăGđ­ÇÇ+ŻŔÉS§1ŞkĺK2$YŽ$gOţ¤h!kµQt»°ľvďWđ“Ź!éôĐÚ¶™ńo¶AF€zuĆŐwM4 ¨z3’öáU¤±Wż „W¡Äţf9eŞBSŐ-Réĺ`Ö×*ăďĎĹĽď$é}R~€+á بÁÚJ:q±ďâDGrš}xrumIšA'ÚĄŢe5z–çЉF^äH’+Ë+Ř}ýu¨F#TĆbfz ó šťÁüÜz˝’”Şë'Žť€±5Ň,Đí¶1ÜŘp Gö#)UąuĎ|ýu¬¬®.őh’Ĺöýy«ŤĽÓ…J|ăk÷aßăß„îtК٤aü$<Îř%Ů…0~VOYGx”· *·@Á÷Ĺj} ŰÖŃ}6_#żČI…Ťa˘°'ŕŇśM&ˇŰkµ\J?Çsr_ŤÔťý“ď µŇ ĺ´™‰od‚=X€´‚Ö.L5ÉĽ şĽĽÄf„eŽ{ćĐ Ĺ%äÝë 9*¸ 8ä9oBôý[‡ý,ŤĽ¦@.é<¨ôB‹V€dIÚň…ÁóN#0ţ†ěsM~ €Ý;wˇ®*¶Nś8KpjúÔ1~ŤŤá‚€#ąü-¬A 0PćE—+ôÝO<˘ŕecĹĽ±iđÎżÄC—hĄV«Ť4M>räŕÁż˙…/őźüŁ˙â}[Ůĺ,×°ÖŞ;îţĆźZc˙ÝtżkŤu."%:‹&˛<ĹĚLgNźÄWď}/î?€“'NˇŞ tš I2öć/JdE i«…ĽÝE»ßÇŁ?€'ľq_^Fý IDAT?¨hˇśŮć$G€A^˝çŹăŤ7ĆěŚŇo÷ŮKî‘K?ăČ&‹@ áÚµRőć8Sx‘+‡ŚcĆED|čÄ•füă4·U?.S–c…ż“I=äí”NĽi í¤2ŻbÇRkÜńş Zk$‰c–em LeScyyfŢŽ…­ ŕräÓx_‡č h—ů’bĆ.şbBówŠÇŻůŤANT‘Şź‹܉rć··č7ŔFS‚ĚßŐEĘíăhoŤő-á±y ÜĎ˝öýŹDŘčŃ@ŽŮĂăq¶ĺe$EŃĘ @Ćźt@ďw. #G_]†[1Ý Ešcňuđń`‰‡ćhcť$ţ;i JR¨t,¬†·—F‚.·í˘g6bţôc |O•ÖĐ®«"ťĆL<0ĹPO")Ž3UyN~·îčlJť¶V9 ĎŐămdî3b-DÜN(ĄÝD% ~/GL–âşÇţFţdăČąř8 IÇ“×0Z^Aşc{v$Âs '·x­O¬Ub…Áů7÷šHąË¸L¨D`-†ŠúĘ žßńĘ{9“CŐ“çmÔs–”;­6mđÜ.,.DŘącŞQ C W××|űAgÂŕQĽĆÇĐX˛€UśdĘR™\kƦ#şÇŹTřv%JL[IZ4–:ťŽ-Ëňź?účżüĺ»úőđýĎ^‘śGąfŔ˝_{ü«Ë+_™ťžęĎü%1‡±P©B·ÓBŞ ÷Ý{žyî9ĽůćQŚŞŠüR¶ń§­2çŐßžšĹÜÜiÜţç˙'ĎÎ!-[Ȳ>öîw˙™ńŹ{¸Bˇnĺúć„ë{ĹQ™AU&lüWh`0UIöDK@’°“)0YĽëÖ[‘¤ ř8knőěŮłálµ™ůË^ˇ€Dóďr$[‘ٵ ä5B—ÉÍ;Żuy§K&1üs›“vĐüÖXęözX[[˙ËżúüßüôíW˙hşEšŔŕ’ĘwĽzd®}Ç]Ş×ë|8K3kÁÇ;‰ŁśČĽY–`f¦Ź}Ď=ŤGyűŔŇĘT’ u9úłVy«Ť˘ŰGwŰvĽüü3xŕî; ’ĺÔ¬‹?iy%_?IŠSŠB¤Î<ŕaD í¸,0żŃÜ&‚ÄĎŚ?„ó5ĂăçCD@\7#yC¬ 3Ƹ\Ú(I°•·bžŞâ?ßrľLű­Ęĺ*›ýo<ŇâbúÖ’#˛"´âO (+SVý{Ă«ó°N4t’ ×ďÂX‹ĺĄUS{/v|)ŻŇ@č=Ó _>śađ*b'B¤A¦ ëłĘĚ\ąä- §2 އp}Oxćpű€O”3 Př˝˝“dTŚi“ ó^xAnĚltwŮí9F"ju÷~Ń: pŞ1Űu¦ˇˇÚí;!^’D‘“›ă~ţä=éHSĘ'ĽMmIµ1Íi „xá„äcQś•Dü[Ź~ť‰€F!ď ń˛¦ú˝€ O¤pňôiź ÓĘ‘ĚÎ@4!NżIÄż)ż6•[S>I‘«K@A3™–,Î&`»đrQŽĂhµJ,-W°&đ6Ek,µĘŇćYúĎďąëžźxđ‘§ţ›đs?vě’:yĺ;~ô™_Ü÷âCłłSď ŇŕHO–z•óLĺtľf§{xčâ±o=Ž×^Ăať§Hó‚UýíňneoĆX|öĂÜÉ“HŰ-diĆŢÇcŔo ×üsŔ€×ş#pDLP=—´¨ÖﰢȫPĹaOy‰?’ŽĎ7sD/›źBČ” DąĎRÎeTÎçľËí(x>6ýËŮN<>q9źßËN¬µN`*rŔ4ńńÉfdÂ=äŁŔZ'΢—@ýu˘ jQ0FvyÂ{mł°ĎT,iłc˘¤őĺwu¸Q@3ë _öL7` j\:Mşě‡Ö˝ŻRÚž4Ę }vűĆ۬Éwř?ˇOZ% SŹ]‡-Ňcíű(ăŕo$yó¨ €#Ó‹ĎúhĎqÇz\¬… €~Z©(ÚG4)B‹žDEďŇl÷Ü -ĚŻŁÁózăFdě]B’#4Yŕ¨'wč“B66Ö$)9‘ß×üŚÖ„c'N8 QłPp×l8` Ł!›uAY9 (‚MôV¬ţÂA@¬ő»`Í(ÚíĆTX[[‡1Q¦C“@‚m۶˙čÜÜÜK_ľçˇ_řđŻĽ˙‰ îäE”ď¸˙'`yeíá™™é>Ű+ t1ĐÖÝ[”zťwÝu'žxňŰxóđTĆ ÍK§îg;Ůëˇ7»ß~ěa<ůđĐ­6Ę~ß1F&h*˛*’Í×7Rî sbŰÓ&LÁ–el»g©(›ńmÔF䨢[ńűzeSň]^¨hĺŇ,ÇĚ”h5®ŚäüÝZ.\…w9Ťé*ˇŐjA“B’'h ‡´ó<>G˝‰8ą_Ńjٶśł^ŮęŔ'j X2jrQ߀ŔEF"§Ęý"u‹–&´ĺŁčş0ţ" ”ŚEQ´śÍ>ÝÖPQş‡j@Â!ÝţS1Łő›ä¤AמVĆČB¤˛ÉkŤ‰˙K÷c×5±Ů Hó̧1nÚôarq ÎtCŤ …>Ćc7GŃO•ńjxąŰř&4ć.řÖ¸quL7kîf´`Ř ˝2#?ư¬ţ?pđ ľď=ßS×`J_):|¦6žţúaqsîCúŔg(5LMŔéß[‰¶‚÷–˛|z¦<`mŽß9ʸąďb͡çţň/>Žßţí˙Zi,Ż®rJäř¤I×±©ééîňâŇž/ţÍúÍ_űů»/ŞÁ (WÜűŔ“¨mußôt/µĆ’Ëâď7,kZ­EŞpűíźÇS{źÁń'¤9ÇňgíŠn­Ţ (Őřô_ü9ĎžEÖë#MŮ»_ýÁS¤vsvGYTľw˛Č‚•÷ŢwGTÚGG<ĆÔŤŕk÷F6!˙G4˘©ČČ‚¬E˘ܰ{'>đëA™Ą€5¨FŚ©ąľsJŇ4ńㄯç,á^壕ÎŃŇ„_Yµ(€?â_Q JŔ ę$Ť}‰T€ĂŃô»żŤÁpxŐCă5–ĺ9>űýt:NhŤą3§1ŞF>Ő¬'ήoĆĽă¶wáĐÁ× u¸şµśAĽ^ĽzÖ=/faİđë>tŚ?e Ť5׾Šúm7lDu"@6⻉óĂżă·âő×_÷éYŤ©qĂ»¤‡_ÚÇçD†i¦Áő=’˘0DÎ˙ˇhµ±ľľ>6čc‰•„‰đkůţŤĎŇ8¶¶Ć;ŢńNĽţĆAč87Ť=÷{RqăV”e'đ;x€#ü*^5ňžüJľűÁŕ€č¨cţxiŻ ¸qńć ߦmĽEż…š…ţĹZ$ÂâŇ^9°ďľí6X|¸)Ě/,âÍ#GŘżEhÜUś@y^ Jţ őë˘% żsöB eá´fnYżp.Ř]b±Ö"M<řŕC Gřčoýô»,-­¸‘bPË&nż§V–—ďúěí÷ţîű‘_ţ‹+Ůż« ţćľoţcEösťnĎZÇacW i•%ČVř«OĎ<ű<ćΞ)…´h±ťżÓCŮ롻m'^Ű˙"ľ~÷W ň e·ëU«^ĺĺ¨Ä¸Ôď%Üâ`٠Ď% ĺ(ż«Ë˙îs·sa†&fĺUľ ˘¶=ă°Í0AŐ Üţig3.ó7ěÚŽ^«ĺŔÖůp±ţ˙1Ý,žřX×Ę9ʦ*˘÷ޤ€Ć}oőý\;±qÉžăÎóŰÍDŔ`X]ŮC:&  50ÖşÄMĆÖ ÍX‹Ł…ŐŐu€i^@N=ĘëMúi¬A–ĺîíÉ> &`aîeÇô/I ĎR’QŽheyNŕ"ëTî%ďĎ"Ľű§ăOnŹ90+qčD0¦FšçȋʙbŚ©‘d)@„ĽU°éĂ3TˇÜ*Ô-—ü_n%t<ĎQ;ÝSođMjň|ąBař ­č&c ˛ýŹ˘q—[ kY|ë°ŞyË!Úg~aO>ý f§¦ˇN<µĽ˛ŠŐµUW'ü˛Ë—ë…a3€ cťÄN€5af`,¬ë»×€ďgr+caŤuŁcü5o†»Be’v‘@8~ňö|ë[X__ĂoýÖď ×ëcii•A@c‡ v»–hőż|úö»Żűč‡ĺßRreR_5đ•{ůý<+>Ţé”aŚ,‡rpR Re™Ak‹Oú3xúŮ}ź_%ň˛…¬ÓFŮéˇŐźFkŞŹ{ďřŽĽţ*’vy–Átˇ‚­Ž§ö„NBďÔ8P&)ä˘0]Ż (bUL€ÓDŚÜ-Bďý/ízČĆŚe\n+$‰c[…$(EHÓyžŁU–PÄńíµ ·á4®V6küKş…)źlü{hkśöÄě›ŘfôcŁNB 8ŃXűź•4ATŁÂńe?Ţ»ąW›;÷˝¨ŞËękđVuYXäE‰ŢÔ4Zíz˝.’,C»ÝĹ6pËÚp‚nżçěŰ.şD¬cîĆĚnߎőőuw°Ľ¤¬Aţî—0w°ť–&Á r'äaBžĺ6ŘǀШ›MsűzXábúď _§ÜŁÔ¶ĆĚô Ö×Ö ]Ľľ±5¦¦ú hÔ;v:``ýţ‹×6ľĎˇ-c Š˘D{°TÓ‚Ś[÷Đfž¬GcĘŚ©1ŐźÂöíŰ]˙ť–Đóę&öZsůÝ,3gŮ eÖú)wÔöËFży`ÇdżË{ĹX4Őďc۶mHś@âßß™Q¬áů”Ăz·˝´ë±‘ń0܆äs0|ôt»Uşf¦[W–,ÚíZ­6gIuŻ!Ń^p÷??J„dTĆ`Ş×ÇöíŰ#çj8Ćď”÷|–EYčözHň°50˛ĐiŠ˘(p%ĘVćD @gÎĚ-ŕ‰'źB]×ř§˙ěwŃév±˛Ě Ŕ‚‚ź'ČXj·[V©äĎ>űĹ»§¬µJWŕ«îľĎoĺYńńV«pĚ_Đš f–üË"Cš(|ęSźÄÓOďĂÜâ<’,G^Š­żŹÖĚ,ęŞÂ'>öŘ.Úëł#ś“đc‡>ŃXj:ďřĎޡą0DËm::áYqě|KŽi“—ř…Ňrv?!¤Nťĺ®1ťkV$9x‘š%*k8^Ú’sK4RwDq˘꺆5’Řw‰K†Ś1äq4™;7o‰G` ń®•ůŹ4ďkŃ»ńż!<ďMý+Um’Ęů”ń„Ińď—R8G‚ĹÂÂ"tJ‘&,ľiň÷-1Ń„.)xŐĽżąi›1Ń÷~*ěLąßřUę+FCţ·aŤ7úFaź.ňÝ&ě"÷]ŤMh´ď6ýnşkÓ3Bˇ€´Ă+çlŕ Őü«Đ0'!ünä«j`éXxť÷­Y &C"@G÷řĄĆ đüQąÔ·Ć9/:ĹDóX"–0ɤ%»©DY0t`çľž)rŇ3ŔÖÍZ?sÚśđťC“ÝřÔnü"RšĄyśĽJÖśkmńăd˝G˙ćó14ÉÜx-&ąó A†‹<>˝\\tRN•‰ľÖ ěőAŐ‹Ë+xjďÓ°ö?ă÷~÷Đé´°Ľ˛ĆÉ“"AĎí j•ą%Ő˙Wźąýž5˙Ëeęş/WÜs˙·>śfÉ_µŰ%«ý#đ˛L㓟üK<óěs8ł°€4Í9ĽŻĂţýŰqřĐA“=MQ‡8szGŹfG8wŽĎŃ®ťÓ)‚×{mj”E'ŽNu~Ů G¶ĹŘI”™c” 6ŇU—EőŤAđ´ >A–Ż-„ţ…ńWŤé—ýhŚA»ŐĆ©Ó'Ů[źc,’î4…S§O75îéÍö) ę_Ń*±±ľµOŤg)úŻqOăĎxçů5ťNgĎÎŤi7ď‚ࡠ&Ŕ¦ĎőőőćţńĄąŮĆqţÖő2B©¬EŻŰĹéą9$¤<3lT×ëü±’:6I@«,±¶ľúßĐĆmČ×k&ßn˝numĐďq˙µ˘đ¬h##$°ď–VW°Ľ|ë@mQD+ ›Fí|ËVQBç˘ ÖXt¦·Á¬Ż—W±÷ég˙ňqüţü ´[V×Öąß‚6‡Ę<·¶Óţź?ó×w­~ôţę˙~ŃťźP®(¸ďÇQiőĄN»m­µÖ %óĺíVO|â?cď3Ďáě‡çž}sóg‘¤˛vEŻŹöô,şÓ3řâç?…łguzHÓ’8Ebs…N(Ąť*=0\gö‹4Bac{˝›ÜČ0HúĽD(šýŚ?–ĆDĘ! ޶dDÜ÷čłsöf2L;ž¦)’,k0w¸öŁ?[jÜpn˘IÍO ŘüťTŰůthëľÄWΫÚ˘-ÔAB9oŢE•hB˘ŁăH+Lu;řˇďy¶ÍÎ"Mh—@­ď‚ÉĹZ‹ţÔ~0’ÚÝ»z™Ş©¶ß˛PtoD¨µJP>/!¨¶ḟZ˝ĺ»7™‹ďżŹĄŰn :|c`złuën§Ţ˘ß4bI˛q«A˘3TőhSă5ÚĆ:Šçi3sőµ‹éé)Ěßxý¦Ľ;Qö€M}Ţz°h죅NRÔî´Ŕó.ęólâŹ3ý>Î^·=ŇsŐ»ĺPĐ„ß'I†Q=„w·ô4bRK[©ŤŤÖî˙Ť»}öČńîzéÜ-Ň…ĺU,¬,am}ÖT®¶xRÎ\ MPPHËŠ>˙©˙„őőue*Iřs—|ĐeÖÚ䎻ąg÷®3^…ćeeŔFĚ®Ý.p`˙‹řęWż†#ÇŽTÂj˙^í™Y¤E‰Ď~ň˙EU×(ĘVpöóR?3RöPîŘjď~ŰöĘźżŰ1&Ż"éŁA{?ö <6HL¸çBć¸&1—lZţąč~ď»Ň0ż«‡!ľ C°Ş•|ßáMţż€w7XźFá’jüűm`Mă%-ĹRE·ÄĐĎFŹ;t‹ŔÍ©©9l60ţqňMčżb±–ç ˙%‚Ö 2­pý®ťPZˇŞFr˛/4)(cŘge(±Ö"ÍjŚFŁÍ JľŃ2c©äąđËÄZ­a݉‰Ŕę– Z Í`ŚÉj‚ĚŚę¦$fŞ–€‘;@ĆŻ¤I*­IE´lPZą°Ş‹/ç‚?ş®1¨k žĐ ÄL?Đć“Z śTkÍ)sϵ4'päs‚dyĚZ « ŁŃ¨ ś&,Ą°îj~Żq: +0~Ö´áh‰MÂDt…îY^8uřMhBxŐ0–u]cTŐA+Šh™F Ú ěś™Ćú`­4Rtʸ‘ŔŽŻ|áŻđ«ţGčmßéßi}Ńŕ؉Óx䡇°sç.üÄű~ ó‹ )PgIä%çĚź={ď·ź9đŢ˙áwť˝”ľ^vđĺ»ţóť;¶˙xs‚ÂąĎÂd˛4Áh°ŽĎ}ţóxóÍèIˇč´Qö¦Đ™™iŤĎý)…˛lą´©Ěxă>^˝ďľ{‰ÎŰŐŃ`ţ„ČăÖ3ńXĆR?Âd†xjŐ¸WâđĽr IDATč”rN±6Ŕ/T7y^éJźlq¦˛FÂŽ#ö—˝:+Ň,â˝°y‡ě^ţÍÝ­Mkż\Ć5ľq›7Č~Ź˙&éu; źĆ &=7ťěĽ5Öńńđ˛ ,§ ˝W¦ĆěÔ¦ú}ŞFĄ4¨Ş,VP5Ářśřáy ‹jdPŐŐ„>DcC·î­‡_[÷ÝśAÍDYáż-ÖŔ–?lb¤@5ˇŐŃBµi¦ţC7Rß&2A31Î^•e 4Ľo¸/ŚY ȱôşe±áO’$‡c}ŁĆ˝Ń‰ăW'7®+Ú§Áx‹Gâľť{b·¦Ă†Uĺ™çV7N\^Vh€Âž»R—I’€Řę+¦$lţ*Ź@…'Sc3ilí’,lsnůľđÔt݇Ă'OŁÝja¸¸¸ĺř\®2ÉŹČZäT˘q×?‡đ+Boű.Ţ›ĆbmqŻ>Š;îřnľůtűłX_řM!\ś@€MMMď:p`˙—¬µ?ODŤl.+¸óîoţÓ^żűű|úÓçk–Ä „‘nż×ÁÇ?ţ1ĽńćQ j˛ŰCŮíŁ==K _üô_:AQógĎg>?śÜçůŹ3L‘NäÔ)÷ HT÷–Í1ăĚÚň# ćďŢŹ3­E>"%ű…î¶ŤÚłđ§lÁńqö¸W›ěţ1`qŁ›÷Ő0äĹe 1‘·Â7éäew»ŕ xÇa3ůÁRôcÔ7÷iÜ1IĄ”CʍÖ8±#ň˘q‰]¤_ÍúƤ­Qp?Ńxg.¬Ä;ŽĐ8ßRU#´Ęvoß"bI¸’ő[Ă(NaJDîěó1iş¨P9 hrBj›ĂIcĆĽ™° ·Ž$8;>AÚŚęŠŰŠWŤ“Qf1ŚmôÖ˘v {4ů¶&B´ń#>+µ1n|řzĽüE-ܨ&b6çśMw_VUFýśpŰE,Ż0JĆÎç±™K†rNMË9€µČŇ Ăa°17iM\mžÓĆ!Eá>ß{"$Ö˘256ţĆ×^$d5j‰ëôt—M:ÖňÜŽŽ#¬âżîe}}Šۧú‡Hí_ď\®RÎËŹČŃť,Í0´ŔwßüŇŻˇ»mGp™kK‹8tř>ó™OáŹ˙řÂhÄ{Ý‹Ľ#É~"LOĎü˝ĎŢ~÷żđ'Ű˙Ëö|űů›V–×?Ţj·¬5–|Η¦Ó+‰P–žx|ö˝đ–×V‘µZěí?= ť¦řëĎ|Рʲ Ě_Ĺ’żś"Ć˙¶bţ“ě»Î–©hdÂřş <6J¬óiyó—'‡9 ĺ -Á«ń4FÄř9<0€›Ć~´ÖeţcD›:H(ź«Çďgőá~äęŹ$<—Ž"" 6bâiűq jlrB„ ĺCÔN˝j+"äă{rśÉ†.DbY|͆›lôž‚,,&´ąŚoěó÷DeYbzş‡nŻŞŞ\Č›“z#GUpŁ;YoUePUUx׉­‹Éhl<Ą’1âWŁ,«Yc¦Ŕ 4‘•ę"IpŚ…ŽűúŮ/«FGa\¬Á(qyńGޱú.ÚhÝ7ĄjřVÉ3z€‹ŞSA[ŰéiČŇ6†wwÂ×o­Ĺ0I0Ř:S\ü‚@# ĎĤQˇ ÓgŮ!ş6U“ŁťsąmžŹ­náńb06Ö%&ŤŻ”MŻ &ţ(t¸ył0I‚Ş®Pú× ‘ˇ‰ńYő!¤ňÜŘ3˛ţ}ÝQ}2 Ds«ť7{];uí˘…ŐőŤ¦ pž@`Rxđů9šźe†ľńŐ»đ żöčlŰŽÚÔ0µÁÚĘ"öď?€{ďů ~á—~ óóK¨ŤĎš„U( ˇÄ–eë_}ń+Üů›úů‡ĎďMšĺ˛€3§ć?»űú]‰5¶±P±„ÜĚiŞ1đĄ;ľŚSgÎ"Érť>ÚSÓČĘ·ö/ĄůkĹĚźĆŐţމ‚ µ!ůSRšĚ?îj ?‘„âšIť•?ś˙oÖIăńbđŘ@ą0°pbB'‚Oĺŕ ŘÜĆZp–YÉŇĹ9ôçđ>mÖ1šdufLDAbm5× 6ńeFĐ xSW’žŽő†=&^lšžś18Sď>^ă `ď®%”ű ˝§]‰B~AP2€Ć{cůË‚Ż˛E‘썞\űü J«“]“Eú•ęŢxö&”\h$NHj4K„’ćÁĘ&“R˝ť ±Q\w+ëĄŘnĽÓçţłĺ(Îü{słsX\XŔâBţÇ“*JüÁś4𮑏·Í5‰HhfqÓ`Ëe7ęČŤyŔvŁŻ‡9y6žŘĚCůČ4ËŠ2'Jz"hhš@lĹö„kĎBŤ(I˘ň—?˝„Jç•°>nŚĆă$YÚÖ*;‡Ű}Ľ‹c÷Â;†ůŮ`ŘÉeqâżcMŔ -µţv)€B_1ăĎ˙ôOđcóťXŘ{šńgÇ~â(ţčŹţ˙Őżüo1:~:iĺĚVzČ\ČíZZşîë_űĘŻř•ífë‚ ŔgvÝß˝˙vffĆ\8µłČ×űuŻĆŕ߼«Łó‹[Ú…Ą+ŻĆÇ>ü˙b2ž ?3­űE›řPó»Dz^?ÝěŰQrp_şŔźRÜÁŻ–'IţÎĄ5tJ /2e@™˘ě‚ć)üN¶ýcüö^ův»Ž%ćeL*Q„`â=zžŐ–%Č"‡L8™!Í!vďA$Ň“™*´ ¤“}šźí$ăŇ=Y‰ŁŹĐÖ3ěđÖ<ćgżő¬DšČ’‰€ NWĆ^(ŕ·\l;G„şrčő{ ó¸b×.€őކ¦i0ˇIĘžsaŚxWĄ¶°ůböđ“±ŮŢyŹś¬˘#'‘NH•Ô §n!4“Ş­±đjA?>‘f3`–0M&ĎôÓc<™`<Ą>ČŢűAňźdK0š,É‹$NÎɬ“33cR‡%€l»+ˇHy1‰t-'Ąź¦.ÝÇúh¨BNLˇ±m|ËäÁ;XŚŢd‚qÓdc wÔţ™-çl@ŃďGSjL] óIö(ĚřIý”Ďs1L—$¨m’XJaKÁ0ťz‰dn–÷rL çQ<ée4ż,c މřŚ)ţö±Łî^XÄĘÚ@]Eăqr¤śy#ŢuÁNćoI Ł×ëc2á“˙3üŘß|šáÍxŚŐĺSxđŔ|éK_Ä _đb¬®űl|•š×ŞŞxvvćź|ô/>˙»·ţč÷Ý˝ť|]0¸ó›ßüőëŻß7/@ĎL ś`Ѱ´°€˙~§—WPő]\ÂŇ•WăK·ËË˨ű}ÔµůŃÎ źA&µ)×N9V0ĽÍ@ ţ °µ,°Ž(SÁřÍÔń9Ú™ ;Áša«ŕglŰ~Ďß Vµt€lŇLâĺ1Yäf1§1Rť~M]©4ťdíĽ>ł2ÚxR E*šď+ĺá»Çťh/tâIńe“cěkĚ&×Ö…-ű¤/î´“¶sŞŞB]Őč÷ú¨«ósóXź‡Łń ß0|ăŃ8j|Ľ 5rvÜÄ<¶µ„ÉDö|Čóéů‘/éZV C”–unW‹¶ĺe}U|xŽGŇĽĆ#ŘeűÇŚX0eŔ˘ d2™`4n”pٳ“I[ —(f;ĆšÁŤd!}4†ő•c»’›Fb ĄĎ·ý2Ł†Ăˇqh¸T×čvĹV„N·^€~;.šÚŢ’•,MËâ™1Xbm}=őź„űŃO6ť‘ÎJ©»‰+cŽârU|?žÄ#ž.Ţ» — d‚=“4kÚbĂ%Ş˘Ôűpőą«*‰@ďoI÷ ŘĄFBĂżgě^\Ŕé•Ô˝úu=!¤yŮIץA¬BD®Âx2Áç>óWřţ×˝ăń:ĆŁN-źĹ‡?ü'xĹ+^…őŃ8muBŽM›1çpěÄń˙ ŔŹn'ŹDîřĘ}7ś;·ň>çĂ›UÁ0>‘Ž]Q|đ~<đŕ·1öł»wan÷8tđ¸o?ŞÁ ú˝ěF(—:LB&r•ôu÷=q2xÚ’ É…A­ě4Ě1ü[ĂBą¤nkF.ŰP #5>ěÜiX¬âBkB>ĺúßpĄtqű”gć%>ßž]˛Í%ň=ykOED:Kô9`×­łw@2IęѶ«ź?.ź‡ZňQKĽÁ’ Ň9<ĽîicŮy+łđ&®kĎ€ć—ŕŞ*€^ŤAÓ`<âôGpßÚ zý>ú˝ę^˝şFUU¨\4GŹN†9­ă b ÄТQž×ěw§?Vi×8é3Ő؆ʼ šjw$s‘cÇđĄ/ŢŽĽč%ćŞ÷8ßexzâěÜěŹüɇ?ńşwľýM[ŢxAŕčŃŁ˙ý 7\0;#53«)ĐŞóółř‹O|««ëčÍÎcniŚŰ?ý  îˇ? Ś.;ëŹT‰~Vµk:Zř3 Lm©µ°Fâ1IŢkgl?Eb’=KäH٧ Ă€EŰýDIÂďüňě9Ĺ2{FÜLćÍ}𬞦lÇ6LźM9Íě ˇFM&,ÔIĄwEŢ€ÖĺCFŻd$>‘źÜňIIňĎ*ČçDÂĆ–Źt8;¸»Ž:r¨śCŻ®1čő±ľ¶ŽáŮe˙Ňĺ„ň0Îź©[˘€â»Ľ× µB‘ůmŔ˝¬G×úĺSůDx`s›áăŹ?Žš=uU%{¨3¦».ŔßlĹkć™ĂFަiŇ)+"BU׸ç›_Ç•W]‹ů]{0Z_ĹĘę>öńŹâ{_őZŚF§tIIĺjÍ€…ąy_=ţ?xÝ– ‚ ßşű±+Ź}âg™ő0b3±‡3ä  &‡łËËřúťwbBs Xşň|ě#ŞÁL}s±I|$×U– Îş“4bs·ĘZŮh6qKGí˙P˘Řhůn× “ŢC_ĆćCóÂą¶˘Đ"ŘŰĆt`Ë`xBZź ÍC‹É™4’ÁííÚ—pAŰ+ )ç[Zf™L M@OęßćCžs=Ćb=.× ¨»T–pĺ ÜRM¦ČĚM; 8Í ŔĚ`€µ~żń[ż…cÇŽc4b4ž`Ň4`Ž›8Í:y^¦˛­Ç›ů3=}ËQ\¬Ľt˝Ř<Şmäz;,I·qÜz¶1I›šôňÓĘĹö©;Ć BâÔzvÁÉoˇ˝e?OÎ®Š€[Ŕ2ź;'ÄĽBżîăç~ć§1™4,ÔčUU äYšÓÝůnffŚÇŁt× ˛z‚ÉőűřümŤ7żőť®­by4ÂÁÇÇo?€+®ĽcŻV"­ň–e^gÂĚěĚ|řŁźúž·ßú†ŻnĄŽÎ›Ü÷Ŕ·ńY7ÝH^@źŁ$ %pŕQő+ÜöéĎbÜ0złs۵÷Ýs'Îť=‹Şßg˘éu¨"ť; Ůő'U/Z .Ya¤*}›]őĺů‘ś-¦5st…iď9Ł> ‹*[DHuëÁ­ĎG…·‘żŽUnŁś_\Ä3o¸kk«XO‚ܦ÷ Źţ[bµ‘ky‘Îiźmg¦•>QŞ++ÓňGżîömâ4O·….Úď[.‹vűŐ5ßTC¶ăî|ó˝%gű‡Y8ˇ®÷—"é’vą®şčĐť™vK&Ö]°ţZU˝ŞBż®1?;‹oś>Ž€ž´Ë›řÎŰŮëéMśař‰ýđđ÷ᦛž™Ĺ%¬ŚÖqÇ—ľ„wżű=X[[‹%Rčt+Uá8hÝ{˝Ţ;n˙ú{_{Ës7˝'ŕĽŔG>vŰk®ĽrďőzÜ,dI'[""‰S'ńč㏣š™Ăâž=řÜg˙ ¨jôűýx»]”|Łużxey P“nÔĹ!9Đ €:ä`¬.nęs”…Mě ¶/ćZT­żc—‡AžG0§#(yŢŘ”›Ň’J8v(ĘhĽŹĆ€d÷«¤‘OHAęŹďŔ\ĂC—»‹%ňĹä.zö|ť/EBą± Ů4ÖŇF(ĄM)Fo;xŽO†FdŁ ×yŘ'ŇV¶;uößş´‘Ŕsžý,Ôu…Ůą9ô›Ť÷qăfÜ-ߩޏŔ<\,Ľ¸X‰ěHT±ĐD˝ z¸ůN$u ó˝ŁÉç¨HQšp–dźNEŔMĎ|&=~đÂÁ}g—ó95×h'ÁĐ9¸^wÜţüđߌáę έťĂ}÷߇kŻŢWnń1qÇOĚĎÍ×?pĎOř?6Ëßů-0˙ÔÂü‚Ń:JEÇ*ŹKŚPéűď˝®×Con§—OáćA˝>Şş‡ ő#MţIę4Ť’©Mm0ŇVő/gíeBΧÚ`–Ş{ŮxaIQ˘$ lr4Ä'ĹŁ)JĂKgD’ěCćěő–4mŚÝs;#%«šx PÔIÜ’\Jv îĘŁ$ „}źôďąZĽ´–f×µ„lwÜ©›q‰TF ZŽ&‹GJ*%#ĐY'¤ĂYÚ©©Ír·ěąxž07;‡«®ş ăń8h"Qc¨UĽ-«Ť7OńIĹ“Ű]ä>-ęď;Xޤw:7‚a©ŮpĂő×áđáCńd•XÎßu/'ޙӀQT¬`™×Sf1ŽpđŕŁXś[ÄÚx„»ď˝×_wC0ÔeÓC!›9 Wő¸ßď˙ř»~ňű~çď˙ü†Ͷ Ŕ×>żż:ş¶ňŠöWäMäF0 kâa"îőjÜsď˝@ÝĂÂŇ|ęŻ?Ô5z˝~TűRjś€;ś=h˛Ý¦ÚŐq˛ !1—î­D_T–¦R>9›ťĺJ6 aIépŇhäě/~)ÔIů˛‚= żuIeÍŤlL–ăŘl€•8ÝĄźď Ć| 9µz©ŇR<ËäyłÄ*'qó¦JҸ”›@l¸ëŇQŠÇţŠéŞŔ)LëHž !$ą^g§]X×óxćM7Ěáźh¬Di˛cŔ˙tsÔËÔĄ…-LŘç[ÝOP˙d”žBŐÓv3÷3ă7>{Î]Ŕń ”T÷r˘L„]{Ęňĺg!á(üţ»ľ7˝éVŚVĎâžűîĂ­ă-Á’f)ŕˇĐ‚©rőţň?üí]|˙ËNo”çí:˛rć†ŮąŮëS˛IH#ă4X9˛š^]ăˇGEÝźÁ©ÓÇqöô)PÝCU×Đ5  ń3i2™±%ýŰúa©]&xńÇQ}Ž^7óÉŃ—€PÎÚ-”$P –-b’©ýThŔ€ż,E$żi˝5//$Ó%•2Çr2‡s­˛ ť,%ĐÝýlëÔkZQ:VWPNZĹy/Ůa5Ľ#± i‚0ŚVČČ(ë#aI×-Źh ÄĄĆQK©ŽB“!uË@˛= ©J˝e7íÜ×1@ĚÎâĘ+ö&›ýËŮmĹ]„zş\ő—]éŇdŸţş}8xđ±óڦ=t/'¨¤‚ˇhćŞp,PI@3ipčĐAĚfńíGAż×Kň3¬áFc 8$53;CŹ|äű|tŁ2l[pćĚňŻąö0ű$]‹ś   tŚ•@¨z=ljQŇbăD'i ɶ¨W!O`dެh[ŔáüŞě{3L5µLÝFŞ &)_· sžW1‡›44Úo’&€M&oĚô·˛ApšóŢăŮĎĽ)ZíĘÍ>_v—Ýe÷$qf|O&Üxă3pđ±G7ßĆ~n}‘ťďÍ’6ëÄťöEĹI‹pß}wăľ˙ő8rę8Nž:e´Đ:R‘30ĚŔ9÷F“Ç]ąÚ 4ť}EŻ×OöŚÁwĘGŐ­€wd˧Ϡ‰ÚcŹ= šé?‚oZ‡‡ö¶Ľ´–ݤ-(Tж+YT°˛áÎJ˙â$l’¬ńö]4`Ă’F̆ éÉoɧŹr°çV^“6ĂÄ•—Íg~5/š.{¤|?ą?)žZŃľ’ŇŠů¶m´ç˝ÇŤ7ޤ˙Ëěž.hnśú~Gđż…H IDATŽ’Î+]Ú|i €ŞÂcŹ=ŚŢ`€“§NjXŤ6)pí¶+€©vî»ţáß˙ĄľńŢrŰŇĽđ…/ěőűýë‰I.¦hß8Wł¶%yTÔ#Ľ]_×Ř4Hą,vĺőżĘűń[FŢRţ‘VcB}ÄKh”hĹHdC%ÉĆA}n\"@±úă&ľLi»‰†"«6Ѥz&CÎG…·±«{=ěÚµ”1üËěžnßµ×âŕÁm‹0!×bŰůG„Źr.ˇňđáÇń웞Őőa~'€Ä#¤žŹiŇľ}7=gŔŞͤç­™¶ÝľńGfě šŠ°i!]$¶Ě%TśŘ›ÉľăÜé“@&iTA›`#%!»ŮKÎ7÷9ŰA{r"řÇĘŇť˙qß@˛ČAשÚ=_6Č`ŘÜÂGa)Ü^¶ ` AľxHË*)d$"-öhęž›$qkݱ.d÷ůzCrŐx{Ç}(ł§H,Ä^µí y"É·Qßd3 RZBR"‘ńěÜ5e Ľc] ‚ʱĽ|Łń0Ópë>6¤ů—MU]anv~€3@Ú#ą­j€[š]śu®ŞÓ“°ŞĘ'×ţBěÔ…ĚĎ fđÄŃŁ@Ő+ě-‡Mo!*Ý%žŚ·@)>­“hÍ"ˇ[UM¨,—nĄ ŢŁšť@Lý_.Y÷›"Ć+‰3Á™"܉f"5 {×B'(7…Ů}Ň;BŇş÷€cťÚŰáˇă4 ‘m‡Rň"ŔRç†zYđUĺCĘO˘†Ř č\F–Ś•ÎĄ5SłS (%¦Ô:’B,BXŢX5—D#ŻđŻG–‹RűꝲçĺJ`—ÁčśĂĚĚ x^v—Ýe÷dw"…ďŢ˝Gžx˘uQŮv\מk/Ą˝´]g+ĽEWŐ8~ň8ćff“ßr.Ęľ#@@UUއű<Šüš°”Ŕf I˙ęµőáL]E«|Ip•ÍQv“3Ŕ„…ůś8yĎD[Ä $*ŚśbÁHě­B˛ťü-!ŕtwtąŢ 5âăśś‚,IRtŇĆ@nU®,ůČ–(˘†‚Ĺ@ą¸9Q`@IZ¨ă™:ÖMZűöhšÚëKĚFOb„'ľ‡h,bŞÉÎh$Ä›´¬ÖBIBČŻăAżÓ®˙ €€⤠ń)2CăńBÉ‹W"Ď|ŇÖtÉ”‹m1Ôä}˘Ř®ł[Ę!ämffMnůz*»ď4qůN§˙Tv| őtH'Üh4ÂâÂVWW;ćßnWJ䦄Ťł/—*Rv†0DŔÉ“'±¸¸4•8äÁÂ\ę*‡ĆOŽ>ůř—Úę€P­¬žë‹¤+Ö‹3IĄ˛¨1v--aĺě˛Nŕ" g*ů>Lî. Äv˝U/(ë‘7BřÔŰ–Ä Ú' 1 ˇ”Xi˛˘AÇ]ž^FbĚÍN nN÷ä)s&FS #ÇýŘGµ•÷ńE!’„‘ó#§÷©t±lŤ«ŁÔíĘeÉ—„±ę‚XD"ŠfüĄ˝ŘF8[.P­‡DŐX“ƬíŔŇ©R[m´ˇ¤˛!4Âż&‘őÍÜfŰ9öłPČĎúúz¸Ęzʤq!ŕ¶YŘó‰{;a.´L[ńw1Ęxľn;i]JŕŰJZ›ůŮj~7ň·q\ě´Ď'ěx<ŽEčŐ5ęZᱥÖG>/ŘĎí:»gÍł‡h¦5»„őłg07; ŹTwi#e~!Ň9Âh4šCŔůÇł]Ę[Ń8Q;zÄ5M°ÝSRo©š K Ż™°´¸„ńŃ'€={˘ÔČş˛¨ĆĂüMqóXT°LŢÜ\wĺÉ^@IA!©›UWÜR˙—R·űŮ1émwiçixÉw”ú],wŠĂúi±Eł,Q0D©Sa7}Ăa­ždÝ]‰JZT‘|F$U ·ëóĐct4…ęÜ.Íčw!Ię‰Ó[a­ZÍĹ:Ş.őaí ¤”Č,!µ~]GË ŤLiKéjÂîł&eĺ<6ˇ®kTU…ɤ0Ćąsç23Ô]a6ú˝Ů»i*żňwąŃ´Ëߴ劮4ş6Żn'o›=ŰJ˝lőŮFď·ZßŰ™2Îia»žźX—Ď6úÝőnŁü–iůĚn@ŰHÝÎo?eLn%Źç›¦}fË)ZĽşŞ0©ëD襌tĐĚó:M‘â-F‰ŽÂţ˘hR<ëŻňŰ„ VĆŮ3Ë„€óđOč lLČ|:ő‘ĂŹ;ßȦłÉT-!ĎëÁI3Áî›nÂé3g0™Lŕ\LdS]X‚ěŞA`Ú`VI±«Ň "Čş¶ŕ‹zŹęřX˘öŠJĎz$1¶DÔNP,[Dń”n !¶Ę$™¨†' o– "ÓÔÜq¶öo3¦ĎbÚĐc~Ť'ú?Xú3—Ĺh‰VAűE«SÚ1­DÓűF˝N˛Ô­řQÔ0EݧtbŮYĘ›“0{BŔ›6&pĐ(„e Ę– epJ‘¤aÓ‡é6!˝óŘâg<™±¶¶†¦i¦k׳ťü˝€Ý(ěVŇŘŞF`«ńnöĽLwŁx7ZÝJú[}/iťĎ{»ĽY¸íüVo‡\”źÓŢo%îia6Ëß´p˛$'íľŐpDÔ"Î…ë‚%ýŤĆôVÝ´SI@é*‡k®¸ ËçÎś•¸í^ŞřŠĂńçSgN@á$€ŘH n¦pńŻĐ»{˙ťX][‹p­6Ŕ€c7/ČD6¦ŤĆcĽä/Âm_ř<=š-C)Dö«* śCUŐÁ¦şLŔľ4[k*IúOO!µ¤ßşťíTÁ^­1d&˘ÔÁ¤Â đHŁPT!(wPÖ)ÇÉg$›Žh B@:&3¸axxS—rŢx˘´Ű_xM*»­ ąŤ1ů‰µÄ¦Ö(,qČ:}ş­Ě‘ľ˘5Î6ř'•˝íĚf©!-ą$RKĐľ`4 ÖfB>¸(î¸0ŁŇ'š¦Áh4Ę&ٰ]5ĺN€Ń…JĂŰ©ťđ»Ůó® űBó˛]·QÜŰiăíö‡ Uőo˛ŰÍĎVŔ}ŁwçŁůŘČĎvňłťxĐŢĂá@#Ö××QŘÉ~¶eĐŹŽ™qÝMĎó ë3™l;—‚ú}t‚@*DC»6îÍ4]čť;·ę–Ďž @AŐʤFxdŁJŕ„ńh„×~ď«qŰç? Ä5;ń¦Ěłšńa‘" őÄŤDW’ŕȡŞ+U¨"Yp•‰ˇ!R. űá!‡ÚRË{¤ęc©§”WČŽ˘’Ň„…śl6ĺARФ@dt©`0ÇË” ÚŽŕëěň‚şŔâ=Îě꣒G ’,hö¸hvZP*ޢř Ń X˙ ©Á"©!śęM HRĺ›ewńĚ= ŕ…ŐÝ–¶†–ۦܥ^ŁH‚Áˇ dň1ŢÉd‚ĺĺeTU0-¬G2/ŤŰîÄ'n«’­âÖä˛Ă {1Ërˇil×íT:+żçÓG·’—­¶ĹFýçRµŃ´´ş–.dLoDĶEńň—ÜŚőŃzŘŔ9¶t©˙`mm'Ž€>ÖWł|˛ °Ő=µDrüر(­6FÚŠ“yÚ@)0ń†×Ľ˙ć_˙*°¸”UČFť&Sëi€¨d&<›čŐĽ¶2€ĘUAરäP98WÁ9‚suÔ8Á>€e–µë¨/—ŔI0MŐ¨öë5”J˛!Éžc㑉ÓJÄĚĹňBöŤo@ŢŞÄĺX%–di@Čqx±… â´4QOAdé$‚´çd!mŞ„´»íńŽt €j ŠűµÂ|j{§R{(ĢHţ,ń±9–i6w&†ę ńľ˝ f›Îj¬&ëbN^O5đz˛¤uąŢžÜé—*­§SűLKKľ_¬´şćűą•°ÖĹ rŚĂ­oxÍ+ľĂáXŤ¬%yPöWiśŇ¦ÇŹĂÚęZą€`fÁÍ–d@…@‡Ćhüăö>đ`6sőX–9›łÂ¦:JŤĹ`6Ç3?Čž[píŔô˘wĄĄCňŢMcŚé·-ë;í\HźÖ\¤¤ëyžÄ#)1´ź4ř5‚ČMłŇ8ĐÝ%Ëu.ÝUŚ]8óśBťVńŽ… %’yE É$ÔOČ,ěĆ2›řEZOŚ-¶%š†DDµŤ­mmÁ_Ť2 )ĐxY´ ®ňÔ›D¦¤W~:©X/kG¶÷ÓĄ}6KKŇy*‘•ęĹöŮ·Ú*óM§ł÷ř/ŢńN¬®­†“čĹş¬=`—Ľ~řüx pŘ»‡đ@-Čg]¨ŚG}'OžÄ•WîEÓŠŠfw;72ăí?öVü7˙óŻbeĺ¬Jú ’q(Ýqď:;»sÚ5©Đ‡©˘ÔXmBެŢ9´=… X€äě]áč~&‘ÇpŚxĎ˝Xw´Ä+ŘzHPH"ůĘz˙šVÚĘAÚô)—I 0ě7´ Á„p ÎąĐIŢIúJ,Ň1L§űF\<IA60şXƬŽXH&âMX,żňkĎެ±=µ&‘˙?ŞX/kGşă~şµĎw’Äśď:ţFqw–…TŢɱ'<•ľŹW°7Ťš Ţyë­đM“-ŕ¦=rvţˇ‹QłŽ‡y8Ü?Ăľ†J˙B’ŰŞŐ0°rnwݵŻĂëá\U®€Ü’ód&—‚T{öÜ ~ý_ţwř'˙ü—™Ů®ęC`H!ľ|Ŕ‚3RxąÖ­íĹk}»ýxŔ°VúÚ„az%YMC"/ÜA "ˇ)ŹllDZé,Ţ{4žÁěŚx6ŢůüŠ_2Ú…t˛)_üęXŽAꀳ݋Ç[‰áĹŢ@'ź”ž=ÚG©ň´it͟Ʉ¤ŚŽ¤#š|8J·I’¤AJdIJ˘Ý©Ę™ŕo4nŇ2Ŕ…ş§ üR¦őtÖŽ<HĚĄlź'‰ąĐuü2= ]–áh pŽ™;˙ŁďńďřŰhź"Š¸Â ˛:q2@áđ‘C8uňDŔŠü©ř›ŞŁ×""Y}ó›ßÄp}*MŠ$%¸č/˝t °Ç;Ţü6\÷Śg‚ąI•¦ŵérýßú•ď˛ ĐŐá;Z­tyĺwżW€Ď;”€wŮw7K;˙M­N›â§˘ń™¦ńh8RňŢŁá°cT~űƇ{ĽGíSÂá Ǹä{¸g ŚđĂsŚŰ›¸mZ±ăJľ$Ž ­`x°f<r\´č“<žâ‰‡¸Ö¤ň644Í“If2Áx2Áx<Ł1FŁFÆëCچC ×Ö1\[Çúú¸ł-¦ąrňňeźďô$oÓ±i\ rŃU¦‹”@ŰXŇN¤łŐöŮ1unńýbĄ%i<ŐŰçR¦u©Ú§ÄŁŤÚ‡pzy9,§rą ąČŻ,›łGUWř‰·Ľ Mă5_ůç~Á…x Ö-`+ů—K;+K`'Râá#Oŕţ rd+i€H¨DX9wż˙›˙8·Ž5HbdŕMÖ~ă?ÄvĂIŰ–Úűľ ¸3IźőĂú±ql…H·xnT7…(O«»cjŮmÇ @ب7ůßÄţŽ €ż‰ŔěᛍoĐ4¬qOźü đ&¬‡÷jĂ!Ž,-lŃV„» bś’ ěŢŁńHä†="qQ›ú M?Ć!DF‰‚ć±i=~ú,0…ě•í{)&«i“¤łîR‚¤MăbKŐ>ÓŇ}Ş“›ĆĹ$™ŰÉťLďÉF,?~UL˝ł÷Yť$ˇV´»žá××ń/~á}ŽGýđ˝y&BXČ ăÔÉ“xüŕŁo™&ýřş­,‰˘|d!ľiđĺ/}“É8V¸dµŽ%zQírܢĹŔłźńLüÔOża»´ˇ<ą@®0·Ď¬? ĆUĆÝäŔÄJôäW€9o‘éż˝ćÓˇHë7Čü–®K+ ń#ć%EĆ&šŻ´úÎ')ZŔż‰dB?5nm˙š°ď|öÝ’ޠܤĎđ§Z ß4Z/ů’rL!†đ°¤)ZʦAÓLĐ4;†ĘآčŞű'Ű$˛Si=•IŚMďRţĹIIř΋ťp—µ#Ý®W×řÚţ»Q9—N2M@ÂÁ›_ú2|ĎÍ/Mif`ďsŤ@`!źžŠűď˙vşŃ/ÔEĐŤś6|…Ě2Fă ~őź˙×[ĚmtIĹĄ ­oo$ÔďÜůde‰DňËë˛\BN$ĘNžO÷+{¦ Ť«E UP’°Y%aI‘z¸&‰ś“ôn—TR·źl¤ußňkĂsüóM“–Ň3óťc~%˙©s3Çĺ…pT2-0M‹-»¤ dł˛Č¤`5"<řđăXŤňvy’O"O–´.Ő$)ĄÇK ’6Ť‹A,.ń›–îeíHŰ­¬žĂWżuW°Źc€;“ě3€źŕźľ÷°ľľž˝b†'aî ę˙Ó§N㑇R< ĺéVťG·U¨ 1'pnŹ;îřB¸5É•*rÝ~'KşŚµáđ[˙8w¶UĐG$Ĺ^[*Á·Ő˙Vďäě¦CŤWÂŤ€đsr±Ů2@ľ›Ětű Ďč:ľIźIőĄs•ş›ěoŇ%˝7F’öúŮ”żÓwÖĄŻKJ4ňđM+ĽĎŇĎEŁdÂ7ň¬űFµYš,ľ¤öOyű&“Ř7řëĎU•×ý“y™–FWZOEs)ĄÇK’›µŹ¤łSîRţSťÄ\ěö!"Ě úřŹţĎčŐ=0‡ P ä č¶Oüú~é=?G.•·E8פߞńŕ÷c8%Lbăńh„é*téBEU G˙úfĚżéą/x[ĺUUŤş×Ăúúsós¸ńĆ2P”FJR-äŘ— "\wí> qÇç>×ëYw÷‡üş/ äŠâGy†žZ «ďB‘¬şŢćSÎÁKÁó(š !â·”ĚUăA­t§çi;ůĎý$ĹQWÁ"ű@ä3!l¬Ëáy°ÓßĹ(CśˇÚ}žÓłěÓ›x ßmZíxdG,‹|„öfźřK´]ń3•'ö%ž!yăHš¸ap‚f<‘ŁÇŃďőpĂľ«‚żót%Yłź]Z­ q[MëbŞtuLď{'~ŁĄDĘë.o>Ý~‘űŐ˛QĚ»ćŁ^ýhľşüÄş)ę’9<V?i|ÔŚnđçźü,&ăuĽú•/Ăh´µ“]“0ő‹1!Út/VZ—’Äظ˴/f˝Ůď“X<ŐŰçR÷ď§CűtąÁ`€O~ö6|ŕĎţ3úý™`ąÔKŕ’Ŕ©@\{Ő5ř?ő ׇ’éN,H.ÉĆ„ńxŚ{ďą{[ Ą{hVˇW§k€%†Í–ä,—Hßś R3Ň®öĺł+řÜ羀ÉdŇbSäťś[]ÁüćżĂž={;wH&ő~”y%ÎňOĘU’śyGëúł aÓT:,ÉČĄ˙îĽ đOü®ŚŃhŚş®;roóŞ“ČeëÖÓ)ËR’čťvĄµ“@y±Ú§LxjŻăwI±OőöéCPWÖ‡Cüöďţ>ţř#Š~Ý‹x˘¸/ @6»“Ç˙đ+˙,­űËšľjdŰc)Ő!Ź>ň0Nś:ĄŐȡŞ|úvC±’‰. €ťi­ôßŕńhxČŐ˝çÓ±Í8G¸˙Áoă™wÝŤ—ľôf;Ů éŇ dyÇŽGřŘű?„ď»ő I5bAŽ˘]}BP™ †+UéeX6«*tÍWŕs-€îŇtIçB0ş÷ŘĽ¤ô¤z»‘kj:Ź­źÜŻ.ˇČÍŠírÄšlűíČ·|3ĘÎěőR¦~%˙Hű)ô’" ÷,t[jď}(ë¤ëůtWi†B +IÚţ˝^xżöoţ-n~ńwăć}7nĽ~––Đď÷łşÚ1—7Yz¶YźČ#8żdĺ3'^g âĄI ;ÚF­D.MY˛~°e×Ń™¦ďůš–ŕÖdŢelL <Ť oV÷«Ť3§ńÇ«Nm°M«c›7e"ëĂ!NźYĆŁŹ=†Ż|óN|ĺëß@0@Ý«UĘ€µ~&çhF#üÚżřW°}0řŁá8eŻ *ް|ć4ľ}ŕ@s árąŠPˇ‡f}ý»ĺŹÍßTK€ÖS°f00Y[[=Řźé«pD"î‚™qÇľŚ«®ş×_]*ŚÍ°jŠ ‚ ěÚµżţĐÇđú·ţ¨®!ŞmŐPlĐnĂ<ĺgص§«„Kz®+ÇŰx)Ý ‰A‡ßŕż$!Š’e^»÷„ ˛w0Ű|¨ôŢ ô©Úňň•„EĘ&ϧ“­™Űä ćvgoNĘä}(k~éZ~¤ěy ŮI‰řPÇF©@$×7WpU ç=jóó‹xč‘8đđcpŽPW•^ďl:*Ą˙˛Fö:žÁĚEÓLâá˙ÄHÄj IDATEůlęS˘Ě^R×Gz×9W~ł÷DÓÓNŤC“ŻNďť?:üS×OžîˇăÍvŕńü\7xo ŇŹ™eFi…kÍ–3˛ü׺ 1é;q&V'Äąçä3ůË>ÂéDɧörNeN ČEd)îLnÉŮ.żr€—¸xYyŞŰÎtcËzüĐęŐ8 q:7Ś=»wcÜL µŮKiđâ_ýă_Áľ«Ż†o| +ŇoDś1Íä0q÷=÷`2An‡Ş®ájÂúńŁŹ"€1†§Ą|‰gŁ=@.ýOŚ|čţßňJLFă0ˇšůčÜę*>ő™Ďâ­oą»–ὂu·t'›¶Bᮾę|ěŹ?‚7żăÖd*Ř.#Řű»Š1Ť L“€s2ĐáÓ%ú®ôěsű)ĺÎŢ3ĆÖJSH /u Ň ÚŠK.yüm"cÓé*‘˝Á¦)$ŞĚ7S[ŠWň4ÝĽ3p­ziÇgäĘÂÎÚĘÁů®ö¨8j]Ł×«17;ŔÂü,ćff03ÓCUŐĄ®Ľ0ńôääE¤’w¸ym7ćubŃ;~pűŤAn%UúéNK''!™ WQ ^ăaâ7}qÚĘ#!aeÖwYݶr®\7<áÎjľ(®“Ż·\†^ÝńČ2qzEĐäÂżlÎ0׎Kˇ±Cš›6‘ľĘý”ęQ<äe  eIK/çŇżˇńa†3ńůŘ&Ď–ĚŔGŢĚmi-=ĆŕKáx=@ěM]Zď¨)Îó+W®´J#d!ÖGë§ž=ĆăëëkXY=‡ĺĺł8sn룼<ĺuÂh†ëxßĎ˙}ÜtĂŤ4“đ ěMKM+öŢ=řŕX>łÚ @®*T>Nž8ţ €°Ëéo# €]3 Ŕčř‡ę ú Uě(Eę;vě>{Űçđ¦7ý0ý^«ĎçR®e”đáń¬g> ü>€˙Éwó ń}^iS MQßĂ!ČrB8eĐ= »H€m8´ kh*)ŃşË'ęîĽäŤ3fÂnN”lşZ®@>ô áś|d×)ËĚÔqŮFWÝOSńŰ ]Âmm9 ‚QüąŞ@09 ßÇě ‡] sص´ąąúý>޸Ľ%0—ŕŇ$G)/IÖ]n ţ§„­şNÉżëQ;űyŢb¸p™ĘÇűF.Ďǡx×8ßrÜSYo‰ ×)sOńž)˙E?m.›–Í»2ĹLC&„"ĆG^ń*Š·Ţ¤Şd·—sZ2Đ™}ľŕů{C"€GbĐe‚—ŔĹr3ä X ÇqŻS0OîXô a.g–c٬ŤGX^^ÁńS§qôä)ś=wh4fŢš¬ńÓ˙ĺOá…Ď{>&“&3Çשţ§±(îСÇqřđ‘HrBĹ’#8ŞQ÷*ĚĚ/ŕî;ż±JŇÎ[›ť°Ň˙Ŕ€?wöĚ·–vď}éx8–}P‹|z_űĘ×ńŞW˝Ň¬·TĹĹÝô„¦ipó nĆ?đ!ĽëÝč çşÁi é´I€Şü»¤â2¬.l®]h»éa\g6ÓLhţ ŞjęxÚ’CV¶-h5:óĚr3Ěł2>U+; X­ry:]ź§Äa‰J6 đXW"9y@l;rUČcęÁcv¦‡=»±{qłł3¨«¸ţF˛WĹNüÝŇ´ü`™M¨ý.w”?ŢŔ3u†Ź}µýŘşŽŘÚ “–Čvśľuĺ«­˝±żŚVĘz) "ŕâ¨=ëÓ†?;ś‰Ă´‚0NwÓ^^oL4ŰÉÚ ]@8•K”@-ÚÎ<˛<çL¦Df55_Q‚/˘Ńł¬#qGXĎáȤ§iqÜhK"·€ą¨ť"[•E†µ€©ĚaOʍńĺy!?´F«"?¬żMQśOŘqĽË†ulWá˝ÔCŰAę`x®QĎ 033Ůą9ô>z §—ĎÂ7“`/e4ÂĎĽűďâ7ߌfŇ„ú÷qŇČćT;sďôéÓ8đĐC(2„šŞB0ŕáhxŔ f h-l¶`IŔá áč‘÷ĺUŻűá—­ňj8łč™G<¬‡Żßů-,,ĚáĹ/~ŃÔdIHLš/zţ ń‰Źü%Ţô®·€ăŃÂí“€. µż§^l€ś™Ř7GßRŰ·—JŇŃĄ]Îݤ@ëŻ]›&ă5Ím»•Ü%ŤŽÖŇ0°kńűW‚D ü7ÓHZ]~ŰÚ#2ypŮJm`D\WŐ5¨Ş ł{wÍc÷®yĚúp.mĚ!ˇřŇŐ“Űő@ĹÇt0nŹŤ‚Ad8Ý®;"SO1ă6˙ÓĘQ¤Řv– Kťtxěć/±ż›@yPé<Ů3LěEI8¨U8ˇš–tč/C€»Ę™ÇĽńŰŇĂ´îËq˝;K3Ŕ<Áę- ZFĚŮŘá"ŚÎ6áEkq‚ňÚăž° w¸X—słl™ ͰÍE]±)Ô/ĹEVc6|Š|#5ĂT(‹Đ;+·öfÁ˙Hˇ„ÁoKMďěrsŢFB}¤hŇßý^KK\UÁ3cě=Îś]F3ăýüĎăą7=“ńV(ÓzÍ—2ő?k«ë¸çŢű‚±4ŽőóJ•CÝëa0;OŹŢ{×W»ü°ů&ŔR0°öĺĎ}ú+Żű‘·üÜx4Ŕđ“&uŔ a ń¸ý‹_AU×xá žŹrô”“»€˘ď=®ßwľđźÁ˝ýǰş¶v$ kŹ´ăd$ ˝°|ľ9 Řš† 3Ňń¦’“iűćiËf`'©OšZ7"E6Żap•í™·+Ň ·Ş­śizm#P ¨mŇŁ(Š—´±¨—[bą¨jô{v-Ía÷®yĚÍŇń@hPhܦYĘťJśĐş…)cPJ4q°TÄ•CHgźQ¬l'“PáZ˙y&¦—)ÇÝ”ÓÖ&ë)€T'Ź^:ĺ{˘¦#…TŁ­h§·-KO-ŕnľś´§pdÁWµq@öBX[Ę“AŮDľě5%XVÝŤ­€•ŤÇŞöĺ1gď(F ßő]ĺ4n Ň©9e~ŚŔ®ŮŇľ$ýTjĹ"i?G'% Ö śř¦4c"‘3!śwQE:@˘12b¤ŤŠaÓ–ľŘ®c­‹D_l}‘ĂÜÜ®şb/V××±ş¶†_ţĄ÷bßŐ× ń9PĹ…łť9~źŚFřÖţ»0Ťđ§2ઠużŹ…Ą|îy;€5 €% Řl @HŔ$F2Ś‘®9ôŘݏňšWł­ ö‘MzTöě1žLđů;ľ„^ŻĆóžűÜ© •jk<‹ ¸ăăźÂßřń·ăđáĂpUŘÉÝ)a§‰ż ŕ6~έ’“Öy‘IKÁT"ł! ¦0ŞđŽt3Í”x”mP¦kۦ[CbTUSĘs•-8Ý`·QÝuk&4műL7—ĺĎ“đFŽ€Ů™–ćç033@ĺ*%450sż›Ö—3*@–ŰŻ2bFXs”:BŞ$dH6<ťL~9Y˙RŹú¨d9eQ y!ÉQ»4đvžÎ$Ü”úĺü=L?ęĘäV`{+ŕ.ÜŘ}úÔsçVž€Zţ Ç“ëľMú„ţ9˛ ¦gNź8ľňŠďýއĂpäχ¬ş8398"4ŢăСĂŘ˝k{öě6%m;Ůl¦É‡*p®Â?ř{?‹ý÷ßoßw/PU0!ÎlަĘ,Ôj—ş=˙Ý-efţJ€čJ ŚŚeŤ:±Ţż÷´8şv˙Óeę0;,q—`±…ú‘üń”‰9ŰΫŐLHŢ˲+ϧLeš)AF ßKBÓëŐXśźĹŇâ,ú˝Db«ŔÚ,pWŠĎ ˛é„áň@&ŚËÂčŢ‚p"ÁúÍ–Ćá@$}%†ŻČQúsÖú áś›ö.†)ĎC~ňç)=×§¤kň‡°+9öpüRŢ»Tnçä},· ůw±žś«ŇsÉł+ËĺÎä»üŁT'íđ¤ď+2ulňÝgţ'i; ĺNé¶ęL~‡2—yvÎĄ~bëVúŤ‹ý*Ő#‘֍̦žm@ěW:¦(váŘGWÚwÓO63÷ëśÄ©˙ëś c(ÜUG´…iŘńF:C„)+'Álµ!F`Ť%EH$‰“ď¸ö%jŽ›ECíQ#Ż,O—Íyř¨M`pĽđ đh°°°€7Ľúµčőz°jĹl3`/Ó‡–‚@Ř÷=X]Y…;bĂg Şkô,îÚM_üěgţÓÁGzŔ)¨ `Ů `-nJäÓĹż @Ŕ`ůô©áK_ůę—őú]~ŇŘ^—Na;m3iđřá#X\ZĞݻµSŮÄŠÉľĽI3Á;ßú·°°¸„Ď~ň@ŻWdU;śô»4ŃAg:¸çqm@,Řn@R‡k ;0,Pv‘€vśÓ‡‚­Ý)qÓ4°I‚>çéůÉ뱌#'Ö~@®ý1±´ňÓuŹC6'Â<Ďë0ôĹ~ŻÂâÂ,ćfú¨ëJxtś&:JżĂ4d@f%ŘďY¦łG$ÁąíßÖ[ţa&6Ö©"M˝Ć|±™p-i“e ű>}J?+Ó2ýÁ—°¦m®Ď@ŞŹÔcúWř'Gi˛'r&_˘9h‚”0Ęł^!Ž›n6*W‹Xé§żĚZ~ťůĂ´đ@$Bp– Äz'í·R.í[Ĺ8%ÓÚ¦©]c˝#-'‘ńŔF?gꓚ–‚(é'Sń I…éň1oµ”f@ÜŇo‘IÝ’NZ }&‰HÎ| ădÝČČ@ÜŘ(ó2Ăł¤ÉŞđąÉ^›L‰e$R š% Ćd2ÁuW_‹=ď»’á­¤‰qfyĆ–Őü¦8v+îŢή¬¤ąŢŢ$RŐ˙Ěü,WUµňÇ˙×ďţ.‚ý˙ÓÎB—D ÜF@śŚl!˝ř7»ľşşňâ—ďkĆŁaĽÁ  ÚZÓx:x™®Ľboçdź%šeđ7Źđň›oÁë_˙CřŔ‡?©í¬"ÎćŮ,K¬JťĄ?Ă€QŽC3 Ł « ×NŰ–I€›[aŰuѡZ·`—&ÍkţŮ]×9 ¦))ň‡®2N#'’Ż˘Ţ¦y»¦ĹŰIl¬fBŠťsý~Ks3ÔAš‚0oYM¤0$ŔŁÔ§ÉH‘áXiÎűŞćËüÉd\€®Ôa˘±_B&W©ĂBGŰţş^ŞX"k«ú›¤¬r=g9p™¬ł¦•Ľ$ŐjNxä‡:©#R–o3_d5U¬˙g}”˛x%Ź˘UIib´ORĹmŁ€)ÓýfĎ7ů ĎČPöž4Ů3%"‚ʲçóSŞß¬Ë‘v™–íđC4`:^Ȥ‘ĎŤ­Od]ůŹÔČ)ýN /*óÄ–;ń:đ¤â×řĹ&gU…§ˇž<˛I[¤~.ŇyĚC’úíg+'ŕ¶&ěfŚ'/xîópĂľkŃČ­~ w¬9Iň–ú§gDŚ»öߍ•••¨ĺŇKŐҧ#T˝ýÁ KKôµ/Ţńˇ÷ßw/€“$Ŕž°–lNlkT Pč=üřňK_őÚ[ú˝ţ.ß4ÄMŁ<Ž(ŞłÂŽ\\8箺ęĘ¬Ę -gž;°÷ ®ľę*üÜ»ßŰľp;Ž>d–şÔé›;Ő6äń4`ÎQ’†CjąäŹVx9^–§Ńşş‰EÖÜŰ„Y=µÓCëy¶fnë,Ó”éPg™5N »ţŰ*‹»hťnŇÔ•źŤ?[D"^(E`ô{5ćô묂˛5`“nZK ň\§8R&±m#Y]áş]-o ™ćH@&‡®8ť•uf'hÚęCđ3«ËÔg-0 č,bd¬ńfy3@•€«`‘ě6BÖôÄX>™(M™m?—:Š@EM+¶”?äĹÍBXf°ů´óTś-»Ľ–˛9*xŐeŁĽt_ PÄť˛JYű„,=€łz׾ŢŢ\j–'RסŢ€|-€Ştšâ·ęs|)ݬ@©@]~Ćw°چľi<Ţë-ˇ1ŹÖ3 'BjĺĎKl,rÔy{!QťgV@6řířôÖoL=˝^ń’—`qa!ÜC@Ú|l„śÜš:żť#€=îÚ7Ö‡Cíß>ž´3‘«+ôú}ĚÎĎł«ë•˙đ;żý;’ż•ţí €YďŘŞ@>íR@ `扏=ńĘ×˝ţuăáMÓ„óŢq“ ÄĄŽÔ=qä(&Mk®ą UĽ*qC H~hęŞÂO˙ťż‹ÁÜ>÷©żGËm„t‚-E÷tUĐvlTYvŮAâĐřä÷t ÖçíĄ iJśí¸-qČă̰Oë 0î“ć!­j¬Ë_»^ĺł <Řśŕtµ×fźÓ–^ýółôzµ>Sý-҉Ŕµť˘? =#lb3‰%RÔ˙Ňä'ż“Z1ľIĺŐ~—@źR†C˝A%ţä—¤.JÁ9°ehŻé·âCvC‡ť†vLč8#‰ěŕ©ü~T‰Âş&ěX‘¸)áşu‰ŔŘ©‰l¨ö´/YĆië*pőć Z"„ąĚJŐČĺŇ0đ>ľó– „‹“¸aŚš1nÜ·/{á‹@•Kóµl$ä8ću¤«Kżč÷{ŹĆ¸ëî»1NҶ´ż@ňJ Źýőgf°¸g7}úăűĂÇyřAäŇżl´–“Ű °=AH@˙ę3§Nźóü^·¸kĎőM3†¬Očŕöťř±Ł'°rvW]u%~Ě™ĎÜ•™Ńx—ß| Ţńöwᣟř8Îť]nŹv@ eĐMŁŰĹ/ž&F6ŘówÓâ”ΙkşÁ3ĚXm€Fň+źÝ`ßţÔď˛~ “˙ŤÖöMšś×ĆÍ­gúIíşÍľq>;&@ó<ŹĚćS—„~ŻĆÜL?nŚţ-@ę/UńłTĘPYĎŤ$$LśqđFq&Üka~˘ŁR ˘µĹ@.ĺ ’9ç`T.A¤Źň·ćϢ™˙T6•wIň§¤†âúk,Rö›‡c]L˘Ř7„Ç\’rš€]Ş#*ÖOcŰ ž&AŠĚ>—˘qµ]•BÜë>-+ÉS»ţbćô·ý¦őGiâÉźKmŮź(mB Ăc}Ęuk’)¶ĹxčUş‚±hú”x%lF9‹_¤gí·řÇxdÓZž7Đ`ő+{}F¤Hg`ß–Ŕ[ĎcŢ=›3óńągß.·Wŕ—şqú$ýsţ”w¬şľâć›qý5űĐx2K-ËѱôiOqsł38łĽÎůűĆô¸ä!u Ő]Ł 0»0Ďk««Ź|čŹţđ?"Hţ˛ůOÖţ­ú?sŰŃČwKj˝o|ńöo¸őm?ÚL…HI*‡¨÷6ü1‡kDęODĹ+aA$—jCt‰ń5c\{ĺ•xÍ-/Ç`¦‡g}–ŇY?Ń sŇSćqđŕă8đĐÉDËĐ=áŢ"J˙łłĽkďúÝßř_ţ×áÚúŕż%éŘş äU?eT'"0 O|÷K^öŠÉxśSč̡Gë1"ťťVW×ńřÁĂťťÁîݻŌ)Ŕ3B¨ěÉd‚ú×ă­·ľ źĽíÓX>u2™Dę‚‘:l\:mp6GICç4 ę]itšC6¨Ě$H\ĆŃç4°ďĘx’r“Ć„ŇÄŐwęxZu”?/UúYÜ$qćÂj”ÚuÔöż‘¶ ß«07;@Ż®˛‚v1:IJ˙ěo3!sm-8R~ Ś„ÂÄ ŹăT AúY˝Qöާ“Ť}+éŕ ŘCÎÇüH¸>rŇ!1ŽYJe)hŰŮ~ă0D¶™ôŰDŠYÇ•Ô 3ÇńBłBkhJ"x‹ÉU’Ŕ‘PhëĺU%?kÔ)4µé7­ń¨ ęYŰ #ąĘJLĚĺźökëOŻ—0őŤÂŻ:9ŹŻZŁĐů4cĆX•,” Í©ďŞęÜîĘW@n‡öaB’Â!ś¤m#ˇŰß)ŹĆŻéáy®žjTů‰°xÍ«W’’[XňÎ>‘źČ€”Ç(ŮđŹ÷yřĆŁr„Wľô<ű™7Em‚Óů‹âĚÄbţ4Śgźő§ŕ\ĺ°¸8Ź{ď{O9Z\ź=î'őëç*ÔýúłłXÜ˝‹îúúW˙ěÎŻ|ůKŞ˙SčŢůß9ůow Ŕţ¶D >řđßýŇ—={a×®kšIfź•– @8Ó«îśĂhÜŕńÇŁń\yĹް>kg“|ZR í¸24ÍK‹KřĹźy/33řÜg>®Şxgúú·¦ˇů͵Ĺ€F—4 óŢTRk@OKCýuKŐeÚh·JWH+'+y=¶Óę ťi„úŕloĹ4őüFźą˙T(’®SěęoĹ1=Í—qŽý~Ťą™zuk(Q-­2vŕÉ˙ĹkťĽŁúYúŤLđg:APäÓě!жłżEzaţÔŔˇŇXĚ‹Ą ©qY¶Q•t^^+=Ú1XÎ ˛. [ce•¤Ň‹ŚWJiQ`ś†Dý›˛«ä¤´LZšÎ™Î0ŁĐ·E?„Ĺj-e¬ę{IHę©*@ŠúĺPo2oĹ}bńëF= ŐYfčĆĆ/@ť’źx›ˇŞŕL \:ă1@.ß3І4­Oa¬5“fV&·ĽÓ» ˝Ůěf –9ÄíNźa4>mŇóňcµUiľaĆüü<*|ó›ű±rn%\n=1„ ť‡ś ŕ?3ą…žL&‡˙đ˙MŮřwAő[ţíiÄŮŃ#Ŕ¨żvűm÷ţŔ›ŢüÎQß7ž¤‘Ä~3€t6VŤS„Ł‚ž€cGŹăä‰SŘ˝{fçfS…QkhĹ ¤Iи7ŕ%·ŕ=?ő|ő›ßŔăz˝¨Ą6 ëSÜKm@>çj3őŇNĂ~5h|ÖMJĘ´Lí[Đ´tšSÉŤTšĄ)‡ţęŽsJĺ{˛qÇŐIL´ŰAŢŮ kD@żWcv¦5ĽE»ĄMslbB6™‡´ůł“ź(ŠÝ’XşYŹ‚«ŔŹe©UýśŽ?É?tI É/2`·i§‘}ýr~\V.ň˘lĚ %2q ™5ă’b9‘A4%ýÓ,iČ{ë\Ľ˘B€Á´]AĆ : DÚ·cż¤‰,Ş@?é rż)ž({#mʧ|‡‚y.Ń ¤gŞ:Ź!r˛ÂV3 DÂJ»’»ö.eŃ=>Ąé I¶ĺ ů’űĚCôÓgß…$4ž1i&››Ĺë_ő\íľtąYk)4öYŐHĹ~Aş ĐaďŢ=8vü8îŢ?Q•ĘL‘ypÔhx0m‘ë?łóó<·¸ŕëúµ=™LŽ!ßř·†¶ý˙Nw>ČF}FÜţŻőžďăŹţo<3AŞ®”5˝\Ś{ÂrČáěŮť”Ss€»—ŔT’Ć!y4}ÍÚ] DËF3•Z]ČUđĺˇDť:$č+ŐłÍsˇI€ŮńýôŢŁń @„ďyŃKđĘ—Ţç*„Kâňńźú‰€żyM„¨ # úě޵oÝu:űŠHţqŽ•[ŁEÁ@2ŞşBo0ŔĚÜ,/íÝCüżď7Ž>ôm' ÇţÎa“ŤÖ]Ŕ~—QĺÖ×V›ł§OzÉ+_ő˝“ń܄à ŽóAŇJďÎ&“‡=łËgqĹž]čĎ b'±’´Ňͧ¨ÖdҍƸ~ßuřG?÷‹XÚ˝ źľí3U`Móćí™Ô´uôR’ť&©¶4 é·Ň(Ázš´ÜĘ·€É”zÉÓčž(dťG™FV7ć˙î4€îťu#ĺ™BB20(ÓpĹo›™¸ ˝^…Ů™>ę:^!»Öłx)5„îxOl0= x6Şů[2iZ1gŕÍű@HJó´r6]Lĺ&3şćgĹ|®ÄĄţŤ©ÝhV7ű-ft©Jď­é[Č{k7úˇĘESľUaęWĚĐš´\M‡g.…ŤUU®âł*Ą)áŇűč‡$ü˙GŢ›‡Kr]u‚ż{cÍĚ·Ö{U%•¤’dIĆÚwa»›š¦h0 Ă:|Í2l =ŔĐ0Ó´§Y>ŕkš†ffř†ˇ›¦íÁěÁ ,o˛¬Ą$•ޤRIŞEUĄZTűŰ23"îť?Î9÷žĚWU6Ţ0!˝ĘĚČȸkÜßď,÷ţ3ę˝ÜĂrů¶sŻX‡xż$‰ďésż·)’Tî•ph^ŁÚaUô?ŰŠHc®"vĂ?Ű(éˢ) ÷ęÜF R­ň¦0*‚Sx^Ă÷q=F¸Fć4?{š¤M¬uńĽ&Pˇ&ÓŢó?áůó@Č?`ş×¶Éˇ–°[í Ż‘¤wűC˝¨7± €oŞşÂm7ż_ţĆ7cnvMÓ@’éűžŮÖíŚÔEŐ~aëxb×ÓX_[ s@Č—“~Ą.ˇäh6M‘9Š~s‹‹ćÉŹ}ôŹôĂŹ€Ŕ_Ľţ»é˝ú›zÍľ¸Ä!`/ą }s,X~Ë÷|˙?»ížű˙ÉĘů GhŞpĆĐŘi’Ŕ$)y€ŚHç’đÇanv÷Ý{v\łI‰a6©v\ ]Č‹v’X$‰Ĺ/ţ»_ĹúßX“(źĐÄiŮ'ő`w€©s.J'J¸†żóňpuĄűn›ĹĹo×c˘śŕŔ‡Î=Ťşľ]G-…O»¦KÂbŇ‘ř6ŻoG1µo¤SÚ­ĘÜüŢ~Ó¶Zk0Ó/±4?@ż—3€ĘĹ#HmzĹAěK©‚áX÷‰Mx®P»ÔňÚúmHë É–_ă‚Ę“fz´TŤşÝťÚµĆ;ô‘\ă1™€G˝‰ýë;Ů5“ _}…úއK₯CÜŞm:őňŇŮí2 ÷ 7iŤew7ťvč¶µžő0Ží#Öź^|ÓŔ75¶“µ»*ŞÎĺD…§JÎQB–_+Ő7ß§kŹZ­J×ÚÎ{%Ą‰XIᎥoŻë"&¨ß¸đKnľ×iÍBhSë:°tôí@»~Ńw ֫ݦX´¤x„ďäé˙ V—˛U_{ď1Źpý5×âÁ»ďˇ|6Ť›Ř6UfÄş™PG /r”e‰˝ĎíÇń'Ă‘+ăd ű=H˙ŠI*1°6!đďő0ł°€3§N<ő˙öoţHíš_Eú"J˙—T˙«éüIFý% ä@€" X°đ?ýs˙bëŐ×Ţ·vá"ŞáMÝŔ; f×Ć"I‰a§"!€®5Ľ`y¤6ĹÎkwŕÎ;oĹěÜÜ5AÓ„ .×fY†sçĎá­żţ+xďźż™ ‹xXHŚ'€öSŔo č `µĎuA°ťÎ7Ü+€µ–~Ż ´Űä66‘ĹT˘Đµ÷ćۉşMĐÍHOumžNV4°űËôÍä=bˇŁ§ M0äśµ~ŽĄů z…ň¸ŤĺĘ,i‘LĎx!Ś‘Ř,%)q j„§ú,öť&˝ErbWOĺ4˘b/'LAŻbuŹPO–ŻŃ*?î¦!6¶=ô|í¶qrnO¶»KŔôŘꂍjĎÄ÷]"ʰ¬A™śńŕő®iઊ2©…__)Ě   Üł¬č­–F<Ç;Ş»ŕ`{‡"Š`h`súúiD@éşäB߯M2¨ä=K«Q‚ [Ţä·ĽĎżKv‚ˇ‹çŃ©żÖě©:O´łErâ(„\@ÄŇ>窪Â5W_Ť‡î˝3˝>Ćă1ŞŞ˘w­±RĺŔ«¬mBc,0Ű൳ç±gď>Ś«*« Q\~ď¤NüśŮ,Ašĺ({= fQŤÇG~űßú+ ŕ?Ť¸íŻëř'1˙?í@˝ 0Pb’,ţČĎľőX\^ľ}ý ƣ1\U)>1 l’˛dNŻ˘~$(‚VŔy`ĐďáÖ[oĆM7Ţ,ËA 7oB$rMÔcPäNĽv oýµ_ĆŢó®/‚.čÓA{đÂf`§ËđŇ—ÖBt?·ÁbşF [ý~ś' I§ťš„ĎÝv¶ËŰL⏿é^ŹŘ7^›S&ëŮ}µÖb¦W`ËÂý2‡M:š )+<3DŕRŘy–1‰µ Ô‚d «‹ŁJ §Ąfb~NeU·¶t¬ÎˇsŁéÂg‘Px- @Ní™2ouŮ€·řąHṌÉz•ďŰX¬~'ö{şĆ˘˝ĹŻEPÂÖj#—ë‰sf‚¨Číu%@ÔĹFU~k:tŢrMUc<ÁŐUčWúNú×ĚK’ FŔM®@Gë•Ŕ6j`Ô ĄÜ.ŘŞĎ:âžş?Ľr2“úh0ĺĆh»xü-ů„Vˇ['őŰPçÎ5J› ĎI[\¸•NBöę>qˇťÄ)\¶ÔZ¤iŠ4Ś«aď~‡¦iřë1v\uŢ|ďXÚ˛U]ŁijÔUŤŞŁŞ8×Đł-ixŐ8 HBYćH’O?»§Nť"„s@Ö.®OŘńŕ=<§6–÷úО‡Áü\Óśř˙Ëżţ%DđÇż5Lwü»$řOÎěOî0@H &i‚{B~â~ůgffćoŢX]Ĺx4BSQČ` Ë!|Ó$EěsIpŽ tšâśăáŤÁ¶ĺ-¸ëÎ۱ĽĽDž¸.J¸úŵĹĚĂ÷˘ČqôŘ1üÂŻý>üWďű‰Ŕĺ@úň@ŢÖLS‘K·OÓ´Ă O'ö˛ÚŘxŹéŞzą)ŐCîEżť¸Ř!±ľhŰć}ĺ§|ŻŢűMĚę5±^ŽĹů™`@¸‹ôQ@¨Ó¸Č´°¤)Ň,ă̆ô 7ażpc,˛,C’$­>©ťĂ¸nиyLʧĚf*[žB0ç9 Ćʵ€® ´qž‹„ćŘF?-†šă± "iQdH;Ńc`Tď¨m·’¨Gú;.šŞÎę÷ˇże<伡űĆg±Ý†íäRę6^oő…ôB#j ,ksHk!÷Ö“ ¶§iFĂ ¬Ż¬`<M‘üąłC[ă·ńŇ6ŔÇź đĹřö-ŕo´ €–ŕHÂS_H˙×u¤Úv=4ąč‚;_#©h[eú Ô‰´Ż˝ň'Ś’ĽŰeë:«şŔ+đ¨krÎëšÚ;(Tn‘fč—%Šđžw3ł­ÜčÓ‰uÁg‡ őşyy›Kďí{OöµWBôçν|§\Eş.]żÍűę˛më–©~›X~żŔâÜý^Ćv¸Ë€˝QçŐ…ĆZ$VŔ]€Ăř;‡ş®QńĂ_%˛,EtĆuŤőq…q- ´Ś4Ş ˇVI’ÇŦ®9Ëoµ·ĺ<Ú"˙Ţ9ÔMĂű—Ă,‚8ś1î@č…đ¤‹CXś÷śŃěn˙'iŠ,ÍĂőouŻ0)&‰… fôób¬Čâ RáÖPż@gCy‘¨Č­,’,E–ç¨1ś©Î4ÁdTW5Ö.^ÄŮÓ§1ÜXçđµí#ŔľŹź5Q!]Ą˛BJ8×Ď÷ȢʿíěÚx.>hI“$EYpŢc8˘Ş$l;Â=şf–ź&Đu‹Ć0Ŕ:ß;‚dě(ÉŹŰ2Ŕ«2¤qÍNÓy^Ŕ{ŹápUUCú«ŠŰé\š$ôJ,ĚĚ`Đ+‘& ŕČĆż}y+îąóN\˝ušŞF")™-Í ×xÔu…qUˇ®+ĘvëAŰJ=‡bö$HzP8ŕůŮś={OíދՕU ńł϶€”ÖľÔI,‡řÍP–=ôçf}šf~ýçć­NśţdżżlůÓŕŻ<î/üm€ţ˝At ÜL°ĺ§ţíŻţĚ`fţĆő‹+äX @đ´MĹ×&H´÷1Ä»8Ş ßďá–[nŔŤ7\ʍÖ'M D ™Xn¨?ľ'2O9čóý˛„÷ëëŽ*RˇzFđ—µ>KĚ úXšźĂLŻç=n˝é&|ń}÷c¦?Ŕęęę¦Fb ŇÄ"‘] ‚V×Q Á… A33>\ăđřSĎâÄÉS0cá­‡ő6Ć‚áů ś“% M`ły^ č—čĎÍÁgţýżţů_qŢť@´ůwÁ˙ŠťţşÇ§ {Ä54V@ż:řř?đř­wÝ{íŇömWŹGŻÂ7S‹Ŕ ŢÄ@k-ęşÁ©Sgpâä)i‚ÁLźX|(ş ~AZňÚű^4®A‘çřę/ý üČü<ňqňú R’ K‡é‡ÁE(7vK›”ČŃ%' Ô„3LT_ĹźuÇ\> ËöşMĘ ·ť–»`r>MĆ2h·ąsSúNĽZEý"ŤśúŰéĺNí2ôŘŇ|ëc€,MP9ŇÔ†ŢmKV±>ZŠ Rž>"%ĆÖqr¦iHÍĘ =6syî;窩1ŞjÔuRQ˙r}$&÷™ÜŁf €Hi"A9ů­|Çą*&Da ű§ť^śéŻ‘,gŕ(iη#«…zň«8|… *í`“í|@Uרť ţb[hxiW”REŐë´ĹđXŇ8D‡´P˙đWŹŕcŕ\K9޶:Ôuőµu¬^\Ĺh8DS“ŤĆޱ×xś Žť´C ß—Ě?Ž=Ě”¦®ÔMľo”˝šîßMSă</×´Ëlřz"¤hśĂp<Ćx<˘ď=Ő˝iH­îśăűyľGĂeąmTÝľÖą†#ň nB‰lňý|CŻĽż>Ô/\ËΕ\ľ´Ń9ÇőOĐ8Ň`Ś™S5ÜNîçBü|Ëšşîş ßňu_Ź;ny˛,Ĺxfć1_ůoýźĹĂ‹äŻţ¦%úů¤Ŕřô€.čË{§^óä#Ţ}őő7Ě\wăëntMăa’€^Ľ•$ Ň€’Ä®'ű§GŁ^=~ gĎśCŻ_ ß+ĂÂÜ="Phb •¦Ď . ŢôŕCř©ůq,,,`ĎóĎaíěi@"ÉÉ˝:˙4LvU›h ¶Í;÷âţ` :Ąešč{\*9‘iţ"Ţu^ęľŮ<›v^$çörŻŘ¦K·§]źÎ=:sgZ("Ie‘)’(űüŁZŇ{(¶ď[um©<ĺ!\ƇEąćE HR˙ë¸ëUă0®j4ŤĘď­¤=ăT{ADĂ&$aÉ‚IŔ¦˘÷…%@-2^)˛y„ú*đ'NfIhŐEý‡Â¨{Çrb[ř†ž k,lšŔ{˛A{§â·‹ÄD'®1NľGü>Śuŕgę™’±óôµZYŕB<}OĎ®řÉłĎt„±.ס®jl¬Żcme•›'’í  ¸Č°DŇAd'’LçÄ™UHŠ‹áhąľ^ÚÚ+í줭őҧ±íLš¦đŢa<‘ŘPűwˇÎBDĄ/ŮWEČT }bĎ7±ţě#stĆ%ÄÖWä•Ú·ÚyµI’PžjŚş©Ú÷DHŞŞB–ĄřŇ/~#ľç›ż·ÝüzäiJŽ·p¨xçÚ1)řYó@ qÁŹô  }ĚÍÎâĄGđ‘Ź<ŠSŻ˝FÚ'MŠř‚]2ĐëA>(–M’“ł_9`nqg_;őěďţÚ/˙&HÝ/1ţ§ŮüŻŘáoÚńé"úĐ•áQ çłçÉÇ^,ĘŢčőwÜy»§YbâĘ{ćEyWZŞHcâ‹(ŐVç®o qôŘ ¬\¸€^ŻDY–qŻuç €RŻFŇ!‹FUW¸ë¶;đ?řĂxđÁ/ĆÉS'qxßspP†+Ř•:Ű]ŃVţÔŘnW¶?Ó‚čăzwĹ÷ĐĺOqʰśwî=yč{uľé….H·Šďž4˘"۬mÓë>Ůţ Ňâiî¤Y‚"O‘Ąô°†J‘$)8€˝ŹŐő<4at,Y»†%ś9¸ÚÄ-Św¤ćŐ5jB h˛ĘÂod!± " jÔŹďŚoÝ&¨üňýěy16Pł“w´@>Ŕ‰0ĹřXŞ1ˇż4uź ďĆŐpMrÂËýĂż^ʉő$2߇ń5†‰†_+*žW=ä㼒ČrM=kh9 ‚ü……›Ç©Şk 76°¶ş‚ńx̤"‚ż”ßÇϡ-^Ńa˛~¸&¦°Up?óďC9S@_o“Č6Mxď1×hꊵ<ÜŹp¨>cŔd*ŚżŠý/ß›¸÷˝ńľq-•~¸göçťö¤mĐ•ĎĂI“Î;ŚÇiÎ|®˙Ćp„«¶nĂ×~Ů—ă-_÷ßŕĆë®Eż(Q¤ LÂÂťi7šđtďÄ+Ž!™Ę¨űý‹óó8üĘ1<üđ#8rě=;‰ż6%ű ¬gÔxCöţ,•¬~čÍ üÂŇ’9°߇˙đw~ë˙E÷É_öůko­ößtµľÔń™ @»BňŢ©?˙Ňó{Ž^`¬·÷j¶¨nŮvâôoŕ'÷şđAP1 )ԙ㼒]ăŃÔ5†ëX[]EUŤ Ô>v=— CŮBř¤™qž‘tQ»ŃY%Ʊ÷±,Y@µÇIŢłŤž¨÷ž%h˝·˝;׽ꟶŮ'„§miŘŮŹŰă\Ć»p/ąO$+Q»Éh´\śžŕÂ{O2Iŕןç8ÜŽÇcÜ}ŰmřÖořFüÇބ…ůyŔ{y†^QĐ.“„ĺ%ú)pŚ}ŢŞ«ăy)‹[¶Ěă豓řŔ_/<×xÄó´íLkÝWÄ™#c lj‘f)ň˛@Ńďˇ?;ë–ÍÇ>ř·˝űŹ˙čOÁ_BüJzß®Ăß§ ţŔgŽíĺi pŻ9|ö‰Ź~č‰7ĺ×Ü—÷Ë^Ű™F˝˛TN+‚Ę~Ň4Ŕ, &liZ]]DZcÇqqĺúe‰˛,Z{žĺh;”)“€Źj^ ĐD7@ÝÔČň _ňĐ›ńS?ö/±óşëđę‰8qŕ%ř,mÝCęÝ^§u•:3Aô«–¨;` ĘÝ{uł9h·Ę3Q⽤ a˘3!Ťw>AÔ«ô](Ę«>¸T!,îr­1ä¸Wäń—2ä˝Ń‹Ş ÷đ~Ň) ŕy#jcŻěŤCÝ8x+9ăyˇ¬šUmůP€Ôn§%ŮÂśZĽâPš’>üVŤ'DB¦ i‰ý¤ű¬ÓÖÎ=Űăôóń;e–Rb{€Ě#®E|b˝[­ú:‹0/ÚŮâŚ&mě‡ ×‰¤= ĘňŢ'Ä9ü8Ű]ŚrÇä…Ż§X+ śsd˙®kşżjg0'Čo•ď„î[´ĘŚ$"ěÓg{Ľ€x¨#Ź…9đ"Ŕ÷ ăF×[C»Ĺś÷´7\accK‹ řň7żßőÍ˙ ·ŢôzE×Ď€Ť ËČÄĂO}ĐĐyB:‡0ÖţxĐďav0ŔˇWŽáŻ>đaěńę¦fŕ7Q&&Lăz˘ć5 °ÖŇŽĘčW ×ďc0?ç{Ář˙·ßúŤ§?ńńÇ@˙Yř‹Ăźůé‚˙ßęřL Ť4ŔŤFĂчŢ˙ŹÜyßC×-oßľÝyç »Š‡nśŇL†ůüh…>*ÓŻO«+kxőř \Ľ¸‚~‘ˇ`Ó€x~_ÎAPTtFk@`5®pËŤ7á»˙ŰďÄ·űw"MSěŮ÷<Ć/Â'YPŃ-6+ýů’ťzI€ "Ą‡˘Ý§›o§Äřť‰z˛\?ý7SęŘřNť7m_‹ \îţÝ:ŃÓÔ Ą±xDoXô@D”*ˇž‘4ŠĘXśÄqâ[xNęś qꆶz©Łg©/Řś‰„HĚyxžbűcŢ>ç4@Ó\—'1nkk t[ä"Ţ şź}čH5˘ü#ËDČű¸Ť1JťBÖvßoęÔľŻ€¨|vžUĐzż—úB?ł'?˙*NÜ78ňőΡiذ¶†Şł]9 {č Čs-›»Hąô{Ă˝ŕ®Ü̶3˘|v,‘«ú†˛©­˘B7Ć’Ö+¨Đëđňźô­ęW’îµDŐ@đ ŕa$ ;:†k%ąO¬łÜ/h4iBB m`‹ńxŚŃhŚ{ď¸ßöŤ˙_űe_…«¶nŃÖqËşŠ,GŻ()`'‚óÁIžú&±D°k°0?AżŹ˝ĎíĂ{Ţ÷×xńŨęŠň_€>úŤĹ3>><_YkÍ>&IĆ1ý{%úć¶,b8űw?˙Ż~ůÂąs‡·ůu“űŚAA‹Ţ~8?µă3Mä ŃŤÓ€“<ö‘>=ť­ľčŽ»ns-Q1.>a™TB¤éi«µŔu”Đ,›VW×ńę«'qöÜ9I‚^żä OTČ•8Ţň–0UUˇ( Ľůţ‡đÓ?úă¸çîűpţâyx~)T%ĐŠ4( “ŔIurík7BąBŔ­ó“óćŔŰúŤ:w 2‡°{ß®ä>)É]ŤĂi_jb.UoR^<ˇÉ MăOö °lµŠ@4YwٶžEOoéÚ5Xµ,QiŔQ‡q]Łnś +UŽzŽńh_d‚ŔvÉUęŢZ 3©Q‹;ź—>ŚńŘăžrĂ2.G-Őę÷Rîűh @ř]ôa€wÁ«\Ȇďu9ńłWmô<^Rv$aNpý…0´2Č1řëĽńbϦ-Ćâüxö¨÷Nů[xúMS7¤X]C5ł$«ŔÚ+Ň€\ŮĽá〽ô}\wDµMČ@(˙…ŔQ xeŽJś\p¨ę IDAT'ż'57ihťŞ›šwWDÍóĘyŻĺô×&,ńĎ«2dđ€9Qß;Uź(íÇůČ»`ĽdĆąHlhB…áxŚ›oĽ_˙•_ďřć·ŕćëoDŻ,ŘφY„@ËR|49ňŚÍÉÚŇ„>&r‘Ą)ćQć9{â)Ľë/ŢŹ—FS;~´TýrüÄGÁ·ľ¤~”ÉO¤ţ˛ßÇ`nÖĎoÝj^Ţ÷ü‡~˙7~ýw_ü¬XG˙iA~ş‹ř'}LęÂ?ý‡xÚI° I $ˇg@ń,\Ó-7ßOţ«a`ç†k«Ź*45e¤…1a¦Ć±ĘΕÎĆL.2AÎŞÄŚ[VT6łł3¸~ç\}Őv¤Yć±é¨»ăâĂ‹Ąú` !!đą"/QŐŢńŽ·˙Ů;đěcź $Di¦LL<|ÔBLßűD3.ój6˙ÍÔ€<ÝßL–˝Y9çü´ű˘s­”5˝pâży΀xďnŮÝö“ÓgŻČ17ŰCYä*ů”d÷F¦ę«ČdxĺsIç Śżl_Şëuí`¬AQäHÓ,¶ňĆMŤQ…Ş©Yö :¦Řľ@x)bf–‘Ăi]Ń6+äÁuŠz*l:ăáÁ¤ÂK‹IRç(čËµďŤ ĺŇy‰ čC©näܤöĚó @]K|u!ŮŇס)±¬Đ5ń2FPś€Ĺ~+Ҹ# úق뗓ź…ř4ÄCâ xÔU…Ő•ś;ý†“[D…«ĺ™ˇ1,ßá+qBäLŹD$VĎkňÉuR$NĆ;ś3m’G/d&Ë2ŇŮ1ŹÁň%oUn >ąHŔâş„,íh"č’7ÉßÇűö÷ŽÍĂń®Ţ~5ŢôŔř’‡ľ[——0Ť±ľ±qU…~ŹÚ!Ýn M,˝óeŹCÍ# ŃxŚ4K°enëëřÄc»°gďó¨ë†žU %¶đđ ßKŰGĽžŞŢłr=ü­…Í(†G^(z=ôggP”eőî˙ňźď™Ç?ń$HÍ/ę~íě§·ů}ŇA~®äřl˝v&hG ,A™%hĐ<˙ÍýŔOţěw˝ţÎ;˙Áę… ~<™zD‹ś,8śK€ŕÄRAËŮ“¨ó%Ĺ5¨FŻ7 úý®˝f;vě¸eYBÔĄQzÔÄ /MŘß.f Ě4Ť§é ôĘÎ_¸€·˙Ů;ń¶w˝‡öîˇhL\dežN&˙“!›ŢÇǸM .]öd]6! ŠlPźo™p řnvM đ3íš8ĺčňxMb-Ę2ÇÜLežńľ_Ŕ{Hđ—yiO a ŮUŢ*jNÚH~ĆPđ4MC^ŹŞi°1®P5ŚE¦&E˛ş$I‚,%m$4ihičą8/ Sg^šŕďŰiL×P€.ŽN¦ż‹ĎL¬§“ }>M)©‰P1Ű´‹1^\Iă&Pnd€¤ElÚGBÖ«ú†‘4±ÇäŢ€Q€ĆÓŘ»šÔÖVVpîĚŚ6657”őű–2P¸]Ř&)ꀖîŔ·}O€w*„»*‡ÔŢY– ČKŔĆpăń1 ±‡v!Q›ÔÖ4D˘ ‚yšC9O¨«¤0µĂ!hNČl3±8ż€7=đ ŢřŔŘş´Śjţč8tč0Ó ±ňJ·łFmy5†Ç̇g6Đhž‹&!•šĄČŠEY  üÜÂś9uâÄó˙çŻţňŮúe{ź8ú­#zúwüČß§ířl]ŽäĐ$ EěE$swÜ˙ĐťßőC?öĂu]ٵuŠĘT5đ5ő©}H`CánXň¤ÇTĂZ+ b!±ŕĽńČł Ű–—píµŰ17?c’ ÎÓ‹‡Ř\ ~ iŮ\FĂ%ď=ĄO±Ŕ 7Ŕ‘ăGń_ßů'xÇ»˙ 'B&AěoC6UÖ±ĐË€W[p…ő›"ÍOŻßôĎ“uî~7˝/&EŽą™¨Đő&/o40Ĺ{GŔ’ÜIŘ?Î>Mš%ic ň<'Ŕ‘ĆĽ' Ŕ°˘PŔŤCů†„ńĚ{0‡Xî& ´\+›ýdŤŠ\‚Ű@4˘¸,\*¸ijUî]cZźˇú¶MăIą.K¤Y€5 ='F ]őµ.Ł3Ď4 éć|Źą "ôʵ*(ä1–kBpedÁů–°îŇ’z5@LDČR 2ăśÇp¤BĂwŔ8’•–ę_čE~%}ó †äpS2öµ>łÉl4a¦?Ŕ÷ŢŹ7=đ n¸î:ŚFC*ËQÝ,KŃË xŁŃU]µČD ýî Ěűeą~˝˘DQćźŔ8‡]»v㑏?†łçÎÁ‹$ˇŕnV'űŰHäζp"ăXc(m·ĺá)…–΋yŻDfŕűó×ďţó˙ôŃĽ˙Ă °ßLę×ö~QűC˝~ÚŽĎĐĺÉź€ mmŔ "X0˙żđKßwÝënşgíÂE?M=®ŕjzH,ßÎZ2$‰EbÓ§ťÂŻ&Á‰D$đ+ytň.-‘)`ŤÁÜÜ ®ąú*l۶Ś,ËC´.Ć1Ä҇ˇÎ:– ©Ä–•Ýó6ÁÄ$ô8|ä0ţô˝ďĆźżď=8¸g70!3é€ŕ%ČŔ´sÓ%őiרĎRŹ‹Ň§źx„o.sźKß[Ëôď¤5Lü ©ăçgz(Š<¨Śu='jŐzďKš$Ö°úÖđ GRkČÁĎX,% DÔĂcÜ8 Ç;ęCK«aŮA’X¤)hÓÔ$a©Ş‰ŞÝźň^Z§5`YĘá@CM%[íxşSHZŹÁN"źh!8;¦Č¨B$:ôâŞÍ á«@@˘©í‚ĄW& ř[Í‘`,â(¦žQĄK R`SWX[]Ĺ…sg1°+ĐíŇ€ ^˘vEúX‡8'ÉF”‰€÷!ýĆ »Ď?ŞÁ•ÄΠk¤i†ĽČá˝ÇhD‘ôBŽűx“)*z>o|Ü˝Ŕí@w0a‚–JxŽŘ`8biq ş÷>ň8v=łŐxDŢ˙‰÷V$}E¤_˘vR?ťŰ_C(j‰ăźgČň yŮC9čűŮ…9łrîüáßů•_ü?Şńč$HâďJý˛ĹŻBŰŢ˙iWűëăłM¤Lů“tÂBşÚ€Y6`ćîßx÷·ţŔ}_3łÁÚ€¦ŞájÚmřżDĽ-m¤3k$śďŰšdH¤±Ó}DR(ň۶-ăšŰŃ ŕaŕ™“ÚF|^Ŕ"; ¤ŃD–Ş2XcŃë•8}ö,ţě}˙ŢőŢ÷`ĎźĘ>lžÁp>„Čľ-Ąnšř§ĸä5›‚îSÁtĐžžÖ·]–LÎ9?yíôvlFdyßś,ôŠłŠ"cŹ^ÝF´ę6 8 4©ť˛8a““lÝr>µn`LČhĂnÚ5Ž)$®¤DmŐd i’,@űĐ]ă[OoǸH!Ţ r»n˙EđŚc'ˇZ]Łb ´`ĽµéôQěĎvY gN˘ ĂčűxÓ’ĚéoÔo#Ď˙ ˇŕó]§YcL+Čeč^Cţi–ÂÚ”űŢ+3·ť·1VuŤőŐ5¬ś?‡ŃpĂ=4ˇU}ßúΉ† ’mq„úU”ÄŃ’˘Ń’ŕµ4ězN¦Ă`Hôd¤ÁI›zTůG2„ő;éňp𫮤Ház‡Ł®ązĽ÷^ú8Žľz‚wÓ6ŇŔX?AZŔ±Zâ·0đśaŃXrň“„RYY ěőĐź™A^”őĂďy÷ä/ßűa”qkßÚŽ~ÚŢďUÉźđ]ü9:dĹN@D@´â (ľâ$8`đ]?üăßtß›ţá׮ݮúńĆĐÔ•v¤I@ŢÚI 6Äd§Ob éŤČ@›‚€t Î$ ­ŔUŰ·byiY^V 0f2y07wd#H˘räç&1(ËëkëxĎŢŹ÷đxřĂu ÓëAď«& vĄŔľ9v® ľV•5©ŘĽüéĺEĐër§”É{bňľ ‡»ĚsĚ z(ňlJ:ŕN9ňŻŃw‰ĺXĎ›$’¦RâÇ7ŽňxH&ż$ć0”x4®Póvľęwüʵ e33 Řó˛á\ęëŰýV? \COť ›RŔ«t˝Ôçe»ˇSÚeöBw¬b/i@Ú·$8165›&´ mópÖUŐĹśU¤ýÁüfâB®w±p4\ż4ă ‘0L´}ŇuQPc}m ĎźÇx4 6xAÜ÷LDőµ,57Ş=)‹"IĘwť{ Ůpírş  ´I@–¦Č2&ă‘ʨdçômŰ|Đřx˙`ß—í jž5 í”×#4®Ć­·Ľ÷Ü~7ĽűnlYXŔhEëzťµ ľ´IK(“Ç9ŽuG}ހчîÖŃEÖ‘„H¨ň™aÔuŤáú:V/^Ä €–ůá[ź˘I h|ĽĆË<ÓÇŚ„ĐhŔo‰¶ąA¤t§DHÜ$IeĽ÷ č&D+ôńľę˝¬YqK Őq\UpM×ßt î˝ónÜ罸ć꫱1Ú`?şsΫ±ku˛~'Ăc@&Ś,ŕ1®*¤‰ĹÜü fĘŻĽ|»v=Ť^<×4´ÝĎVNŻŐ] ź_¬|Ś.ÁL(q"ČW$AšfH J!MqügP”Eóř‡?ô®÷üż˙ő˝ ׿żöđď:ú®ĎŇńą&ú“W‰°™Y@4ýoűç?řŹßř•_ýŤăáŘŚ6ÖQŹ+R“Ö ĚpśgvŘ$Av°'·µHx±É?ř ŘHD3tĆb0čaëň"–¶, /J¸Ć„`˙á^Ş7é Ř6 ° Ž%±ó‰ą˘ĚrdyŠ'ž~ üŘGđđÇ>‚çźŢ¤LY š Zđ “ýi/ŕ“÷&ë _§ßżu.¬ěťňĂCN`0(Qdä`©±G¶čEe?‡ď•s"HŮj*űűyq”€@ŤäMTJ;U`€¦ń7ČČÖFĎn­BĄ×„¸)eăqh‹L%#đĘłÎűvb,ýŁöŃT‰Ňµ%®KRn/á­ß|JAnÄó^«öI0M«ˇÇ]„lZą ·W@^ÚýVĆS4ÜĎÖRp(Ů"[©“1lh„¬ Ź8Ý®€¦¬äüpđ~~ąťŘÍ… H6 Ř˛†X*ď]ż ší˘Š-’ďŔOh%R!8Ţc$6tŻë&ć 5u’¦ŮqŞâ ÍhkvîÄ=·Ţ;n»·Ýr+Ś1¨ęĆÓvľi{TťëpżÖ¤ µ ]$3ł}ĚĎÎ`Pd8zřžÚµĎěŢ‹ŃxDZ¸°>!o|xhĐŢĹľ˝]ď=첉DsśŇ~ţ¬Č%Š^Iˇ|çf±o÷Ó˙—ßýß˙ř1içŕďÚú…«i5Űgíř|#ň*$@âh'Áiţłć~đüą·Üqß_şľ¶ęÇ#ÓŚ+vâŹü_°ÝvMĽ•2—H®wń …X‚Ç´H΋Td¬Ĺě ‡ĄĄlٲ€<+P+Pp0° ä,\mę ¤~@ŤúRhŁá‡ÖZ‹˘,áśĂÇýţćcĹĂű^Ý˙P–0EI*ĎOš`“s“żkź›dß°§•­Ďmô§«¦ď’uťšâÖäY†AźM­śJý§VĄ–$+DĆË.Ö$*ł G Ž5´S€®łŤ¬ńś8HsmőĽ,ţ~BR„ňˇNQ4ʵőhĺĽh·ĂŔ ;ěŐśnWú\LĄ+”˘­‚hŐ_f©¨Ń­MBôŦ© Ö+¶Aővë\ ĎôęBń†ˇCĽěcĺ¨ľŞżZßŘ„v*ÄâZýĎ­áş4uŤápµ•‹¨Ćă0BäţŃ5ŔĹçZꢥęVYB"»ZľÖÄ˝ű@'á‚`űW&‰$±ČR2!I2ď⽢äĎuwägRU5Üp…ĺe:;#¬Ŕľ5M\űä„÷€±@ŻČ°0?‡Ą…Yś<~O=ąO>ő,V.® I&—”„ ÖÓłą  éç›řE“DĎ5©ú ř)k_^ü~f~Ţ9tđ™˙ç·~ămăŃčüĺO€_Ľűµ­˙s*őëăó‰čC€&]łŔ4ŤŔě`vfŰŹţěżůŽť7ÝtçÚĹ?ŤL3®‰PJ­Đq$ IJɲZ^ŘÄ‹T«ďąňđÍ zXZZÄ–Ĺy¤i†şva[ˇH€b2)S´¬ ®áĎ>¨ŻL\4ŕ“ µ˝˘ÄĘú>öŘŁxäńOŕŃ'>{÷’† WN×ýčN3´ĎOçˀͤř‰ë7«‡ľN]n¬Ź5 ňz ąîyY™ź!ŔNý/>$ăńIXĽ—„ęŽÇŔĆ®şa'Ľű^Üç]¸÷λ°Ľ´„µµ5r\ó–kP7jŰ×%’Ó0ĺ.ő1žô°ý˘ŔââfúxőČ«xę©Ýxę©=¸xń"’4%^kcŕ'Ú5ŤL[+â”Ŕך¸•ĎĆą&)Ň<Ţ+ŃëőüĚ‚ąpúô+oűý˙řGÇ<ű.đ‹ťżëä×Mäó9~9>ź €Výił@×?@ţµ×ßxĂw˙čŹË5×ßpëÚĘŞŻFâ(ذŹ@Ś(hŤEbxű HkĽŔ2AĐŰF@±ĹhĂSŔHžh„‡Ü& ˝[ç°°0‹JLjKU€“•°ů@€4„»´˙ ôŞB z´%¸ĺ\Nč˘WuťrÝ˙0DÓD4M $ôĂdaaTzś!¦Ő˝®*¬ Ľ@ą-Y‹vNŢ{Ů%Ŕs€ˇ2‚d†=üÖ5Łáëkk.3ÂxúV&Â@¸ţâhŰ,ąB6¨¶ óÚŽĐ–č‰0P96ˇ­tŢ{TŁ USˇv ęѨ*Ürëđ¦ŔďżÝ{úýÖׇŹF¨śăťŽw(84µÄéWů/XĂ)‰ŠDË4u‹Š2Hf´ÁL‰Ą-ł-ű8tčv=ń v=˝+«kČŇh’…µ,×űé6Ś›ÎżAÓP‘Kyf TŔ82ÓIÜţ,Ď8ŠyöĎĚĎ› gĎ}ß;ŢţÎçžÚő,䵍_;řucřOKßű9ŕó—ČaÔ«A{Ë`×?`šF Íή˙îý‰·\÷şo[»HD ©j wÚ4ŕyĘ΂DŚM_4ŞoMÂŻbĐ;˘i`‚X°Çą …oK+K,̰eaeYŔ9JK>Ržm}Ľ …Đ“ţ"]U¬Ö Jx"ŢÂö(Hpś6±xfĎłxâ™]xâ©§đÄ3Oᱣl6ćGnËć`9Đŕ0 ěŰżź˘)»ĽďţľM&˧űeYŠ~Y ăČ|AZ5Šâhé$ˇj¤ÚŽ2ťlŁcOnŮA~!UÓ q2¦&Ś-ÝY‹€ŠhBcď"@H]˝Şq×ń P1űUO¶ŻŇ~pťÂâiCăÄLs­=žäcŮE¨ńĆn$Ö˝ŞF×DŃÖ D‰:Öšű¨CĚmď㌟FÜßV’6™@°ŤWA_Tż6MŤńh„ŤµµŕĐh@ntôÜuvh­é|$ Ô^HÍcňąĘŁ_|¤ďďä{ľVˇťw˙–Ńh„^݇»o»÷Ţy'şçn˙ĚSĎ‚Ŕý"đuř^IŮ;ÍÎďĎ®‡˙•źď@˝"ww HHái¦Y~íď¸nçÎ˙îÇţĺ[®»ůćŰ#¨BPĂöM(틉@śvćźŕ`Ú’`Ü=` yş€Î) ÷Čňós,.̢Ď{ýë†$Eý ‡e›:¶±j9úđ2Iţ=×-ÍR”y‰ +çńřS»đÄ3Oăń§wa÷3Oă—0,AKŘb#Ăcôbľ™V`:@·ß+đ ż™vN~ueÄ ĎRôĘ"DćëÖ[Öęh.LĘ …Gí‘&FŞ[±‹Âű,„–ŁrJŇ —„‚¨bLP„8ëŞ:j›\<"0+°—öřHDŤHDÜâ­>Ť,x€ĂĽÄ/đíkŚľ>Öő“hG¤Ůúgd·€Q>&¶,Ěďđ+n|ţŘVEbâ[ŁŤh*0ÜżBŰć´öBٸŐx„ŤµuZ?4ŕ«6ÉýÔr<Ű/Ş÷c{śÚuŃŠĹ•® LZŕjš¦F]Ťďńş›^Ź»oż÷ßu7îąó.ěض ăj ç$–ŁL& Ň”^ĹDĺRń;Îléč·Itü 1PN µAK[ć°¸0ŹłgNc÷Ó{đŘăOăĐá#pΑ9MÂeŔzĐŢű.hi† BĘváĐá9"]ÜÇżďÝ IDATm‚7?™ĺ8QO’"-2dYŽĽ,—zýľĚĎ™ó§_;ňž·żíťűv?˝đ˘ćżŕ˙ĽR÷O;ţ® Mä/Á¤Ł`7˘ h\»óşďü‘ű†żčÖ{Gk덆 ĐÂůŚ=wŚGşÂÎú•÷t‹V l3€Ń; $@ۨŬCÂwĽžĄÖ˘ß/177ąŮň·ŘŘ MA–µP`­†pšů@Ţ\ÍŹÖďăůÎő&–đČÓdI‚˛Ě‘Ą)ůŰ©¤x‘&M¬u€}! N€ŕń•…YrG;w+ćÝÓyŢGČŰM?‘i —Ş}A´©IÉŢó!őçÓüpGĘŃ^§Ś“¤nB*YŇžşŠ´4&>ě„ČÁĚo®˛‡rÔyůa2+Rş$¸ę@žN8/a\I—‹„Í‚ߪ§săŃĂ "ž ůŢĐ+‘5ť@,Ő#úDň[ľŇß*u4Ýף®4uŕÚkvâu7ÜŚ›o¸_tÓ-xýM7#I¨‘™„:öĆYBęî,±”¬)If RnĄ·łÖÎÁŐ“D ćĚ}1 vŞ®Ń4Ž<÷=lÝ2k 8„'źxOěÚŤÓgÎRh"ĹĘb sA^%đ¬U-€ |‡nŇňŘ”üQŇ,C–§H vî#‰3s 8ůęŃ˙ňťň/<űŚżVóoüÝ`>‘ť}‚?đw‹ČŃ%ÓâLsÔd ź¦éŇ÷˙äĎ|Ý<ôeMU›ńpĂWăĘi€rtł3KzÁOŔpTAT(źXDâ X D´úSXŮ—mÂâ›ĺ)fgúź ? í@U±şÍÇ…aSAŐrĽřD“ÔbOŇ-ÄŞ“$Ež‘ťě•ŁG±{ďě~nvďÝ‹§÷îFsáç@žS.~iŕ"]ŢÁOÇ3F¦k âyM(ČşČs¤âđ€/:‡†÷"^ËT3 ”ů{Môb`DU9˙¦‰ŚŻ­yŃŚÓą$%¶O0€@DÂkďô`!ł€®ľĚ &µŠó hV­–_€ ěäÝĂ´?HR.@经z"Qń^@d‡·– WAĐCł1@YdťéŁ_8~üžÝ»O>ńöżtkÁFϢń]Ѝ! ;tx˙Źó—ď+šXµű†ÔüečcűľoĐGo0ŔžâĎţđţâěé׎"JüëŘÜąŻëŕç1 ţź·ÇßE ‡&Ýř:˘ &Z+ ýoűţ˙ţ+ßř_őŹňĽ ×Ö}5×Pžď< r‰%ŔÚŃČ.‰÷ž°ż€Hţ’HśY‚Ů`@sv+úM’r¬±(ű9fűĚΔȋđUUŁŞ4Jz@X¸řPÚ—˘TĺĂ<—E:Ô+ ~ ‰±Č‹ E^ŕÔéÓŘ·˙<÷â><˙â‹x~˙ 8řŇ~ V”1¸Ü¸,1€z/ĽOű´k§˙V€ŕ;Ń" “ŕ«>ʼnÇcÂHóřčíT˛EKâJXVAÂ`/•k#ąĐĹÇżµ,Ě‹0(!ă¬ěŘSűIµN.ĽĚŇ ÉaĽď®s1üuTD0ßZ¸KÂt•íY±¶Ž= »d$%´öo‘<‘TŃ}tůź`7ŃaĚ»p$ľł„Ëýĺ“CŇ$h×÷ Üĺy‘űDŰż ŐĂĎ#Ͷߡ®ç°|ŐŐ¸nÇN\»ă:ěܱ×^łŰ–·ˇijTŤř x8ő\ŢúG@^9ň’ş+MF»úúłç=ů&|䢆7a^™™UçA+ürďŮłB3®ŕ\Ť†ăxĘľF13ŹmË۰mi¶-oŶĺí¸jëvě¸ęĚ fP7 jÇLŚQĐ ‚¶¦‡Ľ7ŃAÓpě 9ĉj(VĘ*~k lj2dY‚^ŻŔüląŮ,Ě`ĽĂ‰“gđŇcx~˙aĽtđV×G̉‚ą¦&rÓ4pMM€9‰Ď§¶äijÜeÎĂš(ĺÖKk-;ó%!Őt’SĆìČçlßď—ľ?;gŞápmĎ“O>ü§řű8ůi ? řµG˙đËń…HäĐD@H€8 NsÔZ®‰ {ýíwŢüMßý˝_uËm·ß_U5Ćà ߌ+Ó4MH>DÁ…äd•żáí&–ÂHâ¨Ýjr‡­…lc‚ń:őóĄ}C›ÇEÁX4IŃ+3”e^™#±1AÍx\Ł®ú5`{X§9’IŔÇmV@PÄFxIC¸—‚Â,E¤1ľ™ěÂHSęKŕčńc8tä!RđĘ«Gńę‰xőÄqŚÎś’”B’Âd)›°ŔĄŁ,˛-°‡ŽÄgŇ„†Ç…»"ĐC˝ÂˇP@S.j35ذĘ\|íVť€B«¦?Ô¦urúc/ćŤÍí şodđ•ӛ떥ʗűÍS§ˇaľó yŇJiÄŐî;Ż:%Ě˝pJKőúĽŞ°’'ir ocs¨ňöŻë˝~‹ó‹XśťÇŇâ¶/mĂö­Ű±my;¶oÝF‘>Jô·l€w hŤU$ rÄ–â8ň¤Š„Tk*ây@¶72…1FůIĐmd])ň[ضe۶-ba®‡•‹«xéŔ+xîů—ńÜţ8vü5ŚĆŽśĺ˛Ś$ę4C’$äÄŮÔĽýŻľBĐ q5Ľ“ä<ŃáŐXúdĺy2Jł–GCTüIKÚ§:ćȢ7ż/ű=S8ţĘá}}˙ű~ęŃŹíIđëť?ý1&÷|ÁIüÝ㠙ȱčĆĐD`32ĐĐűćďţŢ7?ř%_ţ¶_síÎáúŞńČ7Um‚Ż€‹+´$"2Ń_@4©ě ·k@ł[í7`-‡ľ4A ,D€v\˛i/@ŃÁ˘ČENŰ䲔Ű{4Ş0®jŚë:ěŽ#ÚH:‚ČÂ-f-lú–"lă Îk⯠RuPÓ*đJš$)›ÂˇÁń'đęńă8râ8Žź<Žă'NâÄk'qâÔIś<}Ă ç‰$X “¦Š#ÖéŕNX#5B Űŕ˘7˙–T*°Jw}Z‘$)ëJúuŇǦX®‘Z©6>ąEAf€«éôjGkWóHČ!¸wĹ"L#‘îŁJˇ=âeR‰H[c-ĄżĘŢyÔŽâ€đćy¤˝¶Ě/biË–·,cyË–—°uiK‹ËX޲Ś,ÍPŐĆ㊒ă„mąÝ1™¤2–Aśž]ßq~(©Ţ¨`Pbűbr›8ŽL®d.yęŘĽH±´0ŔňŇ<®ŢľË‹ó¨ëŽ9†˝Ď˝§źÝ‡}/ŔŮó«0Ö" M3$YN»ťRÚ+ź¤é€M#á׸¦âí„5„ŘĘsH´ü©čšř6:ó% Ň,E’ňö˝ú9ňĽ@Ń/13;‡‹çÎťyţé]ýó?úĂŹ‚¤ý!&íúÝýüÓ"÷}Áż€—#Ó M3™ ź™™Ýú?üc_z׾ą?™ÝX_óő¨6ÎŐpµhś*ÔD­€10‰EbRrZ±–"RÉVCµw\Ň[R̨°Á FŔ_ÔĚWF,Ě ˘r@3LX˛)›bďđÚéÓxí ýť:}§ÎśĆé3§qęĚĽvú5Ľvć4y4Ź*Ň&X $)íöŕ€B€„Ň%‚öŞ{„DRZ­+őˉÔ]=’˛¸GÇ(ŁpĐ«K»’żz¬MëS<"–N•Ř?ĄĂ+â»·ĂwH’ ±ë®©ľ}ťÖ8HúlÖ6Č\­BíH#GQqrܵĹě,çć°ea ç°ea ó‹Xś_ŕĎ[°ea ˛"c`shjŢ®hŔŽ~<˙Xî0Ař¦€Ö%&·ô˝ŚmÔŇ ç1ç¶5wdF„˘=`m‚˘L±´0‹í[°}Ű"¶.͡ŞĆ8|čžÝű<ž~ć9ěŢł'Nľ†şqČó‚ĽâÓiZ ÉR¤–mčIz€Áߨkzď45ď¨ŕYÄO$ń[Ú"-ë&˛o%kŰőł9şD@“®Ó`w+a"šô¤wÝ˙Đţń·~Ű—Ľţ¶Ű00f¸±áëŞ2ÄŽŐvB€}•dˇ2 °Ô/{ŐŁ™@2š¸ĹPi‚–3!pĹŔł‚ ţNR*'i–’“PFŚÜŔSÄÂq…ѵă:8zEśęěY›$n" QÖďJ—r×˝ŘKeë•,š±,˝O_{ÇÉ„·Zý6Ž·>âěůs8wá<Îź?‡łçÎáÜĹ‹8wţΞ?Źsç/ŕě…s¸¸z+++¸¸ş·¶Jăž2q?€#†1‚ô»š¬Ć ¤)f©nšMđ÷—xw…·‡‚oăC\|AFéÎIoOď%3ž÷@Q˘?`¦ßÇ`0ą™ĚÍÎa~0‡ąąYĚĎÎan†ŢĎÍÎan0‹AżbŐ»Żľ €°_ŔfšM–řŐq¸^!ąqZš‰ţĎŞ©STú€„3 ¦6™źJłb­AžgXśźÁŇ–9l[^Ŕö­ ťéamm ‡ÁžçöăéÝĎcĎŢpâäIچ#~ţcŠó$ÍH[–fH“IšĐ_Š$äDż÷ KúLř˝ăí‚Ţ5Á$@) } Š•D‰_Ľ÷-;%&i2ô)6á{ýÉŠÇÜűŘĂóČăůĐ. o -ĺkĐ˙d¤ý/hŕ—ăď#ĂtŢk‡ÁnÎm"Đš!˛› Ĺ×}Ă}oţęŻ~ŕ¦/zĂ˝ÎcE|ăá]ĂŇźźá¨rťIJ› M$E±l+¤m9­(„×Z…&0ŃaŠEÍöÉŐ”á»ţR©˛CI¬…ó ŞŞÂxÔ`\×§ ¦'ĚůÖR©'”v`m@[Éŕ[«µgŤ‰ÔÇRŰ/mi®u&r&Ěí!›DňDpX‹Ťő \X]ÁĹŐ‹X]]ĹĹ•U¬¬®ŕÂÚ*6ÖÖ°>accëĂu¬‡XßŘŕĎŘŘŕĎĂ Ç#řq Tc ©ătĺ1aq’ηRŰÉŃ='íí¬{­ŽPëc0wůř»¦ Ž™H3äY†^݇^Y˘,{čĺʢ@Żěˇ,KôŠeY˘( ôŠÁ3ýýf}ôűĚôgĐďő©Č†śĐďá9đ ĺ_$=śhx§…Cô>ë6U5YéZZŻrŮĆ9ä[Ý4ŃE¦Ss–BCć2 ם$űÄXäyŠąŮ–ç°ĽmW-oÁň–YÔMŤăÇObßţ—±oßKxnßKxńĄC8ţ<ęşááW…˙ż˝o’ă:Ż;·_3łO`ń$@€x ’ Ą˛)Çq$K±JvĹŽËÉŹIůLURVąRĺŠă(v‰Ń"AIA.,‹Ýö=łÓÓ}o~¸÷űî×˝=€ ÷Áéîéé÷ö9ßó‚D‹?b"d\Ng+š$qĚÄ^–5ňç¤@[`Jş/4ô°m˙ěăů.‰/N*–>ĺpłž,EÖn›öÔ´ĘZÜ»wóĆ»?÷˙î'ď˘jÝ7%óĺ8híËV˝uŇ!źđ" ‰şW .†…ęÉŇ3Đýđ/ţĂ·ßţŢľsńĘŐ7µ1Č{=S…ó hŰĎŰxK™\đ,‰Č1•F.lŔ"Á%*_#,’q~(1VO&\V»»jÜáÎÁ–y®7N’Č +\ڱMpúůŔV! ô…ëW %Ç:n1ü2; č–ůý׼î­Ë!é °kŰe<úßAQŔďl'ÚDÁ‹®÷›÷V»qOYď’ÜĘ‘»Öµó>o€G-pó~Žţ ·"«(÷Č}䛦®–Ą1®źkE¸¸´m۬¬Eű,Đh™pÖcä$M¤IjăĆ.;MSdIĄ|=ľv.sc¬NÂÍÖŠkgŕkĺ°gŔÝ[/ í}Ô Ü6xä>cŘóPÍ‘đb‘XąBřţÖË›.o%śÎe·óŠG ¬f˝g·čĽNbT@jV”$1ÚťŽšĹ‘…y;zÇŽĚa~nEQ`mý>[Ľ‡O?»_˙ö6n~ňÖV×Đíő9Ô'Ć_râÇ $¦źTXk?E§VpS Ä’ĽÖÚ·Ä_—4i=DúĆ”üwfł÷]"őáĎśĄOĄ{dé·Z¦=5Ą˛v +K÷>ąńî;ďţĂOţű»°MzrTÉ_Ćô›\üőţüMn~Ô¦żń Š¦đ@Ý+POlň 4ŠýŐüöŰßűţwÎ_ľňôű=74Ck[›oěkJ)jDU˘ÁP¬Ä4%’( MČS@ŃPY! TlŐ¸(5¤x$5«y@YÔÜč vÚ×˝ “D!Nb´2;îvš:Íel—5›gPŘpÂŔZ2v,­µQ ‚ô&§×´´ňÉ s0Rŕ_ëŽŕá—Ůměę!›ňđ ű)°‹Ă˙Ţ;Ič;/N¨5‘1˘Ť- #ş t®Ć@™ČmOsٻܑśRPÜ*¬ë^űĐNýÜ)§ĂŔ]?‘łAWŠď]Çj¨Č‡Ľ«ôw"D"ť ďőńű¦Ä;~4*/AÖt¨]rÚ7Ý:%öí6¤™JŚór I’˘ŐJqh~óó38rx‡Í`áĐ[Ľ‡ĎîÜĹćĆö÷÷YVţĆšHŢĘüX'ÓÔ‘{ł°%ĚÖ%%6ąÖh˛ú­0Ňę׆ ßr­“\¸’¤¶3_J®}סĎĆc:ÓÓ*ÍR¬.Ýżýń/ß{ďď˙Ű}¶%/ąřĄkżžÁ/köµ?A4Ł"D Č$¶›O˙ÍżűŃßý“ľuéę·ŢěĚLuúÝŠAn›ôHĎ€ë±M1x"mnIĚyÖ ű D.ą0V±M8ŐRTX’ŹŮÚcŻY„ôŹ­Ô'%„ů‘!Ëđ#Đ)¸n}®‡ąkăE F 6’ç…ÍÂ.K r?Ľs…+" ’W˝0¨’™Ţňç#,}*Y”ÂĂ®÷Äýௗr›$ńT%ěg.á@ ź›oÍ.ěŠVňŞ„·Ă’Ćź'—ë®jçF·‰š„í›Ĺ$y%âňU±âŹ®wí>ńT÷'Ţ=M"ńúĺZŚŻ…¦/çŐ°+%q„$M0Ýicvv ‡ÍaáĐ,šĹüÜ "ěíîâáę#Ü˝·Ś{÷ŕó;÷±tË+±·ŰEQ” Ěw! "u·Sî3ű,@’ ŽSŰ ÎĄ±Î;`«•/˘IżÔ[ř0.aÚ/p#űΠާD¸÷ł,CÚnˇŐĘĐ™žÖZß_üüĂďżó/˙ü÷˙ăX _’ľtíK+źâú˛t݉ôëĂńľ°ÄO`2Ô=$†UP ^ZX´ÄŻĽvîÇýźľóęo^?rěř±Ľ×Ă ĎMYĘĐ€1öŤc(äk ™*rV?Ǣkă°÷@„|‚›oW¬`cúô``qĄ…ěp/{/¨d„@U PČ€Ę ąE±ËHŹUµ•rm.ś((ö¨*ą˝x ¸%čĺyIDATż€žF€ĆA×di÷źłŠśŹUvÓS H“Äz˛­,± D™=ĺ:ěŃpĄ”” eAîĆ074Źá›mä{Ăş·(˝&`6ö.úČ8˙°#Âa.9â…8'Úˇî÷n ¶P©<ÎH'„pĺÓvśŐ^ń°}ďö&­~#­dž¬i*Ţ"ďęą±—…­đš'Bz ×o>w>§Â í N ´U¬2,A%I„4K1=ŐA»ÓÂětÇ%ŇgIˇ,JěîuńřńV®aĺá:–WV±şö++kŘŢŢAŻ×Ă (ůˇż ?Póôô7ÇŁ$ÚőťTJ!N)ŕâđIę˛ý]}×h'¦ňżÄ%ë%‘{>ý7¶ŚśŃO˝ř“Jł[§ź$ ­¬Ü]ĽuóĆO˙îoß__}xĎťĆ>ZůM®ý&÷ľFpń?‚x:4…šÄ@=PŽG0*w Mëľýo˙äÚ~˙Ż_¸ví[GŹť8–çűČű}Ł‹Rm“¨¬p]Ćś}F­cÉÍďG0ôÉ‘-Šă¸ćEp=Čs@Â"ň=(™˘{a%2ZĎJ¸i:eÎú†cťČŔز2hŔ’ÝżV$ŘŇĚiLBˇ•Ů:g› Ů ćÂzŠR;‘P¸ÖÉ%Š˘DQlm]VŢ4ÔÇ]+ńŔHkĎÍ[˘T˘ĂťtŃ{âł/^şÇ*@|JBs?…JYĐĽ­&˘˘„-l˛¶˝Ĺ\±¶é8X%HŹ_™zHü,Á.2ţ—LꢔË,W˛ÔöŻ·˝+Zę´ŃigčtÚhwÚč´2dY¨E1@o݇Íím‚µě8čŇ—–ţ@|Ökő›ů^ř„ľ§A_ăňd ^Z(Ë ›Â$ ZĚ˙Őţ›7Ţü·_?wńҵ¬ÓI˝}ĹŔ… Ś«MvoM÷çŔŮÂPÎĘŹ*ź\H‰e±Ŕs”bďAD€Ř÷ ?;Ył/“ô´łH+­†źĄpÁŻKc]˝<Ż’ÖYéä¶§áJcr]&Čś`HłíĚş3ă*.¬üŇĆđěV$h yY@J—}o‰) Ę–¦÷¶Ě†$ń5Î ó2Éůőw á/śO€HJ¬jx` »ú[ż+'łD üń°EZý­;p&o9Dvâ,M–6KcŰĺ­•8÷q‚,ÍĐjŮA¤R7ŞŁ^ą@ŻŰÇ^Ż‹í­=lnď`gg›[ŰŘÜÚÁÎζ·w°µµŤý~Žýľ­ đײöB4Ň+âďŤn¸)Ô%ףkđĹ[ýRT‹űEˇw¨˝•HšG‘­µ§öľIj«’Ä&čĹi‚ÔĺŘu7B ťŽbQ»OŐ=ibŇ4UívĄ)±rďîÍŰtăýäo?ÜŰŮZwíSâ^=Ž/Iź\ű“dďËź €g ŐđIb &hĘh 4‰‚ @tţŇ«Ż|ďĎţüÚŐ×߸zú•óW’V‘ ĐE©l‡>?â\5~áó„ Âq»ĺ>Ś [Ç4Â! N,*ř?Qvy»Ĺô’­Ş×€ńY ˙‰ ÷vŰäw|I Kun[Fű.ť.’(˛/Ô(˛ ńR™\ě:śŃĐ«*B[ËŚĘ1”+ŐsĺrÚ dŚ+µ‚MĆ*í°ÂZC‚DŤła8ź0~Ľz"mć"ߦղ…5ĺy "WoF!'nNĺjş} kĹÂ*R˘Ř¶»NRűüřgÂoa4ʢ´-vű¶ˇÔţţ>v÷şčíďcoo{»]ěu»čv÷ŃÝďaoŻ‹^wýLăäŚ qĐő™śż$ ŃóÄĄ®@Ĺ…Ď®}Zŕóp{âD%Bö–R® âŘŐÚ'H’Ě’=•á9Ď@šĄvY’ ÉśPČěóĹ1’46IšŞv» Őĺű‹w>ąuóźýÓŻo~ô«[°„MV~=†/ _şő)žoǤ˙Ą#€/Mb É;0LhJ(¬‹‚@téĘkçţřÇvíęëo\yů•óW’,Uůţ>ŠÁŔčR+CăĎ“5n|ĽŘQŹčĂM/÷އ€Ă qŚXą°kŰI pĽ‹LhžŕL,"™Ö'‘» ÝËŃÍ% ć‚Ą·Žöox'ŞEk özs˘‘xiśßҸ¶#~nÔ'ĘĆd)Ç"¶—$QPÂ+“$–T“HąR­IŠňCŕGVَU©âĂ=ťĆ…K¸.ż´źÚ)Mçˇ JW‘AaAQ:.ÜĽmSDě…ëűŁź÷Qš‡ľ-KÍíwézĐ˝V ’ôĎ [ľLt¨ô KĎ}_ź~. 0ďbo”۱mD‚ÍMĐş{TČ»Â=$\(Źcô‰íßČ~¨$/Md™Ż™˙.ke&ÍZŞÝiC)…ŐĺĄĎ?ż}ëć˙÷źóëŢ» ď˘o"{™¸WŹă7YůĂâůôź1‚řj0N (x!0¬ůĐ0AĐä%HDWţŐëç˙řOüÚĺk×.żôňŮ‹S3Ó­<Ď1ČűĐ…q ŤëĘGcĚ+תCäđ'ő°I‚‰đp‰!×®%$?Ä-W çŞt&')ôr^~Á›šĺĂÖ,˝Ĺ‹ÔőVř*€á]ďĆ5¦˛®}ĂńŹL[«ßť!ťŻv~cs ČĚ¢&4Đ´»ć]Â/§ë*¶A×]˙âXÄď”\^óŕřcá-Ŕç4“¨ýÍpň®OÓůy’ý €Ď =3îíóá^}»Ă÷-ß÷çkDÁµ8„H“W˘„׉ő<0 ‘Ëâ' ?Mmý}’Ř’Ľ$Ël›ďV iš™V§ĄÚSÓ(ň=|đé˝ĹĹŰżúĹĎ~űŃ»˙ď&Ľµ>ĘşEř٬|ú¤“¤˙%!€ß ęB`Tî@“w@ŽUĐ$RT= €x~ţбüűż|őµë×/ťąpńⱓ'Oč˛Ä źŁFëR!s-yvý*ŃrX Ż€"@V¦ňń]ÔĘç% ·˛Ŕr*ŁĆŞźşB(ţ]i଻㨄b†ž/`É@ŁqǡyMžvşŔţŠ­uţŻËŮâ¤ţű>Ö<ž â0 ŽÇŻ?nÝęôs#Č5OĎĺ¤8O„fÖ7ţ8f7tteµqÉśB\‘xĄ10HĽŠ‡ť˙V8˛ć-{iáűO—č+úëŰL~7@jó)¨ O–µ¶3´:´˛v¶¶6Wď/-.Ţşuűýúé­‡Ëwďş‹'ăř9FÇďe źá7‘} ý/AünˇjÓĂţIď@]Ô˝R ĽŢ~˙—ď»tůâŐ+—Nśzů\gz:-ň>ňÁK—šăĘY-Ő­6 Š”ŻBúÎ-)ę*hcĘ&őđbŔ—Á‰X¦ďÚ #_Ţ- Ję <uëT¬š®Z¸v±°iž-lđµUŹIó9{‚׆vâ­z›đť(í}–uřU/ŠňK,v!<úŻç0ŽčËąócęßa«y”:7áO—՟ؤľ4K')ÚS´; ň6Żßypďîgź|ôá'żřÇ˙y ¶ëĹđëD/­úzÂŢ$„_'ű:ńŁ6đ%"€ç ĂBŁ<őrĂ&Aâ`‚a=„§¦§Ź|ďÇ~áÚ›×Ďź˝péüÉÓ§ĎeívTäąíTXş–ĹôňÔä']ÉŻĐ8 š–M„ D/á% 1 Ŕíj#¶Žč­évPń”*GxJX\˘0˝•)ö-ČŠ?k.mźHćÜŔěŻ+KÚäúĽ˝Ú¶9l&1`Ľ'â…D¸B`M`Éóů’Pö¦úc0µiw_¸_€Ţ"íô™ă$ŁD‚ž‚Č+!)·Ś/Ę_ŕGŐř\‚"—ľŮ“ż2Ňgâ?®[ř1˘$B'•‘ô˘Äfň'IЬÓFÖĘP l®Żß[{°|çÎí[ź˙Ë϶¸ůh} ž¨›,ú:Ů#ü¦L}Šĺ×­|Ô¦Q›řŠŔó‹&®WÔA˝!… š*¤( Y8zâŹ~ôŁsW߸~ţĚ… çOś!Ó ŕÉź7‘ž2 ¶ľä9°ŽĹ]çü– Ç„6ŕc`h@+Q!_ °Pžü ŕ:ă‰ő)ńOx\Ü2ËYÚY’n k Í*±öş·‚…ÇŃAÓěŃ"f„p9? ¦λó‘çćŕ+šÂJľOŤyŐNţşÂ{sśaâ®Yó$Ş4´&±§Ý}đ7^ó9yRŻL“5Ď÷ÓSĺůާŠ'J<\ľDÄ?Ď5˘Wҧd=ѵ3Žʼn×HźÜú4¨N’$KUÖj!ËZä9¶7ß_}°|çÎ'·î|ô‹ź/®=|@®|iÝ׉ľţŻ)v?¬4Żnáű‡ŕ ů<ŕëaá *Fĺ4y šĘe‚zŽA j·Ű ˙ú‡zćÚőëçÎ\¸töŘÉ“/9zě6Ö[ŕF+JgĺRĚŐz´vď^Ä•ŃČ÷&ą˙ á2ä›˝ µ_@É UŢÉĘ-2J`·¬áoÜ|M<0黕 SŠ#r»¶$#ŢŽ Ň*ÉóFĽUé–k·/nĂKŢ v9$tŔYdž%ĆP€Ö$,Ć{L€ŁBFC+X¨üqŇw,*b|äIňçď÷­éšĘýÓµŻ [‚U=wîxéÚłŐď˝v7~»žĎĄÓŢŔDţžŚz%gĽ—«Nöś'#šm1ŃS}}ě5סáxÓq›4ËTÖĘÄ ¶··w7Ö×–×,Ýą{űÓ»ľó‹Ąť­ŤexB®[ńőä<š–îű:ásçŹséK˛Ä˙ś!€Ż'ęb€>'ĂDÁ(aĐä5 üű×ßúöą7~˙÷Ďśżôęé—ÎĽrćČń㧦fgZĺ @Qć(…Í+(i¨Pg!:wµ5ŘişO+š/€ĺyAô”# Ľ@°‹…ç€C€Ë™Äţ4H8:"V±2 ‰ślwŃE.k,xd†ż›ňVľ< ´LzW„€ß—·ţ}˛ aÁô]“'@°ŽĄDąvÝj];Pî×{@ ö !ü>Ýp¨6Ź˘+ٵ­é§kYńH8Ň·˝‹­@á¶Á‚řůşÂ@”§ 5\[€Ë6)ůµnŐÓHś ËŢ%ěq匋×Űţů‘ëş— Nb“f©˛ {-t÷vÍîÖćŇúÇËîÝ]ľőŃŻ>żuăĂĎak퉜GYňMőöŁ,űIöáŤŔ7ăÁ¸°ASř`X˘á8q@ąťö[đÝłŻ]ż~ęĺWÎť8}ö•3‡Ź=>·°0oJŤ˘(PÚ±Ś)ŤŇÚ 'ŞÝ>ł5ŕXµ1ľm.‘S•±iąr!aăݰbťéÎs`Şď|ţžÉş®ťČí\ąö­3WŢĽ~âüĺ+§^:}úäÜ‘……#GOµ§§­ şpâ@kUÚŽ/>¤ uĹe-Č‘­dďú­/ÄČr•×—ôţ}…düşv[UíAjŔGęŔ‹+thw¦rśĆ :>ÍëV…„$uîˇ/Ĺ‘+‡ą»iéňć$9Aäîđ*žU!]ňPֵқŕî—=Âęqó˝LÖ‹±ť‡€]wRDČĂ˝©ĽnÁQ˘Ż~ťŕáĂŔ‹ 5âłžO §‡5,ÖŢxX®ASŁaÓ•^§Îś=yîňĺĂ®^;qôäÉĂ'Nś<:wxaaîĐüÂôÜü\’$(\kZ] P4ڞëmŔÂ@vĂŁ8¶X¦e~ÍĂ1k÷{2­XµËĽ˘ {XK_W^±•ß©kŔ(ż^ĹJ¦učwlU…uóŮó°ŰŚH›ŇGđçáĂžđ™› `JĎ‚*bÚ˙űkĄšľÖĽ›ő™w>ĽŁ¨+žksLm”#?/3î‰đ#§1bÔH'JL”Äʶ͍‘¤)tiĐÝŮŮßÝŮYÝŮÚŘŢ|ôčáúęĂíĺĎ—ď}úéöĄ»÷a“í€*É7ĹŢë–ű$îzIđĂbőă^’}ÓgŔ7AH óĐg}şž[0IŽÁ00,ĽĐ”‹Đ$ *Ç €ą·Ţţî‰3.>}öÜńŮCóÓGŽ?>537=;7{hjvöPÚjÁčĄëgŻ Ű»Ţ¦Ô(Q ´)ˇ]ŻzîYŻ˝ ŃŔV´Śµ‚Ś›-wUČáu‰ Puˇ!˝•]Öö[Ť‰ kŰkţŤŤ6¸u”AEź’Şş˛äÝĽp† âťqąűV5˝ŠÔA˛—V˝KÄ«ö”đ=ď‰Ô#1Ž…ŹÇ+D*2qš(Ů,'Jä˝>z˝˝nŻ»·ľ»˝ÝŰŮÚ\Ýzüx÷ŃęęăĄĹĎÖnüńă^wwţ’I"–¤Ý4=ÎzŻ[đĂ,ůa}SéÝ(˛Çů€AŚBS.AÓç°Ľ‚I“›D¨Ă8C“€Ĺ±Ňń¤gĎ_»čSWďJćR7Î}1 ďíúýýŤýnŻŰíîőş;ŰŹ·66vŻ­o­,ÝY}pď^wińÓ‡şârąŽ#íII}±Ź˛âë?ŚÜ%ů7}bČ|Ŕ Š žăĽŔxa0JŚ uo¸¤ĹIż—BAg|ôř‰c§Îś™›]Xhť<őňѹÇć:ÓÓéôĚě|gjz.ͲVšeqkjjľ•ełI–Ş$Ëc\Kĺ%…\GEJĐĆŁ8~_Úw˝Ě¶'®&ňŤ÷*xc_2p+‹;)„ÄP(€ó‘^xÚ¬R~,ţ”{l¬˝Fî‘tŠçťĺNet*Ž0Čsýý<ďyľŮßď úý<ď÷ş»ű˝ŢĆŢövľł˝µ÷čáĂőŤµµŢęňňîúęĘlbť$LI¤M$Ýd‰O˛lŐ>*Ë~R’—d$üútÓ|@#€€g…aŢ9=LČé&a Ĺ@SČáIĽ Ł–7­7É:ňře΄µ[íĂ'Ďśť›_8Ôšš™Kçž™ž™›iOuZi–Ąi«·Űí¬ŐéĚf­v'MÓ,I“8ÉŇ(K[Óqšvâ(JŁ(JąłąśĚ5˘ň8C‰Ž€ €LĽ“ţ~ďoh¸‰ŇZŕłćÝrgĄGP@ěNß”E ­ FŃş,u©ő@—ĺţ ěúýrĘÁ  úy/ďďďőűűÝĽżŻó^żčď÷úÝ˝˝îÎöÖÖîÖö`űńă|íáĘnwwç<‘JëVă0—ů8‹{G棾ÉU?ĚE˙¤DH>ŕ©@ŔW&1 §Umy4äűq^„ş7ˇI$ ›¶lśŔtŰĂŽI/˝ČĺąŐŻcýšÄ:33łíÎĚl:5=•f­vE‘Š˘X©HEQ!B¬T¬TEŠÜĺ.ÓÝ.‚ÖĄ± m´kÔ¤µ6¦4FëÂh­QjmPjSj­óĽŻűÝŢ`oo7ßÝŢęčÁ–¨Ť‹97‘ĐLŁ,ćqßMJŇŁâ꣼‰Ř'qŐŹšnşVMÓ_Aü®ĐôěM"šHPNO*&™•Ü8JhL*N†ÍŹűW?wL4mÄç(ĎĚ8(xë“ĐDÚrů(‹v’uâ% F‰…q–÷0küIČü‹ű(bDđ• €€ç“Š9Ýô9éôłü÷¤d>)ŃOr.Ł®SÓü¤EPMÄ6lŮÓŠ‚aBˇi[“’ő8G죖ŤşNĂćľrđuðgv”@P¨ZĂ“|[6L<4ýnT(ŁiýIö9Ég}zÔ˛IĐDVăDŔ°Ď§ őďężk“loÔ2ú$/Ş­‹!ż©#}Ŕs‹ ľi¨“˝\Ţ´®śnúí$$;î»'%đ¦íÉ&÷ţ¤Öţ“ţÍOJlŁ,_"Ńú÷_Ö瓬ÓDěăOý·_Kđ"bÜs?‰ő,Cýű'ťţ2ć‡-{VçŇ~–óO2=ĘRo"ěQČ=ૠFc’ż‘aäŰä‰ßÓw¦ay}Ůł>ľ§Aťżˇ6µĽOăRź„°©8đě!˙®F‰€ażö}?ŹD(ŚűͰuę×6 ŕ)ńĽľ@<†ýť6…~—w<°žţ?6Gűµ¸iIEND®B`‚‰PNG  IHDR\r¨f IDATxśě˝{´eÉYöűŞjď}^÷Ţ~LĎh43ŇHhĐŔ€L1` ^@¶l'Ća ě•eĽl ÉZÎrě$`›Ř+`YÄJb±¬p„yÄF K’%’FčŃ=ÓÓÓ3ýĽŹóÚŻŞ/|Uµëś{î«çötĎĚůzÝ>çěS»vťŞúŢŹÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5¬a kXĂÖ°†5ܧ@÷zkxi°˝˝ýfţ^ĄÔ·x@qŻÇ´†-€ßsÎ}ŢwöěŮß»×Z†5x…ÂŤ7ľŔĎx;3ßëá¬á "ř€˙ôÂ… żsʇaM^píÚµĚĚ™™üÎZĂýa˝č}=ôĐwÝëńkđŠ‚[·nQY–OŃ[×\˙• DfţtŻ×ű˛óçĎßÓ…4÷ňák8ĚfłO*˘·Zç0žNQUZkáVhű‘$˙Çf«Ş•Íş¶nU›Ťá<í$쏣ZëNp“ż‘ĄzY†a݇Ě8ć/ťÍfźđÔ ;˙0€·Ýń`ďÖŔ} źúÔ§~‘ľť°ü· Ž»QWÝw’öÇíó8ă8)Ň«ú¸Óľ—ÇúqÎĹ÷©Ń5÷ąĎ˝™?¤µf­5ĹUŽlË×Nňý*WJ­DÖU}ÖďacXţ­}^¸ÎĽĎĺ·Š€, ş'¬«"y˘»<¶Ă? üŞĎiˇĎ@Ř™ÖZ¶ÖRUUŢö¶·ÝÜ7I§ kŔ}Ď<óĚÖÚ)Ąhy#XŘDDžäç\Dč“öyŘőĺţV‹“¨Ié÷Ç…€´G=;%‡ ôűă®”Ф‘1†‰čŁ?öŹşCXK÷\Ľxńf~ â`řKąÍýwŞoż÷Üń˝+$ŠUp'ş˙˛´ˇµ†1Úvcŕśű‡O<ńÄ_:Ů OkpźŔĄK—~Ö9÷ťÖZ8çĐ4 Âűń˝ďÜ)2ž”[߉…ýĄA7›ˇąv ş( /\™NXn,psǡ˛ŔCg ý¬{–sŔí‰Ăîxč¬ÂfO‚ŘÝ]47n ;węěŮ•D ˲řŢZűŤO>ůäż:ń9&¬ Ŕ}—.]úçÜĎ·m‹đ—"€{Ĺý—EďăŽă0Ńř~¸'mźŢGĆ`ďýďÇ[~ň'ńI­±őŢ÷"ó›QÁřĚe‹ü7ŻĂřę˙ůWěâ]_›!¤lO€ď˙ĺ ĽPĺřzWń7ţăęÖ?ĂZÔ?ôCxäŁĹ'ŢúVĽţÝď^ ,J©Čý=`f¶J©ŃSO=U뇝ŽĚ»XĂÝ…K—. ęşţů¦i¸iÔu Ŕ˛ČĺúnüHmŤ#˝žŢwŐ=\Oá¨{VYĺŹűśăţ&(…ŮoýŠ^Ź1cöÉOŠTবľAkrŚľřA|ä˘R]ßĎ^kńâLcăńłřígŚNÖĐZÔý(6ú} ˙đÁu˝đ;¬µhŰUUˇ,KĚçs*ËRO§Ó»&¬ Ŕ=†ńxü UUq]×´,ö'Źň{)pëjŇ-ߌTËí–ďYEäşgylGŤď¸c[¸ÇZ żů›ń‘¦Á660üĘŻŚ.O0᫟Ę1řÔP}ř ř†§4wĎyÓë5ŢĽű"¦˙ßgń­_ęP·‰1QkĚľáđŃůĺŰßĘóĺ€8ÎŔ üľřcżó;żó˝+űa­ÜCřřÇ?ţµÎąß źSĽ›żĘ˘~‚łĘÜ{ŽzÎťŽm•ŢÜß´ę÷¸ŞďíZCmm´Žm¬vçŚÖ[} 7]ŽŁsŔ¸b” ałÇčç†@D`<™ŔŤÇ ŃHţYE‘żýíooޏĺD°vŢChŰöďbE†ěÝF~ s'$Ї¶G!ŐQś7íç°öw:¶“ÜwěßĂ UŔÄüäôEŚł}ŠéËĚšA)`«OŘě-Ú&â؆CčÁđá°ß“\#çęşţ1?tŕެ%€{űŘÇwÎ]:®ŃŠYBPó,“ĎKĄ3<˙ ( §Á'`Đ1—üřăr ęYN wn©ŽĺŁ ÷„Y Ď;Ć4,FU–Łu t„€´m»ĎĂ#Í|–}Ç;ŢqŞL{-Ü#`ćď9ÉćŻęđôÓř©÷ü ű˘· ?Â&~ęŘSŘLIˇŚ…ŔXĚé-DÁĹĆÜł0pá^^o}řń·ŕ…g>'D€8ł|ěş«ahÝ‹ăQ*®Ĺ±‡vIď,í÷H1ŘăHç)8g»ţ—ú\X ŘŮt’nYFxm4lccÉxě\Űâ Ź="B=›â]ęOዿčÍ(ň\féhG˙ćoţć·Ľăď8µ0á5¸G@Dâ¸m÷Ćc<ýŮĎăâłĎŕ“źř}`0ÂÖ™ł°Ě"sJ‡‚|KžçŻŕ”h0¶ Ňpě„©:öH¤O¤A8۶Č.<‚«×oBk-:.'č R ÎZpB |cyA@:ůV)‚łNľ÷”mxľ¸â8ŢĎPJĂZ‹čqç0R?XDtc24mťĚA:_Ľ@řFk´m‹ vIJ ÜÍ (F–¨Ë Jv··QΧ2ëe€íë7půĘä™ÁăŹ=†˘X¬ć~€ű—‰č۬ Ŕ+ůŹŁ Ú¶Ĺx2A‘d™,WŻßĂp4BYΡµńśŁ“‰9Aظ™“Wé;|΄ăÚ6n`Fř.ĺŘž°x–eV@‘ôµ´ö˘ąŔpQ•V°‘°ř>Ŕ©˙>üf04i´,”Čó(ÔŃ‚ÁĐZٵmüańwFbŘÍŤsŚ,Ď +J"î ;$S°2LÔĎÓ1„g„‘ËšY´ Ęů ĺxĎŰ8‹^QŔ±Cžĺ0ZÁhŤŞ®eŮ>Ŕ [Ń×µoNŻ9°··÷őűý÷ßË1(Ąđ‘Ź|:±,Ż"BY–PDP¤ ýFȲ™Ńřw˙Â÷‚’ÍGÉćd{ö︜ŕßđ Ŕ¤Č‹ÜŃrĐI rťÂ·Á}&ý÷Î=ňë˙8H+±/@P€J|ëJ §&ĺÇJ˘2 ˇ@ÚV>ă1IÎÉ‹żôî«/^ş]› Ş Üy™hĄż]~w–e`碄$śßK"ě sČ Ćh4NwóH!V"çŔť¤ÁŚĚd(ăÖµHUž ćĆŔcü ŢÖZt„AöÉŁö×Iŕ5E~é—~él۶ďźĎç-Ü8(ůf••Ú9ç  <'1Zˇ×ëáâżů(´Î • ŕqD©N€Hů«B0ÂćSZ  ÁJ…B“@ EPÚxëŕ(ÇôĆ56ţ>ŹĽŞCtmtt…QhŁ„0„6¤äš2ZK)ÔZăŹÇ»đüřŹ,/˘ŠÁůŮ&Ó §; †;i%př`8těi–B0T!Už@ĐJÁyÉ& ąň÷ÉFę¤Fn^¸ü,`Ł‚# `-ŚŃ°ŽeÍüu%„`aOäĺPJőŽąÍŽŻ)đä“OţĘp8dľÇµőĄ?ʕ圓c"ç„–PŃ<ËPM&0™€ř˝xŤĽáŮż84%‰‹ŕ_Č$v"aa€ś—*HB·5)Ě€HAiÇ€RBdL‘ˇmZ ňvňř— [hÇ—°Hçzľř+ľĎáó ŞI p Ý+ÄŠ ëD†#ď÷#ŕâ÷iű Ţ;v(Š.ę)AI꤆(¶ŘľyZ á‹Ŕ 늢€u “gBPý„”ä´ŻUnÍÓvżfŔ?řÁ?űđĂU¨ěr/!Ťd;ŽĎX` ^Ä÷QcÖŠ«”ŕ§Ů ]đ‰ ?ĂńŰëąaóic!X,ↄ#€\Çąť' :ŕ€łk›Ŕˇ•ĂÂYÁf‚ÉsŘş†łâ  €ĄO&Ó %\Ő)†ö9oôńĄ_÷u¸řÉO@›lŃuéëŞňÓÓŮć+!şÖh›&Ţżü}$ţs–e¨Ş:~Žv`ß˝»·oc>źˇ)Ëčţ‹`-śma-‹‘3YŰ€üéţ|9öék†<öŘcď5& ŮşOਠ—wD]Ľ?ڀɌçŞóÝ.µ°o#ż}”ŃqăE.ă˙‚”$׍ç”R0¦鵆sVě 9¬µ€“q)ÝI"QüOžI$…8ź Î?ňŢôĺoĂ3źţT´50 żs…Ĺ<±fě›Űd*WiJ —ú>ä>fFSU¸ńülž?߉6‹źĚăţç˱§Ż đ|ŕGžxâ‰Áݱ= H%Ă›Q ‡1u”`Eš¤łÎű÷±ä—ď †1zÍ€Ő.Ć`+Ş´†cĺ•É`2ń$h­‘ç9]s"śWex/ÄŢN ”)ą RÄâß"aăüy<ńGż Ď~úÓüwâ# öé¤ýČłJ|_ćü]ßéçĹg¦ö†ËĎ\´–ÓVÎ÷qô>¨( Ąĺutćľúß˙6|áKëxŠü :}jěKć9üQÚB@;·˘w­ňâÚ3nÝĽůtzląžŹ ÇÉ—8-xŐ€'žxâo;çî;ÝŘżĐÇUQŘű–ű#m`ډČÂĚ8á<ëŁőz˝ĘŮ ěIDŃ—ĎŁÍ €×^ĽgmS0$† K‘s)Ą˘ =đpŕ‹g´ŃȲ< •¸ýÇÔÚ@ű´ç'ŻűĂfD—ˇŃŢ ˘<úľöťďÂŻ˙“˙UĽ#qîdfösńĹŔř —żÇ2ňűţüڧ*’¶Ő|Ž[×®u™q¦Voąh8ćv\&VGĹŽś^ŐŕąçžűÓ[[[7w÷R8(Ř/ţíżąčŤ6`Ś”ŽRJ#(÷óŞ…RkĹÚ?++8PÜÜn^‰0žĚŔĚčŹFpTy%úF'ţĂë÷*ö•ő Đh!f@iÝŮ$<„0aĎ@( ÄÎ#ľJl JGu‡Ľ‘RnBňŐßömřŘŻ˙ ¶Ż_÷jVÚr ÷î6¸óľ_B~cĺÎ⿯oçđÜł—ż›°;Ű_©„éëi«š<üđĂ˙Ťµv_yíéµÝo‡LúQ r”(·ĘČsä"űŻ;lś9#"s–E#ZńăfĽ†‰8źTŞ#R`ź ěĹţ…ĆáÄýç#¨Ś(@S/@ĽDě#tC@Ei9q` ö†!ó*Śí;ţłÄ?úŃ˙ÚäGÎë˛îľđݢ’żůÓ~ÓFšĎôĆÇÁď€2Â3ęŞFßä‘§suz,˙«ü÷©Ę°ů9Ú :‚$¨{íĹP­ňő/ýĘýËF âc éŢLÇqZđŞ&ÇŤśząŐĂt˙cą~XöťÖý~UÝ i-!vUUa6źťĂt:e r 4m-úub, FŔ´NŢHđNÇ•jáśÔ,ÔÖbVV *kL†ĽP°6ÔĘ,d4šŞAÓHîwNŚmĚ m lŰF$) Â!í !ămaOtű}î<Ć>Ă]@ôĺů_¤‚üiź~¤ fL'ěÜĽą_ôŹpÔ_ŹFäă«…wŻjđJ€y•0ą Atg”6QŘgvŹ' ‡čŤF€łŘŢŮAU×@˘+;Ź$ €Čuş®g\‹ŹŮ}YHŚŃőó€¦ CÜt>ŃGt‚D-:[FV¤ŐĹKâ¸H"ĺ­ź»ý3z{’ßłŕ¶‹×Ů»2SîĎ ÷®ň$´ÖâęłĎ`".NČą¨Š-€K?ď'‹.͵đU Á xĐ"ď×c‘ Žě=k ' wĚ b ś—ĎćŃĎžg)Ěçs ş‚8tőIŐMA´+ ]8«Ŕ%Ó© ěudÇí¬AŃď`2 “™L ěUY&HJn‘߉ÍĘKű2ÚDÚA} Q* C^@_nrÔľ˛ňwç'Ü_ä9%›ńŇ>ŹţhĂŻYşbĘÓ‡áć&ęşöŢŹî÷8gŃ %· ×?PX»_#pe?Ě6Až‹±c°’×ŕB€É úý>L¦1›Î¤?0fłiÇť8hąŇpř/ç"S ň çgÇétLáŕ¬EŃď çôă ?Gźo€ÔZ!/rR:ܲäPR,÷8°’°çÖJůteXŰ&D3MŢĎĹ›ĽJrşąŽRCŇ>XűëŞÂ W®`˛·{ř˘˛¸Fgă˝ýö¶Ĺ|>EŰ2Şj~¨ ¬ý˛W@¨vܬ Ŕ}«Ü?+Á#¦ăĹMJv`¤Ş› PĘŞBŻČ»,Dt›ťŔ*pôÔ6[†A%ăK˛Öb@ěÔć@% Đ6 š¦ő6†ÎôOţ5í7H!ÚŽ‹'Ű5 ®żUó·zî›ÓAç€{;;ěî˘÷ÇĹE÷"(Ä= pZ¸Î|C ęGü–ż_DŚĽČE<ő!łZ‹ń­µV hŤş¬`|.żk-†Ăˇâ‘(Ęůăé…Ă–îH°J%\«Ż X…üµ[ľ8Ě (‘´Mş¬|ä)­ç¤´R¨«jAŽşĐď+‹¦n@JÔ?ŠDJY© ‡ÖpY8§ZŁŕ +ýĄŠ$㏔$YŰŠ›ŇąşöDÇ˙*ŹDś s©ĎÇ×0Z@wňׂë°k–˘Dä°b "ŕöÍO&(Fä1‰Á3śÉ°L Ĺě`űPIXô"¬Ý€ŻpX%îÔîŽÓ>©s‘e™u ixľ|‹ÎWżłţË{ťçČsq‡ŐU%yţÖÁZë­ęA a0 -”?$“0­ů’Ů‚[Śşś(ôXh#5Ňůa  Rp¶•Ú„Ěą[âźč:čîOý~A÷_0éuĘ~Ôó)ýĆ÷Ľ„‘UUâćµk€ÖÇŕ —˙C×üHqĚŚL›tťű* ' 1_ĺ8 X€S‚UŇ\TX6%7!TÇ%"ŘÖz_?D<'Ât:Ť˘w°ľËˇ“ÖďWAfc¤€üĆ2Yg-ęşöÄ)9 ”˝«ŃŰ `-0™ ßz”µ€2]PĆ *+IźÖFŠG˘®ć á řę­ăÚdđ´$ş‰Žz®OI?Qnč‚k˘—ŔwG žÉ„vt1H? \yöYtETĄť y á9C×.ľeňÂÉÁI›ĂPyy/±(č!wťÖŕ%B*ęź”“´ČÇę%ęŽŘÉÁ•AoĄlCś={mScĽ7ÁĆ–§#őóúývwv±·»‹ţ@D\Űú˘ťDčůŕą&ÜÚú±)vh™a3ŤÜhŚ66AŠĐ¶­śS%Ů9hc0źĎPUuDT +b‹cZÁ—Ĺ„WĎő(±_tSŕç.Ěa7ŻQą'‘^„ Ĺ›;{ÜŻ”ÂĺK—¤ŹP`!DQŠđédśS(‰OPü%-ş3Ž®\ÚöÂÚpźÁqőüĂŕ¤j@÷-ŁmŹ`±p3”"ěÝŢÁtwě+Óvoߎ\Qé`p“|}9ßĎWí±!-'¸qPA¤ Ő´0,:Dżgv€Ęň^¶iˇ´ ŃUĄ‰FúwAg‡gÔÁuň„[;«q™wŇ´?ďŔSÂH0D§OQ‰qŃßçÇtóúu”ĺAV‘ď´—’–Ö %qI” ÔWB­Ô4Şݸ óÝ X€;€ăęůGőÜŮ"GéÖ —’ľŇč7ĹĹ,ËĐ„ŠĽ^—–StDÖĆČą:śŻ'úz,Ö €ˇ˘čŮ4 LžÁ@AQÇŔxwĎëř„ůl†,Ďa˛,–,Ëam‹"Ďať“˘DúpäŘv #ť‹G¬íî‰â=RS‡‹´"~Ď yU{Â|6ĹíץĐix>'xľĽT ńÄ!%{aA; NÍń’Â!4`őšŻpź¬ Ŕ ŕNôü;yĆa µ’´XŇ36)î3˘’O‘Ě•ňÉ4‰1Š$fżmZM|řN^%Ť×˙NCń4)GîŔNşĐ™‰›ś9-™nÜ4M§bD“ŽaŰf!  î¦hçĎń’€r>i 0Y†Ö¶p­îTZ#7bükŰ$ťTt†ň^ĺ|ŢN’©ěÝsÔýnĄš¶•ŁÄ ĄÍ¤¸…UĘ /Ë9H+ä˝ĘŮĽC~$‘|RQw˝,çĎçÉHDŔł_ř<ęşŢgťgËŽFN'~|h/!°s(çĘů3ü8Z‹¦®Đ:ö‡Ťîß k7ŕ}§ˇçÔďťąE¶d "˛¸Éb}|çŔŠP9¶Îź‹Üs6ťa8âŮ‹ŢŔ8˘ł°M +Ěž»űG¤Fź%9ŢÚ9ë k”u‰˘¬Đ”•xâđe,ÎZÚ¶– ÄÔJR"Gťa.JŇŚ3ŔÎ%a¸A¨÷㍖˙Ô'Đ ĄxŘ{dţ(Ľáú‹W%‚t‚ŢľWíűSÉŤ’Ď^Ťa_¶ DQ1LŢ–â“¨î¤ ŐZx™ŕ4ôüú ţÜăŮÔ˝HNâQ m,ě]öÚdwE݇Ş,ŃÔ5Ş˛”łëKÔ53ŕĎt¶ ÚafXď2ÔFĂY m%. pÓ¶´śyJ IDAT•g°“SnTâG˘·Ň MÓDűCĐń‰<c9Z“<3ĹĂż=1븢BwăS’ůôuNÖŽú7c2cw{[J‘#†÷ „2űĘĆŮUŇ“ď8{@€cň†$D+!~qő•=–%ÄuQĐŔć cÚ†ý ÄĺčóţێŸ«í_ÄU!Ŕ+9!FõmŞRľÜ¶Xé­µ±äX–癬kˇXJn[*ę0šşÂŢn˝űN˝˙ľËĆËňuScáĽ{+DţYضEŰÚčI9ĄÎGď% föÜrŃr¦Mˇ9I': Âĺ Ý üq4ü ˇ‘÷ÖZĽřüď­čl‘ݢRb nËHf|’§9Dţ8t±Ô/©P1}Öâ>HßßMUŕUM^÷­?"Á/>r [şL/öfaůěşëž“.´qa;ąäH*·xoÚwh·ôl;™â÷ţůOco:°¸ĐGIA_KŠĽ( '‡;Ń÷•1ŘŘÚ„" ôPÍklť=+—/Ł© iĂgśčůa3;˙JşyQŰĚś“°c'HÍěłű"Ő8J⦔bÎëďä1ClRŹ€Óë”ÔX {@¬= ´ŔĎ[(´(  Âł Wž˝ňĆÔd‚“öÉm ČšVöďľ”0=(˙"‚/݇Řpwu˙ŻjpfÔR@B¸‰˛ú ăäÓĎ)ň¦źý5ç-ä|řĄĎŽáŕ@ĽôŚ=o pŇl@Ź˙°mÚ¦ ©¶ęj†ke%ČçuűŞ*ˇ”Ć`8Ś6Ľ(„S#šŚŔ˙ωíşo"zAŃwž ;k–$#m4´1BtśMě "âwÎÄ農Kˇ°‡/Â,É@z•K,‚Žű§“śŞJ)Ľxĺ ÚÖCz‹QÉě§zX:,ő—śÁH 8Š‚ ¨AáËáXѡ/^Őŕ•' ű űĚ9F¨Â™ąEȲ ç.ś@hšFN¸-+ôaĽ7—ž„ކȋÜçÎ8éź>[ëbd słäÄöČQ¤oęÚÇÚëĚ­má¬ő®E 8‚SĽđśHÁCÁ]ŐŁ Á¶)ĸ׫ „Ď0ŢŮĹtĽóöC'»3#pꄱ»ćĺ€xŔ ťľOÍ–ńžhŔ‰ŁCďÖŕŔ dF!řšŰơn[䚎¤â‡÷{‡‹L ,î@]NĚ Ł5j­‘ďPZăú /âÁ‡ÂdwŐ§±±µ…¦iň ´60Ć- ĹqeY†ş®1źÍş‚ IKěĎ˙Ł`óňqV*1¦TeéĄ"xo†?Ů}˛Ż?śú©ĎăĎűף—üąoűzĽţÁsOKüÝ÷ţ_xןřĽóßűŔG~˙ńS?ű $”÷'~ô/a6Żú>nD`dD‚ ™1¨K‰˛C#áľ5wîŔë/ĽčŤm@Ţ/™ Ů0G9›Ă9FF€Ę2ôzE'şúÝMÝ 7ěÇý~Y–!Ë3 Ú!šşBQdŘ:{Ú—ŮąţD’ 8Ţ•*şVQDĘř;ŃÉ4"ý{K '¦đÉ?Žť$%qÁ+Ä@Ćtö@(Rd˝}ó&ćłYtÓ´Ź J#Ý—mŔ2§:s€#yĄ`­]¸/uc®†u6ŕ} Î1š¶#7ßýÎoÂoěiEŽżţ}ßű_ý$~÷÷>oúcßüÇ˙(ľçżü;hŰů»Ţ‰üî?Ť˙á=˙ďţ[?„ú‹żŽw|Ů›0™'G\cqˇWŠz‰śÉ`8Äp ÄÇCU0Dť{đAÔĺÎ9E!uő°­Ĺ?„¶nŔ̰­Ĺl:•B˘u%ÄnP€”e “eţŔQOúµÎ‚A(Ë™“,DĄ z>śu0ýyžŁiZĚ iŚ÷Ćpľ†APc(á°@‘„KZ>“K.Ţ‘«űý>úýľŻ±ż==¨+ ‚ÚÜ<†ĂĆÖ–„űxŚEś˘D•‘ĎáEŻ·Ďő· ™gĎ?€şŞý©ÇݲŮÖbcë ¬sŘÝŢY©¤ëľĘ;tÚ°&Çľü­oÄ/ü&…Ö¶řĐG>‰÷üźżŚŃ°Ź§/^Ćo~ä@Šđç˙ä7âoţýÔéűźö˙Ćßóßá'ßűsxÓŁŻĂ˙óŻţ5ţć_|Wěú 7ŕJw`´D´/ýNůQ†$U)Ŕ5ż.gŃČGIŃáh„éŢD r@ŠcĽźĐ™F–h› "Ą YCiďSއom ­ °shëyžĂ¶ ĽJ4QW5¬‘ŕ Ůt*¶JĹc µVr”‚nĺ=PÚBµ-¬1`vÍç)8†?đŃu)¦‘žůüç:[ôŚÇăcqSfF]×M§IűE#aü@â))ú=ÜşyCšB3–´éńŢZëüY ˇĐŔѰ*Pě4`MŽ üÁ>wţ•G‘i0;ĎŤ€ÝÉĚsF‡­á·wĆŃŢú‚š[#ěW@ę[Ü KDĐÔ˘{;"P+m´1ţŕ Ńťłz˝B x%ČgöiŚaL^őöăĺřŇôs ńĄ§ł‚—¤4×ŐgžC0ĘIoš:‚łoRW¬;”d"v•ŚV5’ű•ň už™Î›!űE1%6ČŐ\ý •p­ÜCHm] Ű×ćÖÎ>p—_¸0gJ)ÜŢăüŮ-߲CôGĄ@‹>#ą÷y‘Ă9öޢ®+lžŮőm4"YŰb>›ŁďSh•Ň0ąÁp8‚É2ěíîáÚóĎ{SśxB9.fÄ‚!EW6ľpy×J鱦iśÜ&3Đ™Ň:J,ÁR•e˘w‹Ől!˘“ł7¸/ęöbŰď b;”yĽyýęşZ°é‘/…ß8ůXh×]Oüú„d˘ĹµHÜčÚĆR`ˇ=ycLřS‹ÔkíĽŹA­ ţĘëŕF+üăź˙üíżúÝřżń?ˇ®üČü9üÜ/˙¬łřýĎ|ßógżMjďßI6`‹`”ăĺĽĂ^žÁ9‹˘(pëú 1ČyîîśEŰZhc0OPŐ% ˝áy–ű4_mäŻmZäy.ÄÉK<˝áŐĽDŰÔ rý>¨ëÓńž„^űáZ+°Źpţ°D÷%ÁdrbQY&éĽŃýč=ÎA‡kě{h0B¬^D~&Ěf3ěÜşăüâ ö†”24áL†B Vply%|ę€7¦z‚¶`;fš0ŕ•KĽ0«Ľ§kpL¨ężř^á?®ęü|§đŃO~?ýł˙?ö׾J)üËßý8>đËB/ËńŁ?ńüŔwľUÓî[čUťčÍ {”8·úIđ.˝LÂom«1ܡŞ+dY÷šµ-ÚVDií+Ţ:v¨ËJÄtß—m[ďţc©ňSäpm¸©É@´˘Ă7u]„yQ@Ş’ĽřáhŁuŔm1ů+‚s’m¨µ?=ŘĄżť%ßG˛Wi‚Ež˝üż`·gŔ9‹Ż<eTçjŕ<ňÁÄ|ĽşwŮíÝ|!ĺ7 y‘ł |{”?qIwY‚“F‡Ţ)¬ Ŕ1€TU÷đ·`tW.*|[Ö ~îW~ËGŃ1´VřÝO<ŤßüŘ,‡^hĄĺ`K?öî÷áť_÷cOç+XĹ7 ‘Â|6Eă-öÁ8ČěłőĘăÝm03晜gźŻfÓ Ŕ>ž (=ŢëĽEŃm[LĆ{ĐJ,’1ą˙Ą¦`0ŕ>í7ď0Y޶ëżÖ♊ľŞű°ĺş®‘ĺꪎ.7ĎÎČ)Ă:¸Ăěő ĚMDt•瞓H? ±úé4Fýpé Vę ÝT§Čăý)Iä<-I$ľ4`íĽä°‹U!(<Ó•ĎÄe•ł ö¨VaĺďřlÁ@K}ů;vR“ꍫ±ď¬ű„Č«`ŔÁB!C[×PZ…­ (Ý߀Q fă¬Xçëóń.LŰB7-”—.j_ń7ďő‘·Pôű bŕ-ř„rç¦ňZ–Ń4ŞşöţűNĎqť Ŕ‹ˇÇÜ!'˙„C®˝řšPj@šżďüťűľ[ ˇ EE ŰR=˘dŕ€PD4Mm|.€JĽ9 +zđnŔšÜ#8,Řç0,Ś#/ÖqZĐŤ767đŕĂŁ©kěíěbăĚ&ćłĂ!Ú¶E[7Čňăֵ먚 y–űóú[çđř×~Kb“q~ćW?vâ–ÓY†Oţú/@ë Ľ©,Ç›ßń­BŹŕ5ř˙ţ3T“=ÄÜ‚*i˘m“E‚Čň’÷CF<úڞD>ńxŚńŢžpĘ0a*áĚ'‘xÇ‘ ŹĎ KĹ /ĆľŽĂ«¤!NHhzŚG/ #1ž&ĽŞ ŔΤô©©ŐXĚ˙‡?óľK"sZ I f˙™Wőťę«.nb€a'3´]ŕ%ZA±č$!¤Ľ8–Xý[7n`w{ýÁ¶µŚÇPZaűć-̦3‰",r4µd öú=čĚ€ëF ýŕÚg>ŠrwÖ¶°m‹¦śˇWä %śŚt†ů|†˛¬`ŰĘdřŘ?{Hi0ýÍ3xň߂٬Âtw/ÚČ‹ÉUU!Fç© ?‚J†{ýźąËő÷Ą A¬Ö¶¸ţâ ˘ĄVúÔ8ŻŹßýŽEťXö;Ćwˇô·8@Ô+ď§~|Ľ‡/#ý:đ„đâżřńČ1O‰»;y‡«ď ¤’Ĺ›–@áWí×s ż÷ŕŢ:——1rF{—‘0…łúLžĽoż*Klť?‡éd f‡j&Á3ŔĚsţ,ĎćłŔŚńÍë^Ö¶ńçäFŁ©+b•vVžo˛F)ÔţË’@˝Ą"Xëër;‡™Ă»>:˘L‚đ]‡dNٲA„ç/?çŠ,»řŇu°A4—ç‡ç<áś°J$Š%—)qÁ ˘C•޸vž6ŚgĄ”ˇşĺ üě‡AčçNű2ĆQîÄú `3X˝~D k-zL&')R LŤÖ×®Ľ€áĆA¤ä4aŕX< ‘´ęěQ‡Ů|×nŔ{§)î/÷ąŇyX6ŕD“p˛¶µ × VnfFU×(§3dEÍł[č=´M “IŔŹsmŰ mZ FCś9{;»Čň &33,Ť~–ĺ#Ź@—Ôë^ýÄ RĐ_ň$Pô żäI¦»zó‡_‡ŢőRTkŘÖ˘*«xö Xř•¸őA¬"2F‹ż8üĂ„Č@¸‹Âhš¦KşżLEşIë®%%»O*: )>#Tű ľbýÚ„ĎűĎ»(ą;Ţü_V ×6€» «˙nŰV…}®^ěe#—sWs?ČBőâĽ($,Wôú}TóŠ^·oŢDŻ?@^HčpQxřŃGpîóh[‹,3Řą˝Ť­łgpí…Áޱ7ť OŕŢňEP?,#QŹ' ~p€~äőhvwŃ»|Ůź%@p­ © śéŻÄ^atwĐE°Ó€P…Ż3hyŚ'`?/M]a!-–(!~ś»)űŢSu‰žľJz@tG&ą€ÝôcĹ"„ăÁY©îžHQá=žú¬‹‚ľ,rçÓ6f;8é"‡wŔĆŁ·$»- q™Ů¦ÁlĽ‡¦šŁiZ˝ĺl­ĺŻ[×o ×ďŮaçÖ6EŻ"@{ßţl2‘ ?ë0ěőáf3ŕů«Đ˙ÎWĂů ?ĘčcŠĚ.Â4 Č PR’«s¨šZPÉ9(k`ýďŐYvâ2¬« Jµ(}ÔU “ç`›ˇmü1c쀦FS×r­Ş:ά€•<šgYڎu čADH†łmçŤÖűÎîź^qlí‚Ä‚$®„lhöŻíÚ xŕnčůGő}ő'XdvŹ>ů{ę+°yć,†>mrá¤JKđ ň˘@۶č mťů¬»¶iˇó JiĚgsdyÇŚ˘×1”Î á·ťç¸ńń ë€ÉxŚ^Żş˝ ú5-(Ëg^dĄ2W%PU¨Ëş×“<~ĄŕlŻřöďBS—‰Oč\{AzfŔ1ŚŃRĐ€19ZŰMA‰ˇS;ÜÄ÷ýťwC™LŞ ×•¸Vą;´Ä}h´<“ť¤*Ź66°·ł –|Ž“ÓŽE±±˝uŚ"7ĎKŔ÷íŔ€/ÁÎŽáŘú„%ń¤\xđAśü żf ćVčUŰŕü[ž„m{µő’Űţu^»_&¸›zţqú<)ÁQJáĘg>…×_8‹łgÎbc÷1|6˘ĐŘYôCL'c“áĚ™-X9G (ŁŔŽQ–R0$óÉ:YQ`csE€˝˝ôŠuÓÂ9É:¬Ş#¸ÁٵkŘ}ěQń˙ŹFĐóRôéKĎŔ* ®¸<‡É˛H|>üź‘g’ět—ó‡iŠO8ňhsÓ‰09{á<¦“)†Ł!Ëčč G8ó–·ŕgţÚ÷Cml`´±)Vú”•čÖKSĚ–ńčŢ€+—/ŇčË÷…ö`lŽ6°7™t¦…$iy ťsxă›ßŚg/]ڧ‡Ö¶uřň gѸ{/\}Ů %Ξ»ÂtkřĄŔk’Ü ·ŢKµ«0¤ÄNŢ,ž$XÎśc’sIihmP ĺ|c2ÔM…¬(°5 .+) ’ŤÝ¦Bîký7>ŃÇ: ×:4ÖAe™OúńĆ0źĹH^oĄÁ”1ň§HÉ CeŮ@ç™Ô$Đ€Cä!ň~y¬5,„ű‹QćpYżŹ¬ß÷U~ŽZ@çąĎY8¤ť˛’mL.µ »/ĄDşQPÖÇAě3Xî÷űËwRâ:đŕ4'ňĄŘŠő>4ŕ3ÎY‘#Ë3ŔNĘz9'94,ľó>fĆóĎ>‹7|Ń›pëú ,….˘µÁ`´ţ@*mlmaĽłŰ7o¶-¶oŢĆl>“Ű~ćÂ?˙ň×?•g°uŤćąËhCpUb0ĺă˛ĚD7]“* k¸÷ű:ŐŘż©«ŽĂ<Ă‚ć˝ĎĘî]É—Ý,zCCJ§ůăÁ«c”HŤ€¨sń‘ěË $u˙‰»¸`›X-ž,KŚŮ‹N^3ŕ^čůGÝŕŘnŔxĽ("äąś¶SWĄ×eYtUg1™LńÉŹ}ŁÍ Ŕ9|ú÷>k-ÚĆÂŮVj6-F[›L&ČMe´ţhŤ˘?Ä|˝Ű×aňmkQÎç°WŻŕĚ…pó7>„ĆZ4;;@ë@Î"¤é¤4ňţ_ó®ď‡ńýííHUR>@N"VždD"຀ńxˇ!Ç9HâŘK18ŹpkAR`ĆśKü˙G,!Çż&—ĺä$ʍj±xL(grŇź˛ŻË"×*Ŕ ánčů§Ýçr˙‡AŁC}?0|ÚŔŤ1(Š×®<Ź®\‰„áÚóW#’°ed˝Š"Ç`4ňĎPČG›Ď={;×®`„*·››¸ôâ§AĆ×A śVÚsX91¨7Â1`ňY–٬JŚ66Pו/QN^×÷"6ú˝>ŔŔt:Á _ ß çcň<ó ŤÍ¸ţŃY‘A }$üÂxŤX¶8{ţ<ćóą/‰`‰#§:ěFŁ ‡ÓÄČ®ĹÂ8gqááQ5rsÚ˝m[ś=˙ÚÖb÷ćöJä_»ON›bľôţ’`ľ“lŔĐŤpN0Q ú`+®«˝Ý]XkáÚp€ĆĘápsQ”f‰ł÷Ňٵ-T!HŘ4 ę¦rŁ®+”U j‚x+‘ŕ {!¦×küů@]Uϧ$1IŚyr†ˇ6NjJ™uÔu)ůJŁśĎˇ‹:ËPgtžĂY‹˝[·P7 š¶íbőc^çî=AÎ8 F¸yăŚ^¶¨Ó śdĚçsL&c¤DbŢȼZ‹~ŻŹ«Ď?ß9ů©n­ĹÎíۨ[‹ńxw‰P%ŁX±ŽT ď^Őŕ4ŕtlľŢ= Gia¬ű‡÷‡/6õŇŰěÖ][*ĂZëĎó“ë‚ďጽndÁO^Ngpě0ŢŁU™3gĺY pScş·hŔóa´ ń-”1޶ óýá­łŢßÎM…(ĄŔľ€*)…şnäO8iĽxő(“a6›Gu+5:q!.çŕ{BĐUŢäÖ¤ä@­ŁD“‚L*•y…¶:b¨´6Ţ Čń+f·ř[|ű•«»":t]ôe„ÓĐóżgF,µe­Z©ůŞEŽ–RQ7%olT ¶®+˛™śäŰ…×űX{çëůqčÜ­EŃ+PdBľî?üOşgjŕ?őPěsśŘ$´UÄď˘ŕ›żď/mGřŇ8ŁÍM”eéĂ“Ą(¨Î2źĆlbB€Ť1e IDATŹăy_Š”4# ©Z¤ŚŃ: ť„ř!)÷űůďDüj{RjőëTŞ%€”h¤FĂĹz2Î í"M´Ö6€—NKĎŹ‹Č€uNĘiµ¶uHwŢIŐ ®.&Ě&Te Ą¤2Î SÉwQôú(畸‰ĹćK›„áŤnš˙ŃmÓ@)…<ÓřđĎ˙ď0™äĺ%„Öh±aëßüżúŹţGdEĎMđÁźůȲ¤ŁŃ´V¨K9¬( 8vhęyݎ,+0— Ą°·łŤŤÍ-4u¦±ĚfěŤc”#)#)ÂÎJČoÄMŹuÁ¶TÉQm˝Ž›,\HzŐY˘rShčI>%RĘÂŮ]:ô*O@ |·2P—aM–ŕt&>PpÉŘkšM۶âÓúŤ’ýĘä­Ů쏣ő†JŁČ ŢúĺOˇi[Śooc¸1’Ó€†}0ĺ|îĹwÂxo;7oŁ,çč÷¨«J˘ÎĚÄ ‡¦®1›ÍaťĹćĆFt7¶µ´˘ÄhëÓť[bS@;›çźÍa´ö§@ ˛´m+ĆĘAuY#ďőP 8‹Ş’:”"%†RN°H‹đ FU‡ń=t—žÜşXŕŘ^š ‘n–+ŚďGI¶!©EéŔyäw‡‹ńŮŇ×Ó‚5ŔiéůiÂőŰƢŞ4>¤6ËÔ!ĎYĺţX˝)BYm&AHçcاcA޶mĐZ‹Ş,QU&{M#A@[[(gR ´±-TÓ€űľÂŹW)ş®ăůěőÜƆ1z»A*;©F¤Ha^–hšµ—,ş ))ôţŮtŠť˝](RČňăÉFkĎáIЇx¬Ť†˝ŕĎ—pt÷ź9ůNż C7«éÔ.ŕ&u*A5]y öˇĹpź®7ęI0XŇĺAb§ Żipúţ|ŽČ_×-ĘR?Č´˘}„ć ďj ¸'C;“eŃđg­ßř ! ĽţńÇ`ëĆëŘŔóĎ>‡ťí]3önm#¤ ł•łłĽ+ŐÍÖ˘urć đŔCBiŤŤŤ”&Üş~ÝŰÄ– @Ţ)ȦµmjÝ_Řç±J>¦ČŘŮÝń†6o`řAÇŹH“ę ÇČ;d‡‹r‚»á`ŇN˛Júě¦űř°č}X$^ .(źĺ]·vľ p7RĄ_‚ueŐ˘ś{ä‡Dě W OpčŽÝ€i‹ţpÍ3›ěMĐT5Z4± 1źOńâsWPWň˘đĺ¨,FŁ!Š^ŞŞ‘ís ÚÖbsë jÚ6ĆŰ666ä1E0yŽ˘×Ç™óçŃËŚŮ"@Dč=čŤ!ň,GUUPZ 0ĘČé@¤Đ4 vvv°ąą“iXÇ8sö,Ú¶ŤřM:ůáÁ›%µgd÷ş¸şĘĽHĆŠyVńżĺUŤCŚť /%Š*±¦ô!1(®Zńu6ŕ]„Ó÷SKľCU·ÍTµéčT|Ą4 ô袠+ß 9©g:‡"BŃ/$7ß: 7GĐFˇ®Ś66 ÎśA9ź#/ Ľxĺyś=JĽî‘ (ú=Tó9fł¶ÎŹ00 EÄojlnťA^ärx§Ź˘ŰŘ:ţ`€˝ť ĺ ĆĹđ» n<ăĚą3 H)‚ön,ç”VN'Ř×Ď#4u%FSgŃÔ „§‡2Ţ^HřJ±˘u]|žč¬‚]CJš;Ą´íâ”ce;ŢÝďÁb)­´—ĺcÍ‚e Q'ڧŻp·B‚Ť_íÝ]L¦R|CDqŮh-Ô`ŔŤá`­÷Żü*×ĎBľ@ü/ĐWß6 Š~&BUŐľÔ=ˇm,€bĐCž÷ŕŁijĽůÉ·JI0źĺ0zĂ>®^ą‚«—ŻČá§Úű˝ďc×ŃĐçZ‹sśÇxoŚŞśááëë ÚÁqÓĆ`çöz˝ꦎŐĂ:´M‹ÝÝÉü›Í%Ć»{¨ć•Ďú ©ÂđH*îuĚ<ó ŻK<Öý_ăMčECÝÂj`ˇń*ý˙ úěÇŇ%ěŤ­ŽśZĎBĽ“$±;…W=x©iş«úÓZŁŞ*ÜŢŢEUYXŰbsc›Ł-żWTgźňÇ`+RhŮb6›ˇ¬J´rˇŹ[‡fĺ|ަ©1“ďĎÁą``gç62-.3m24^ oď mZ8¶0ĆŔ1gą°$v(«D:q­ůů U‡ ůţeYJµŢcŔŃÝŚ6h±âfLJ€ŕ¬Ăöö¶GrxĄE!XŢĄů0DŹfĎĺX¤ =@˛ 6“ýsś|OXÝ˙R[éßźu'gúČ pě,˝·ëă¤Eb^*Ľę ŔiéůĚ c nÝŢĆÎÎD [(rŽÔ^DaŔÎ"Vu9%xksyžăÎEqî0U`ń 9ŇŰ\Né- ńÓ"rZkŃëčĺ=lśŮÂ#ox#,[äYޞ,cĄZŰ´hšĂŤ˛Ľ€­k<ýź•ĄWY€Ŕ}ä9—lč˘Č‘ç9X gěőzĐyE …<7ľ¦_!÷łCQä"Uř¸˙ťŰŰčő{rrR14ĐďőPU=h­Ń+rÔý"ž8l˛\Ę™+ŤŤ­M GpÎass)"äi±Îa4acssIś^ÍŇ%‹±ąąą:`!9O<(AŁŃfWŔC۶čőz°şEžç+ź÷ҢCOŻjpş~ŕř»{c\»~ĂţŁ‘čp^?‚(ýŕ3\ë ŹĽďËjĺB“ xŰJ]ĽžŃ0&CŃ—”`­5Ęy‰ÁĆćóRDěťm̦S8Ż.(­QÎfQŹÍ˛çÎźCY 1mmÂ9‡ůlö˙ł÷fA–%ç}ß/3Ď~×Zşz›  €I€eÉ&)R´K¶¤µ’řdűĹK„9Ěř$z KáĐÉPv$€ ˘ÄÄ2P`0=Ó=˝UwWwUÝýl™~ČĚsέŞŢ=´ tvÜ®»ś{î9™ůíß÷˙菆ěÝĽ¦Ć Đ¦FkM‘äyN]—ÔuĹrą Ô4™|e©¬ÎÝo’&¬VąŐ„”d:ťQäą7ń„/Ąk#&Č‹%«|E yYP%AhuUQU5µ®™N¦ÔŽ8§÷ě ĐÚěZkf‹ÓéôHZ­8ń©1šápÄtrŘš÷F×,W+ćs›ĽÔUY‘ç9eYQ”ĺ}}›úfĆw4řö‡AxőÂ%Â0a4µţ¤†¨ŹřIďµvˇŐđAąŃŰ(vY„aČb6oŞé´Ń¬KŞ˛$íeQˇ¤rXłĂCŰľ[ŘŠÁŃĆCc(« ­5I–r¸@ś¤*!˘|ąbz8qvłóDřđśť.@f YŻÇjµ"[f\– “Ă)Ëĺ)•ËÓo˘ă?‡t‰ĹÎ_Љ˘řąđBRʦ˛[Ĺ×^“wNx-PşóÉĆKďÍ \wŚPîxő@Ř`˙‹ÖŹâ#Í}tîĄË滾+ŢJSŕŃ·ůłů’W^˝Ě 7"vŔ'Ą ź,ĺý&°{QĘ–  žtŢ“Gk?ÓpD„!RI‚ D`ŃzÓ,#ISú!YżOšő€gž{ޞ,ŮŘÚ˘®­_˘,K’4!r‡Łqł}ć4qsćěYŞ˛"ŚBŇ^Fšöč‡$‘b<ŢpE:öĘV«%«ŐĘš+aHč®m>›łżgŤ)úŰň÷qT, %TďyoG9Vt‚n‚ćd‹ŹŚt'tZ4 ŤŤ2XbµŮ‹t˘óxŃ1ëE÷µt×ŢaT÷:íÝöÂcŕ-Vĺ—ÜÚŰçŕpĹ ?˛n© ˝KđÝEk5Vň çĺ¶Ď¤ö˙čns{7XN›ŁeQş„8ĂôpJ]V,sŇ,ŁČ T˛{ő–‹ÓĂCÂ0d9›“úlíl“¦{7n¤Ćh[ş‹äúŐk$YJŹČ˛>µ±|Q°±µ…Ů?@)ÉbfĂ…BŰnÜ@c( ŰśÄÔ]L˙źŁZ'ńµ°!TďAo˛ať¸…'|Z)ŽlÂlŢń(ťv˘ť_Ă~ŻYt'JÓ­ČŻŤiŻďAA¨)ň×-Ü}»Ľ…{ťđnfáăjŔ·x(%ąr}Ź|Y“& :Égűô©¦Oťm+dŘÜŮa<ŁĹŤk»”EA…ôC–«%[Č@R9I¤P˘×ďłµ˝ÍîŐkL&‹%™°šŞj¦ÓUYÚ^%2Ž˝nŠkťzďťzŢ,8nŹ[ ďka|bô<\Şn;…ŤsDn¸IC§ÖDC9¶–-Ăh٦sžŁ*Âńń¸đŹy´ˇBÁµűěO —ĆÎÖ¤Ýkľ«Ćе÷Z›źFęŻ3ăś˝{ţŁ‹,ŽĽđ‡adf¸Ź¤˛öjšö¨uM’fäË%*PÜş~ťSgϲZ.) ćÓ)uUR8ç_ŇËHłQś†‹.°\,ął·gűůů{pjg‡Ű{·Ńşbçůqá•WIłű·ďPW5B Ű^ Ů|ć}H˛,#Š#¦“Yç†ÖďŐtE8ŐŢt%˝ěÝtz |ž˝čJ÷n}nW[iüÚ6ďY×c[çŘĐ  ËîubĐu«±¬ńáŻáŢ˝"µúßĺ  ©wȵű‡ěO–DqJeRCX)DgQŽ?8&áĄl7L»Ž-yPĐ®¸sČóćŔI~mLíppűR¸2ä’ĺjĹŢî –Ë9IÖC–RPV5[ý!QbCuI’°\.‰“„´×#Í2 ĺ É·¶laQô{ ˝Á€ŃxLžçL'kÉ@eY˛\Ě1Ć°Ę ”’TŽ9xoç ĺ¸ ůwěfŮů¤±Ü{ŤPŕ=“€YÓZ3Ě|5ÍĚóڦJĐŰ®|úŢĂ3´Łë'±…H-đ¤@Ď}l˙Ç  Ź`M¶Í2+ön_gÔSÔ5µTF"´ nLO±¦ĹÝMý÷vÚqg XŰhw»¶îߎŔo.ĺ Ľ‚0D×Ú¶ţ®j‹ĆE¬K.Ľň ďţž÷đÄSO±űAĐëőŃĆ‚qä«›§NSVČú}ŠĽ đ˝?đýL¦3†ĂeY˛Z®ăóĎ<ÉĺK—”č(ËŇEQhŐom8ś Ą˘XÚŞŔşvá>ĺç<Ńtô«ć=Ëd <";Fč]7*!LóÚµĄş.ÓnŢ÷€0kZzó·a.G~ëč¶ń©=‰lż˙PÉ^ÇM‡ůîĂŚďJpt"Ą ¸đúË }0%2”µ Đ‚J d-»iŚËňó^}Ż2®«˙^#¸»żŔʇő’¨}„!JlîĽö@d ŤÇÜŮ»Íí[{H)Y-—\-.Et6ťňĆĹËôz=Ň^FFŚí4ňĆĹ‹LŚFTEŠB666řÖËßtĄĆŮ`@ĆÔu‰A'1R)®Ľńu]7]b~ümYG GMDë´kü ™Żú{ #á˝:.<7~íÜd®©ëtlýްű±Ż8ş\ŐdÍĐHŽu çčx\ řŤ{íŢĽB?K°úˇD‰)K”†˘©Ś@hH”W?=‘{˘^OZwÚíŻçáŞ;:ŁŰ´UUR…Îkw#Ĺ*w]4ŮhÄl:±-ĵŤőůŠU`Ű}…•ösmĐuÍÂĺëçyÁt2!ŠlÖájąDJI˝Ę)‹’ŮlFUäyE±\ÚŚąş&P)%Ëůśĺri}BRë )]7Ł®ĘŢ%Ţće+ŮŹćH!:iąëšÂq˘ďoCĐëÇ7źy¦ęć¶)Ö1G®é(ż0Í€N:ŔZĘŻ ĆW â* ď˛Ň'|öf˘F2ľăŔMo0 í~ĐHQ+PJPT!µ‘5$@» ץűI˙¨©]Ä{ŮţwKűÂj“Č—+Ş˛lö©5ej”Ěg3Śůlfr®™Ąe: ÉjiSÓ¬GŰâ!¤‹˛ĘĽpř}ŇVĘ€<Ď1Â0DhkÓF?@H… CÂ8&/r× 4Jbj]»ű‘./ŢŢń E8(,ęaŚF—¨ăçÄÍ»'pü4M'$7‹Öˇ‡×ş]"Łdíŕ”m_€îgn~›§ö¸¦KׄѣÚu¬ŤýÔ6öGi§¸iűÜŐN4<ě„q/ĽČG9ľă@WęźÄAŻß¸ÄxŮ´^ź …FHdI  Ż 6ŠB « îů×Ď}{7naśäŐşv]q,¸”ŤzŤ°ůIQPŐ¶›’Ş*)ŠÂâ÷×5۶;ŠČóśëWŻŮĽwwnßaąZőű$qJ]WTeIUkµ1čÚ4©Ľ¶á©°ÎAiš2ťMJ±\-É—++ĺ…@(‰Pu]±{ó˝ţśeľbzpŘ«íËÔ5Y/ăÚŐ«¶±!ř“ÉŃĂp8b2™´ =ď&¶şÖ$iĚĹ‹ě?ŞşćÖŢmŠŞćđđŕk:nľ•¶żßŃ ŕ^ĂĂť›7›\CX#Bż1,AKBV(U@^I’ЇŽuí±˙ôZě_JAž[Ź}Ç„aŘ8ęüxŕě®5‰cHŇ”¬×ÇÍrą"_­p—Apćü9ęŞbµ\"¤ Ďó¦»nUXŚľŞŞlk0§ ˛ôą=ęŞáÔć˛@8Lý8Kéé]Ö5­ňŐŠŰ·÷¬Ż@)˘¸¦jj­I{=Gčm8u:™Ň­lŕŔěd»× )lÄ@JŹ!ŘfÚů|{)"čtrŮŤ™ćë- BH%›RäĆŽďJ÷ÜgßÉnĺŕQMăČPA`#4Ş Ůu6¦w#î»™…ŹAAńR˛8’1T©ŤíoŐ5Bąd!ܢU$eČ«B”†ŐbŽt’! C‡[ď7ŚquúšĺŇćȇٻ^×Ý@Ať_¸s`[Oŕk Žćś>w–ĺbÉ|:Ą?±NéŹF«UU1ÚS׆ׯłwë&yY°ąµE…îÚ´]ăQh,EIĄĐ•Ĺh«Z×$©- Ł~żoS j]SäeY˛X®Z˘rÄä‰Úëá^31]?J٦UÁ»ć–ÁHáRţ}6 iľ»ć ôŇÜĂ5ŃsDĐŰk:^blŽ+›|ḏ”AG˛ß…ÜËöě|„ĂCQV$Ij+ř Hmy€¨4"ÔjDP2úëŃw„°NŔŇ9u#ňěź˝Ý]ó9Ű;§Đhňĺ­5‡wîpgď“}„´»I–R—µĹtMK´®©kawC„®+ąu"j­mK/ÇÜ&ł)ýţŔ1Ŕ€8‰1VynAF«Š˛¬@z˝Ś4M¨ęš˛(¨ő:{łSŘýzĄđŽtÖ|,žYéßş2‘Â:;Zľg.-bsKz[[¶8‚Ć/šÝUÇËéŚýM¤Ż6ě.ZűZ47z|Ľé–qob|×2€;·ď0 ěäĘÎ&BX^dÝeşă$‚P ˝DÉ€,Daă@jÎ?ěî‹ă¨A‚7·ĐǬUg7^ĺć@AYL§SÂ0b˙ÎתJPU2Pxô\)dÓ°óÖők–ř¤t±nŐ@uy5ÝĂŢŢmĐš·Ís.|ëUT˛-¬Ý+%㍑EÖv®Ë˛p*ľl:×µŤL(Wrě5ĺK|±Dݤl:É®ô÷âŢ“kŇ^řĄ “¬i ={éîŹő™„Ţ$ťGS^ÜLţúâ÷+˛˝ß:ßëóÇ&Ŕ#ůrE¤Â–š:Ą¤M¨Qk„6N+¨3€˘ČQ6ú}‚ŔNŁ167 (ŠĆă/„aěÔta«÷‚ŕĸ"ÚP §ÁšĂ„ BÎ?ő”uÄUÖąwůő‹ěś=C0¤7F!FŰ#ůrEÚËČ‹˘!†čަŞ-ÔŘhcL’eśÚ»ŤR‚~ŮŠAŁÚVń ş¶Ő‰Ňů¬a«APMš$„aHÇN8ZÁ``ł…¤YF†a€-"t ¶Áún š(K‡…X“ôö0›U¨„»Ë5•ż#<±ŻÍË€Öë‚LëBč>ÚŹíפ„Zw¤˙˝™ÁQ“đq5ŕ#6G˝&Ś#׼ĺx<ż]ŔN:W©‘µ FWA”™;§ő×uEš&ÍBcČóĄ$A!„Ť›æ{X{O@ĹdYŹĺbAU•G}ĘeÉŻ˝Ţ¤÷ćË%q19°\¬xăő‹ěś;G/Ëxĺĺo8O?Ž,¶€6®Ć€V?÷ÄynÝşÉb>ăCŰOcgIvĚ_ěbݍ(l Ń)•M"Ş*능ëm(Txš¦LfČ@±Ď©«Š0މă¤aŇt—Čk]).Ełv cm<ëÂ28ăéąc"t2 ýůşaPk ŘšDź#űD:0ŃŐN2t˘Č'’˙˝ŠÄ‡ÁÂĆkQGűÉ‹váÝËŽ qĂPĺ˘ ‰.ąĂzĘĄ„aÂd2ĄŞjکѵáô™ÓTUÖAЂܿ9PP–0E 4 ÓűPAŔą§ž¤®j¦‡Ćc‚8¦Ě ćłŰ[A@6čóÄ3Osgo©Â…ű„T8´¶ CŔPŐ¶ľµĘąyóeYŻ3LgRI)©ËŠZI’8a6›Ńë÷m¶˘żWWĐ%~o› …Ńpžţ¦iHgŽ:ęż_‹SľNřBĘ@7T/ݱî{ uË&…·mŰáµ ‹ŹŘţdÇéâÍ ŕDŞöCČfĎś¤<ýcB‡ß®¬ÇŘż/C]ÓüâwA]•0FĹuUÂ>fL§Sâ8!Ží9ÂPqíę5ž|ę<‹ĹŇ"öuŐî~ˇźÎ't7Ëjeť€2P(„ €éˇ;‡ĹâËó´aăÔ&łÉŚÚĺdý ]kddŐěçž7/íkÔµ&«Ą ĆaH^Vô=ڶáNHnßşeµOdX˘jfĐü(©lň1äeIĐw×ŇőI ŁĹlŢŞëžĐ64Ř-«vźŻQZG »Ž~Íő56=X†â‘Lű=‹Bl@8,aeąđŮ‚żŽł˝:×ÚY"‰srÜĐ28‚>˘á“mÚ´R0J:sĎo°Ž>˘ářżh$A#háPsĄ¤,sëĐ Bi5íťm§$ÉqŐN¶ýŹwdÓěůĂ~źô]ďÄ”%ĹŤŐŇ’˛(9ĽłOÚď3ży )-ZoUU¶6MÚŔţí=ć󹫎SSÇ1ÓĂ Ć&‡‡ö%Aíý§hôh!¬&ílnŹ d|LŢŘćq’4)şAŮĎ´& "˛žĹ/ě¶ţöçóÉY šO٦Ó0OřJJ‹ÄlLC¸Íw:€±]M¬ZŢUő\é°Ŕ» ĽÍáÎŐčţĆâ#‚ƇLf˝5±»şnÄ˝Çă0ŕ#žđ•RkÄŐJ*Ůٸ˘ă tŇ‘˘°Ł"𡩪Ş-"ď*' -Üsw±Ą(°N07÷ăÍ,˛' l0dxö,Ůö6B)ŞsçX˝ţ:Ł(fľłµ}ŠłOśGJIś¦L'd˝”;ű„ADQćĉő#ś>–@Ůë‹Ó„K^gsk‹Ë—.19ś°tÉDłÉŚÁ`hŻCxłĂÓ†ĎŐ6KßĺxĎ?‚ĐŞůJ…,ćsŞş˛~—°\.ŮŢIZŰž[Ó Tŕˇ}ghÇA¦ý:wç˛q”z`¬Y€8âĚ÷”lßp~G×űĐrÂ5˛Âąf…Ż\čâ.˝Á-aýowţq‚~Ç3€®×ôč„Zn?ó*ż{§q­©˘B‚ š÷-sÁzÂťÄS긽ĘŞ×k„ńPiź^Ę”˛Ş)&TUQ-ÔaD9Âäbµb˛@™ç¶ůG˛/Ł4Ë8¸˝G6Ż ‚(°1ü("NbnÝĽEU”ě^ß%"˘$fűô)vŻ^§,+˛^ʬß]ŁT@Ż×#Śb„jsű…±&Š–¸U ¤MU¶Hľ*ٍÉô’?Nâ4AÉ€0Ś@…ˇHĄŹĆ¤˝ĆĆăq+TŹÍe+qµë 0Ź,ČĘx8v/ORÁ×mř~ŻÇp8ta×¶p¨ŞJ’$AŞŕ®}Ú[8y?<6bÜÍÁÝF IDAT‹°Ö<ţG^[ő˝ű^ÚKÚ´ŢÚWf9-Ŕ”†Á ÇŤÝ›lno5qyĄ$«Ő’~ŔjµDĘpíî5NZl]×¶ ¸,1Q‚ôlČöÉ'‡Č˘¦ČK‚ 'ôP” "Šb*‡$‚ş.ÉzBJÂ0tj¬!C˘8ˇŞlH3Š'‡yN‘ŻX.  EU˛\®¨µ±=iť~eQ!]ă^oŔrą´é±B6©˝R)ëŕóuŇ&M.Y¨Ňţ>>e¸¦*t˘ëšĂCĘşf4qxxČń6_â]×µf±XpxxŘf8‘ďµoh ÍůĹI®˝UךůbÉd:=ÖÇŻŞJVą-§.ËňFµľö'™…ŹĂ€Źh¨@r’FĐőt3ĐZfb±ô-şŤF)I-JIŠ˘äÔÎ)nďY„\ú“ôú=ęşr‹w<üwÔáw×Úďîf ¤¤Ć0yă"r0 >ďÝb°ąiý`±ý€˘(‡hcHÓľU3¬ )˝á€^Ď6<©Š’ÉňJŰöa ¸qý:ýá<_5šŹ>”&Úî>Ây[ÝX5ČÍ\:€/ bÍĂ/;VX§7 Ë®k}4ßß>{OĐ„n|©±0·#@ÝZ⮿ł[đmÍ­ oĎÓř˙}F§8˛G„iü=Ţů0Ú¶äâDkâq5ŕ[<ڱM=Ąw^‰nšiw’[˘ď~E!UUQ…Ťů ›ŕS–eiŘ9˝eĂXÚn¨˘(0ĆÇń‰ąţ "°{¶®+ňů’*_Ár…žL@űnE†˛Ě Ĺ|6c:ť0o0›NŘ«kúýĽMżßg6›Ű”ŕJÇ!ÓéśÁ°O]Ő\xő[î"”°íÇ˝YdŤďÖA‡pZ„q×ŮńŻĐÎu“Çcoş%f:ź š ÷ĂŘßętÜí¬ŕ2ţ¶€°Ż[{_5ďŮEđ^ŇÇ20-0˙í5ŢF ĽŻÁ D¶L®Y Mł“f_yąő˝Ů¬ô[hűűńÝËŐ4łđÔkWŇeĄ‡őňć€" ŞŞ¤®C‡Ígè)úi!Ăl/=éňîŤÁj´ă^'^żűO×5ËĹÂţĚtÚl&ă$VšőHł>˝AźŞ®9÷Ô“LIł”ĺ"'í­(Š‚$‰ŮsłĐí»ŽIh ĘV)šF*‰őÜ'ʢ *rŁ1«ĺŇJq§ ëZ7QíZ[€Ńý}F®At¸~Ëĺ0ÔuĹäŕÓ«śůbŽĄX)—¤`‡+:ĘóyT4Ž?!AX;[ŇD´nÓv­ŠMëcX3!üŚ´Z€Wß[©ďl|÷şKřNś#ÜçÚŔ;ŢţΞ=o‘–Ý˝H©H“ŚűáᓟţuÂ0lľŰŘbŢ@đÜsĎ!…­ˇ®ĐéĹŻ} éÇB‚¨;¦ üŘ )ŔoŐř®e6ôëŤ;X#ř.áw?ó¦mta™Ŕb±DĄmÖ(%¬(KňĽ`6µý÷0ô’ bˇŹ|Üč÷űÎI¦¨Ę’éáĶż}§?˛{}×™`Ś`ďv'I’Ňö]ŻŔŠĹlN^TeĹÁţÚŘę=!%‹Ĺ‚ŞŞyíÂŚŃś{~Ęją˛5Ň‚xeçfąX!•$M3ň<§péĹRŘŽŔÝđźŢÚ˙G|^Cs„ÓÍĎq+t©/ZMO Ďg\˘‘/šSďzç;QAHšĆ¬V9i’˘E‡ś9w–§ž|Šë7v]‚‘;iK ®Jľ÷…lSŁMÍîî ö÷ďX$¤îµŢk™OŘŹAAáđ6Š‚Ć6·sŰzgŰąî¶őZ7 lŢ6dYFžŻX­rŞjiˇ·ĹeÍŽ0颽®®fp2¤°Ž+ŔTqG E]UÔ®jOşk4ćÓ™˝!ĐÝL¸#άĂʢ sZŤŹ×En„tMľ\q89$ŽR«]hç9wN/©‚Žt–N3Á´ět#¸ýkgv5Äßt`čhëŚhÓ÷- sO©o×Ěk>s‘vlln¦óĺ‚ßřřgX®V/<˙ú«żęĚGÇ@ ç|îď°9aHŰ8˙ľôAn\gl÷j2ňô-]hp!gvNqůę.›ăŤ5â^'řîÂ9•ŹŔăޱŔ0(«‚˛´Ą·Ď9®|GŕZwËúµ”ä-Hĺ74R U€M‘J˘ë‡J‚#÷C#ů„Äqlťbl>ź7Ş jŁ-XHYşî@‚@h* Fkmó*ŤĽ—[7uq­ôv°`Ҷ˙¶Rąťß†Ř]ˇŽ}îçľ…ó¤Ë$ě$ú禙%ѱým• Žřď4‚ŃpDšĄüĆg“J×.ŁÓđň7_a0ńCúĎŤßA–eEŃ00ën°%ŕ?řţ÷!Q`Kśżňâ‹”UŐú{DçZ»á<ľŁKüÝ÷”ëlcŚ>¦úŹt¤OcŻéµ×B(ÂĐĄ»:{+Í;Ď˝ $5îgćŻ1šŤń^ĐÝŚ1 }†Ă!ăń†UÍ},|íĽ‚C…U]%a°˝sŠŮtJ’$Aŕ€9 ý>çĎťçÔΧ¶·BrîÜy>ř"ĄBcGý}ÖÚj1A˛Z­ĐŠAö÷©+C­+Ś6HiÓ„%­“ŻąfáĚ5\XÍćíhjkĎi‹ý„˙¬‘ř–đ-żHcµ¸ŐjĹÁá„(  B(Ĺ}ýë|ď ď%ŮJxĎóĎóâK/5ý |•áÎÎO>ń$‹ĺ’0Š¨ęš—ţčŹVDĂp®íäuî¦?>‚á'ón}Îělsăćm676ZI4ĘeG đ„cŚő4Ť`ŚÁh˙׺{_»÷=$©ŤćÜą'X®rT Ž§â8Ó}oĐďłX,ŘŮ9Í©íS|î _°I]nMŚ1üéůëŞKV«ś$MyîąwĐ5ëŞâô©ÓeÉÁŐ+nÍî±Üw1ĺřŽfŞFťŢŮćň•kś=s¦ó=Ö–ř˝sÎ1íÉKG'iq¦nżË0Új5?î†sü†lžüĘ!űTóą˝6e;ú`4BJňĽâÎíkÜĽvť(I¦®¸ÇúS2 ®*’8%M®\ľb›ŚMš¦Q€Ô’bU'±Kv˛ąíI#%óŮŚĄs ad_¤őđ‹4…Ń•%L{©Ĺ_0Â66ČwoMg(W©©\ʱR®:P ˛’ČőPÂF<”6ügăo Â€ŮrÁWŻrsď×nŢŕúÍ[\Ý˝ÁŞČ ”ËÉp-»µ6ôł/]DÉ ŤÇK7Áíć±úŃŚ†#n޺ŵë×8sj­5Ż^¸€÷r~č?Čjµ"/ 0†_űÔ§xýő‹6qŞsʲ,ąůÂ{(ŠśŰ':‡˙?u]łłłÍáá„ńxxĚŘń2­:-A[Ő˛Ł 8ćĐřşć‹Ľ9PPá÷aR–ĺb‰# ® q3=ś’ö2Î>yL'3ză>QRWłů‚lsL1şćpŠ B˘0cÂ8jşńřRç^/#Žň•m-ÖŕŕKeł(ĄBfĹÎ6js (äbŮÚőľG€ťAkJTZ×P â*Ů›N;žĐşĺÎţöů"fMmĽßBßm±} \kC*g'[ŤRIC'„Q@’¦Ě¦s„¤˝”ĺbÁr2P(Ą(Š‚Ĺ|Žžxć).Ľrş®J˘µˇČsdXÔ!)­˝l / –Ëą‹ ,K˘H»ŘľBY•–ŮŐ„@„ˇ•¬Z#ðÉb'ˇ}=Źl<ţö®ťž„6‚Zň"Gi«öוmyf|âOUOź‚gÎźo0!ĘŞ˘2†/=qž+7nđúŐ«ÜĽło×_©&¶°îT´ćĎ+ŻľĘźý‰źŕůwľ‹ßüěçĂ€§źzŠgźyłůŚůbÁ§ó7ůďűľÖăß9‡ďq€9‚ŕ|Źq4Qěq5ŕŚ˙çĂźůáétö•’TU}˙/Á ßg˙ŕ€( Cź¸aWŞ%řVő÷*}7"Đ8ܠ٬ű|ä ;¨°˝¶F~0'‰UAW+” nŚ(Ş‚4MŃZ3Źlľ8qéµöÚWËĂĆö6ű{·éÔUMżß'ÉRtťY‚PŠ$IPR˛ĚW#‰â­8"Ž"W÷Đ^{]×čé uő:ĺÁ!âÔ6f8˘nRĘ‚ňömÔrI ¤S˙U«I PĘâÚ$'Ůd6„)h˛ő” ëŮÔÚ:đ<łŇĆ®żÄbhmŘÜÚŕýď}~ßű•$/J.^»ĆĄ«×¸xĺŻ]˝Š6šĐ«đŽp_yőUúYźľç{(«©$˙áŹ˙5›˛Ś_řĹ_´ŮŤÍľŤăÔľ˛LĘű*ďf˙ßÍ$|ĽËřĺŹ~vGëúŻkmţ˛ÖúG«˛ —%oj˛676¸˝żĎx8rE)Đđ ·ĄjÍrľ@C†ÔUÍjąd1ź!ĄŕĚąs¬V+V‹%Á´×c±\Ř|} 11Á ? ë÷ąđĘ·(ňÜĆç 6’ 5+w]UY1cÚÔ ”uíŕż•+ĎuŮ}ŞP–óů‹9Ož?Oš&¬V?ńc?NY–Ľúúk|éĹm’P'ěč‘|˛µ.LĹĽÇř•Ź~ö{´®˙¦6ć'ËŞxN ČŇÄln é÷–Ë•íi÷ăhÜukcĂÉ”Z×diÚQóŹJrsÄصő[ 7 hĽÀ÷×ěw•” ĸR ]k Â0b4Ţ`Ľ±AQ–ÔUM…ÜĽyłéYpóú.u]°8}ei7lö_ B˘…¨µM.J‹Ś ×ëˇÂ%Y1 Üuh­&aË%bµ˛aŔW'Ą(7Ć$Ó)¦?@Ä1AY#°Ť3k—Y©T@¨l˙>Ü\WZcęšZ F„!?˙áŹpţÜžs†gßö,Łń4IIâö ż@'hăĂzSÂŐ 4«)D·AĐďM˙ü»ÚđáŹ}öyůiŁőZëň´’a/3››#˘P1ťMÄîî5§Lg >řŽađuÇ˝rFĂËŐŠ·nqzű”UŹHň–)pÄÖďŘü^cŔ¬ߥď“Ň>ď˝ŘvyT"—/‡Šb% ăľ2ʍ«šĂbźţpŚ6ěuőĘeĆ[›c¨ŞńĆĆ`ą\’e™e,ÂÚľţľGDYżG^ä¶X2ŤŁ€Ş˛ńü,ËŔ%Ęh­‰ă­+[c qęÚ‹«é*—‹…c<´Z„oŞJÚp§tiÇJIć‹—ŻírçpĘÁdbNlŤÇělnqćÔ§·79˝µMEÔş¦ŞkĐ!!T»‡°^úŞ®mZµ®mŁ­Y[ă1˙Á~€Í^Jü•?÷ç8}öBŔÇýÓÜşu‹(ŃM˘ř„ŁÖnó‹î„Í=ÂÁÝ˝đ]üżúŮłŔaŚůi¨Ď $˝~f¶6F(wîÜßxůeöÝPA„ LŢ5ÄzR¦ŐI“›Ä1IsĺúuF!qµDĚzŘĆ«ű÷Ę č2îµŔÉ‹|÷T`<&&«ĺŠ °ŘR*Ęş"_­ŘŰŰăpźţ O8äŕöîěłĚWya=ÔĆ2%óąĂ0ĐŽ™ůßr>5]×LgÔuM önÝFJ7ĎsçömŰÉŮé‹Őá…Aš¶  ©$ [@äZ« ʰĚÚŹěvrß•J…!"˛„·Čs^żnmyź`4ěgśÝŢáĚ©-Ţ÷ž÷8߲˝ śšaĂD1MYVŽAş5p°„ŕ{ž7çź~†Ş¬Pó ˙ţű€Ż_xŤÝ˝Űŕ}‚Fđ ççÄŢŘń}ůđ١ßŢřw’|řSź–"ţ®â?G÷c Ž#łµ9" ·oľřUöî4M+d˘ÂFEh:őń0i–ŢűöôÓŮŚ[{‡ úCŰ,ăH¶źÍL;â욍Á缙^đ6@eĐşćÉw˝«­•—vS™Ú0ŹIf‹ť„"HBFaDŘë[p_Ś$-Á…aD]YŚ:Ą$YŻGĹ(eŻÉçú+‹ý7Ú ‡H)źÚF”Ď"<ľź#r MŹ/“FH­ú#;Î=ĆĂ>Q/C IâZ‹K´Ú™ˇ<ž ë ˝˙Ţ%-kŚ5îܺɥÝkÜśÎxů›Ż°ł1ć‰3§9z‡'Îśˇ—¦TeIĺÖ% ld Šc¤TTUĹäđŚáôů'©ŞŠo|íŮŹůSß·ÁŹüŕŘŰßgQk.^|ýĂCÂ(l®Űw z•~đěĐooü;Ĺ>öńĎ˝ )ţľ¨ůiBá°Ď ź2™ŠŻ˝ô×voPĄµ3Ă•D(†8!č ™—9/˝ř~ű_ż÷S Ę ¸·şŻá™@/ËúěLΦ¤m.Šw.­ű§Uű=ĂP8Řčűý±ë\Ó& ‹É”8-ŞŽ#$Ł5uQPç95†8 Ńyi%řŢ-,>źń&ĘŘú~!$Ô‚YU‘¤)ăń©ËĹ’( I†C„DQL™&¤i¨—moˇ±~ź!§µF…EOňÝHˇś9ĄQ2 ­ÓN)kj˝4Ą—fÖ†‚4롫’Ú:%€6ćŻl ˛G#ö)Ľk6–OśPqŇËRVUĹ·®\ĺ/QÖ5˝4ĺüÎOž>Í3çĎĹ)EY MíYÔ˛M±Ęątá[îÝ€u>gĽ}g‡ó›c&3ţđ•ońŇ7_aľZ_ó®#𑀓ĚÂďČ0ŕÇ~í·ţš”âż“BĽĎ`Ă;[›c´)ĹëŻ]ä Ż^`2™"dH‡¨$ED1"Íc¦ľúűżĂ×^ü2W޸HŻ?`ľX'ţ›Q©¬cÉ0ôʆ”UĹţí ×ö:Mâ0rU˘˘©·ÇŘgCUŐL¦S˛,Ĺvq»ąŢGß;éZ˝źŁ€†Fhű–6@íŕ·ËŇzô•äđ`ź8NÉú™5µŘa‘Żrň"·@ĆĆé몢(J¤¬¨u…Ňʆ+ŰŰPeQP%«|EXó¨¬*´¶-ĂeeÁAë0t‰l§a§ZhjcaÁŞĘ3IQŐö †Ţţö'‰ă—ţđK÷\č» ĺWaâŮŚXT » %–éˇm˘¤˘.lţľ’ + †08Řß·6·ôŮqV"‡a€ ,ÂOEx)žĆ eRaŚvĐgĘâÜ»„ŞĽ(moD4Ň S Ą¤6`Śl€„m¨ŃÎľ·aA›*m(W+ŇÁ€rµBůůĂŃ8I1Ć0Öü@cR€Sž¤5Íz=†ĂÁ±y8ćόnM¦\űĘ‹čZłłµÉąí-ŢY–…+– ”Ťýkc(Ë’( ‰â:żýôą3<űÄěŢşA$.«ňxôç;> ř±ŹţN(ŁňgB©ţ …4Ć$‰ űâÚŐ+üęo˙»»·AÄ„YŹ ÍCdšńŐ/‘Ż~ů‹\˝|‘Ţ`Dllmá{Řűö_AtĽCĎ›]żÁQ"őę}/ËčeŮ˝Cxte:YŠw žtíĽÔeé°ĺ‘Ôť–gZkʢ¤Č—ˇ¤Ö%uU±\.ŘÜÜD!ůjIÚËBRŐĂရ»7t!mk/ď!×Ć0ťL\\Ĺ”En#uF»ÜI‰ˇŞ,AUďŁ8¦®*kţHI†Ôµv„Ô¶DÖˇćh§0jt JYóĆÍCe4ËĹm ×ď1›Í]ţÍŐż3–HóŐŠĺbŽŞĹ ô¸|Św„ ú˝ŚŮ|Îî­[¬Š’ ÉŢţ>/˝zł[l ‡äUeý<şEFŞëʢ ó‰Xt(éĹÚµÝgŁÍyT㏍|ň3żh­ţQ Ě+e$A›4‰é÷3qéâE>ů/?ÁŤ[·m 8I ł”¨?¤żąÍĄ+ođĄĎŽŻ˙ŰIÓŚ0ŠŘŘÜvV8Đ%ˇ8'”TŹĆVz§!ÜźáÜď|÷ 6^0Ńľ0`Ë„±ŇËIŃůtĆä`źÚ1…ešrxpÝzö•$Ë2ęÚšZk¤iMhhY•¨«şé{č}Ú•âjmĘ&ĽhcĂBÚ„ŻQ)Ńum-w.č@ăş3.y'˝›ą’äÓ)IżO9› °EPŇ™>hM¨vl˙ć©1»0hR¨Ź®DG;ÍÁš u]ńc?ú#, ‚0äĘŢmľôő—IŁgĎźĺŮóç÷űcŁ2´ueURT•[{ŮřdGCąŰ>č>˙˙mđźüW˙Ą”á˙…"4Ć Ů÷ĹĹ‹ŻńáŹü67oîŮvWYFÔë“ ÇÄĂ!_ůňđĹßýyćóYŻĎh´aťVŇKZ€Ű$¸Š/« ¨ű^׽ƛu>Č9» ůćÚů”ťÚŢÔ+€‹ÝŰë.ň%O˝ím€ŕćî.xî]ďdąČ BĹäpÂŤë»$IŇD<Á )Č—+łyŁäy†0Ž™Î,2P?g9ź!ĐyôíšÔ˛¦*mrM—čÚŮ쵡®Ş&ü×B…ąu4–($íűBŞ<'Ř>E1›¶(Č5_i1ýÜtć©ű'śóDşh…tˇP:_łnČöMqu‚Í­Sś;s–ůrAFFGdI ĆđÚő]^ľôYóŁâCÄ"P|:â IDATU*P¤˛ůž±ÝcŹĘĺ+W* îő{˛Í-jđ…ý[ĽôŐ? JR˘0b06ę}[;.[8)Ů„-&ÝŞ3•Óđ~çôYsÝó?Ôďcsç€ŔcaŃx‚(´­µ¤d:ťQ—IšP–·÷nłZĺDQHĐçą÷ŘPâĺK—¦*„í°‹Ŕ¦ů ›ŚÓ6čP® Ďk·^~O´R¨Ô„Sh"´ !š9±LWüCó™ŔKtűz59$ęő¨–K5Ö ˝­Úß5:ó¦µU˛ó{¸ä-—BŚđ*uŠ [őţď˙~V«ßxĺŢ÷Ţďm*ŤĂ1Hâ„R׼văôő—9»˝Í»ž<Ď;;”eĺąu.ě~¶˙ýLË7;Ţđ±O|~;N˘_JâčÇ ĆcűBW9˙řÇxńĄ?BAŇď† ¶wźţĚŻóÍo~ŤŢ`D0r/›Ş‘>ŢŰ4îl Ţ®©hK1rŻÁx @ĂîQ—»hŔB@1›‘ś;OµX °}UU¸Ĺč·óäfő/ŔŁ !×ű†@Ç­ę=>IRÎź9GY•Ľqő*Ďżűy»/•ô|Âi%Yš0].ů˝ŻńőoňÜçy×ÓOරʓö‚Ď=y”ă‘3€_űÔżůŻ’,ú_·é•”b<đĄ/ýźůŤĎ1],IŇ>ŮhČŕÔir­ů—źú_{…ţ`ÄhĽŮl¶a¤ß®Ń˛e~“BNëĄ<śÓäţÄ÷࣫îuŕśtţNűěąal»ĺ*ŹĆ‹Í©7Ú%)ý~F’őEXFA ă › ;›ÎŁ!yžŰąóDçź;ďĽP-ˇŞŔvF˛‰? Ö,“íÜË#ń Ę3ě¦pc(W—ß®łgţĆ«ńN ȧ”‹H!@Ɇá4Yv'M–Ťß3N~ţ;‡{G Xµ] žyú)V«—._&K2ŠĽ°ÎÎ&‹ŃżqiĆ{ţ0´?đÚő]ľň­ üŮĽŹŐ2ż'¸WtČÍG>ńůźý+ńG~ćîgxđńČŔG~íó[˝4ůTšĆ?h´1ĆŃďgäËżđ ˙ßřÖ‚(&oŃß>…L3>űąĎđę·ľÁ`8d8Úh¤ý:á‹F @»i€ŞŞaîs )Qő\ó$i{Rşĺ˝T­7ĂLîöŮQĆđ ZGj aä€D8źG>ť†ÄÉ‚Z¦‡+-Ł€şZşďöńzs0!ŠcKč^â:•şŰ¸Sş÷‚0°@B •hÚ‚5Ť“đŽČ•R#iĄz«%¬1Ń~&ýÚĹlNo{ ęʆ3]n7 ÝaťY:b ·ÇđąřBÂĆşf(űwgűµ®yăĘÎź=KU¶€JĘFňűDé±…hŻB*’8ęÜÓÉëŰÝ—'šµ6ăńčż˙ŐO~á'çóůźů[íĎ_ľç†ąĎx$ ŕăźú×˙Ń —~BĘC捍řâ—řđżř(łeN6ŃßÜfpú,đ˙†żüEúýĂń¸Qă,gnńá %Żšvß[SýE×`-RXW›Ž°'Â!ě%ţeo6Ţkš˙m tX @*i»ýımíť$ Aű{´‘‘Ö_`[_Yő=ŠcşŽE/a…—Ě^U$Ó§¸2@;`‰q.~éł  âµ^ @¬IîÖéç}ăá{ńu"ŐjEÄ–i¸şîľFóÄNŔşDŞ yvçŐóŤîsĄHS1ąłżĎű^x˛®Y®VMYű˘Iü˛÷¨s ĎX» é.VęQ'qWXhcĆeŮ;Ă(|ăW>ú™żý×ţňOüâo #ăŰfźüŤßůźű˝ěżB¸kچ)ýČ/ó…ßţd1Ř>ĹćOsu÷ţůJĹ ‡Ł&3ĚcÉ ·˘­Ý×n’fCvÂváťKÎJv Go~t'őn^ůî8IB?¬Fŕóhßřî8)*pÂŮŔ‚ "ŚlsŇŞöe¸–8ű Zäą›Ňrz®ÝŕvţT P®’®K„ Qy„!A`@d m©­lý˛CÔ–8•Ó<é4Fiß_ʧUŃÔ*ŰCĘĺ‚ţ`Đ 5>€5ˇß•üÓ@”pŐ…˛Ő,śţg‹‘:Ď „"$«ŐŠ?ůˇBJÁţť}€6”(ě7¤ť| á\nî;{{ÝTą÷^蚻꺡 Ěh<ţ?˙ĹÇ?űŁő/ýŘß˝ď Oßřôç~˙·˝ŢźŇ¶îZ" ˙äźţo|ă•WI‡#F§Ď’Ś7ůő_˙87oŢ Ë2‹ââlżĆ ŤłÉoLďĄmĄżh6‡¤«¦v5Đa‰¬ßď;·řÖŤý˘Â~×CÚď9ű»¬J„ěaڦßD1RBQ&îk˘9đ˙;}T©Ŕö´f@NjߩUËÓ~ŻabŞ×Ă(Ó$ń4ŇżŃ Ňź_yć#šßńŇ%ţ0Š`MšÓjΧÁt* ťháÇÇ\çűڶ÷&ţa˛^ź^ŻgÍ/@c˙ŮíMëgCcC­Kˇ#šÁSÁŚćÉł§ůŹęď (ňÓ`˝Ó™TÓ±ŹťóéćxÚ ÷gMŕΛGÇšf*(‹Šżý×˙[˙ÎÉ }×ኌ‚(â#˙ě'JRnďݲ)˛BaĐ<űöwđúĹ×mK*?gF`”t„ŮJ##i’±*Vn^±›×Ýtă{ń¨şĆđ¶gßĆĹ×/"<ůüű¸ňŤ—lP/Ů|])Ćô2VK["lŹqrÖ·“4Rך·=ó —.]BŞN™°qí۵!H’Ä-©kÚX»Ý)í†ůD+¶[ŐßY Ízş÷”’Ľôo˙-Ď<ý Q0™ÎŘ˝yŁ)OnRŽŤ˙Ó02Żkh<ď7Ćłľmîµ’4áďýýżÇĎţŁźe0Úb•­ég˝”P˙ď_ţ—ďý©źü ·ďż‘ěxhđ+űl¶9ż–ĄéŽq¶M¨y>ăç~îŕöá”Ńé3l?ő6~ű_}Ž+o\¤?®5„lbů~Ăx{Ń˙ëz]§Ť {çŠiŐ)×ÚÖŘ„“8ŽyîŮgIĂ€˛*%Q©»˝¶QĽ”bíscZ…T¬}ĺ.„ßü˘Wqíaµk´qŻ…>É7a0 CF››Ś6¶P˝«bEo0DvÎŚŃśyňI´S˝[¦é©ëĺgéÎţŤ“”"/\Eˇ˝Zź`ĺµ±ĆIŞ5gΞk*÷Níl#—O#ćH2Ž[§$IYy±#źµZť}ĎhĂÎé3ÔƸPb«ą´ÓÝ>7@š$¬Vwń¬ Ń.»[ĂŤÍ1‹ŐŽÓ\WłX¦9Ö2č>7Ćpë`ÂĎüĂźáýĚ?¤?>EY` M“3BŠ×é—?ůěßüÉ?żwß“ó ŕ#ű|8Ú|˝—e;Ć!„•Ôeąä˙ăźco2cóě9ú;gřč‡ Ł5˝~ßÚ€ÂĆL}–hl'ٱ÷ ·~ű9ŢŚ—đ´Z€Ź!ăUIçx #úýăáŔ¦¬6ňš˝Ý1'Ľ+şŚ ű¬#:No V « ‡îÜA7Oq°ǶBsç3]F¤É˛i$Bç|Íl{ ú˙¶÷ćŃvĺťčŻŞöt¦;ę^M–äAĆx’ä38@BI !ˇ3öĐ˝^z­×Ż“×/tČJ:^§ű%é~«I:! 0` 86`Ú6Ć$ËšçYşŇťďöPőţ¨úŞjď{î•dl†ä–ÖŐ9gďŞÚ{×®ď÷Ťő Ą0Řjazz‚9%I$ĺˇÔÄťÖjčvş(Ç~Q&ľňű)”Ä`k3SÓÖSO]PĄ •}ÝD'C­ô xaçRbxp3ÓÓĆ3ŁŔ”^ĂĐéö°0;N·‹…ůyôť3Ţ\č§ ()±úšÍ9}˙á˙˙ń·ICg~R`,‰ă&[{˙ęď>{Ý{ŢőC3}/ŕ•+€áÖł­fc“ô&h üţďÓł˝jDŁŽOüí_ Ţh"#=99w:‘/ÚeW a“e‰žÔďNU€9nUęBDq ŤFÓ˝Ô K/MŞŇ‡˙Ł, ŃôëłÜ–ő}˝TGe ¶Ź+ ý$˘j â=?ň#hµZĂĐĆÝC)4šM,Ě·ť•Ů3‚—;cVÝ*TQRší÷De}NˇQo`aˇ …N}µ{¶AU85ńE0čMH<ŔcĚĆÝ[ęÍ&ć·-3edĺB”µňžý˘´uĚ/Üb.K7Óćő\ďŽ\ť ý&ćŰ[Ŕń!A–ĺxfĎ>t»=°%ćÇĄĽCŚ1q„±k®ĂůĂńÁţGüŢďEaĆ\%q2"›ňű\˘T.ľđčÓ68ĐşUJi‘˛Ń¨ă˙đ˙ĆńÓç°jÓ5H9ĂŁźţ8­–Ţí…‘¸ď|ľZBd–€­IŠÖ28yçÇáé÷Ô "ÂhÜľhźă¸ŻŃ•ÜƬ4/í몀c‹jxDTy>’§:CŽ˝¶W–Í`ę_{Őz4 $Qdýđ´Ź^†ČăJJ4+­ř’ sHyy‘“ @ @.ôę>Ő‡čŕ:%¸»‘ŇWUŞŻpŽ@đĘ(ô»€Rzgä‚ňë1ŻzźK*(łxČĚ-¤řWç˝?r°ÜI)¬ÚiéB$â ´Ě‹$‰$ڰnl¦ggÔĄ(¸ŔłŹ~÷|˙[±úşÍ8sp?ţŕ~˙ţ7?€ŮŮp٤Ôëő źüĚ?|îÇ~řű޶\˙—}ńÉźúyeV1†( đĺÇÁó;_ÄđúŤčAáËź˙,ŽřE™ří‚"ţR°Źóźń[®O€@˘,Łńç® cv! I…”:Ű«}=ڤFǡÍËc`–řbŻ›O>»×í&©˛§”b6Ä”Ń9s 9x¨_ŘgŐ`ż)†ZcÝšŐčt»cȋ¬Ë×D D€n· ˙ÎČĺ™­íuJ´˘_—ĽF.`ścˇÓBO…Pݶ1ŔRżĚµ7ŇXNý›zžZîDp­.Cé彌«"­•Šö2č4çđ$‘jqă«Ŕ1?żŕŮŕ]†©(ŔěVô„ÎXL÷ૣ ú4ŻuśD§ŰłîN'î0Ś ˘‘$}µ˙ĄbEŞn@$u<őµÇp÷˝oŔř¦k±kď~|öÁđ–üt:ú˝+¦Đj ĽőăźúŇży現é˙YbP. đŃÖŕŕŔ_™k3ÚV}a~ő±żEcŐ8TăË?Ćŕ€&~îąf¸78>çgÓ|™řőygĐó‹"Ć<¦>=˘Ő)ź KŚděáń•‚µ;+łžtä™°‹Éě\t×´Ć@ĆěÖłB…®[Hfţ˛B€Í8č}ô8®Ý°E!uř.×n)R”RB3ÍłA™4źž®ęO5Áą^›Ď*“ĐZ«éátj?ů…6…‚ĹHÚĺ Mqµ¦µ0Kiőofű(ĐƤTL‚…ůůą2čöşT äE^;ĺń„Ą´ťa~~~ńXŰ9iľ3ýžĂ ÔY‚y™á€ˇF #"tŇ´0v•ÂČ໪|—ŚUеĞ~ň«¸÷őßáµWáďř8îĽón4ZŁîŤ1Ąš­ć‡˙ćýÝOżă­§ú ă%`xhčO“ZÂôžvCŁ‘ŕ#˙ăżA†1šcăxčÁŹŁŢ0»Ăń »úÉ7ΕŐ> PŇëąOü®.R ·Ů*Q‚J!/tfW˙ĺŇŰ ‰!§ď`Č Ř—ną%t§ű»Ŕ'ř~gâ–ë3ÇétŢŔŇ=/U ń'qŚVł‰±ŃQäyŽ,Ď!˛P@a$Ąxć™ţíë”ć“’Á !Lö[X  ¬<8@9€8ŽŃív5°D9T»«qÍŁ:Ą¨/͡m˙JŮŰ2Çsyť[°ŇܝغfPˇ  ,/Jó˘ş÷˝e>gfçĘóŽAiő’Ůő aąíÇą‹A±™‹y9Ŕ©‘襩‹vŤĄ^­ąjpa(„zACů•/5hŰ´¤VÇ“Ź?†űżďŃYÇGţěŕ7˙ý0;7G“‘…A šőĆ_xcżŢ–€>óŘćfłůNE˛±ŇŹqúä <÷Â.¬ľî<úČC¨Őŕ‡°.:Žz1nD|B=ŇË}âׯŮ—Oü°ˇ–öŹsżą|-†"ÓD˘‰ĎĽĆŚĂ‰Ř"®}Ţ?É{eĄŹűĂÖ‡2ľŘ·ńĂ[zé ÷ťo$ Îťi€˘! Ď îĎkj Ö— <©ŔěűO©@"ľ˛uaŻŻčş—áIĘ\ÔηĄů?”÷żm.Żôł±řóĎÎ ź •‚›<ő‘q›ŘÚjFIĚo@RbĎîÝxó÷ÜoU-ľ÷ĺÔBŠ‘)Š"ńÄ×Ĺëî»ű÷˝öbÍş f7@1Ć’¤ö†Ź}âˇ{ňo}˛zťe`xhčaXŽÁˇD!ů‡GĐĂľý»‘e’$6I:`C>-׳»*Îx"żG(ţ”źÚÎć^Ü SĐ.™<Ë=—Ł!OOPx}Yž8ŕ¬@! XP¤˝(ć>łĎŔŚ;§Ŕ¸ [:)( Uť/q˙ůĂÂääziO'\˛°ľ_ÍKXş6+ýşÂ~}¸ë×r™¶‹;şĚBŔ§ěŻĘĂô©nV©ă@pąq(qěKŤŤµiŔ9C†ř‰źx'B!fkwŻ,·`ČŇ Ü@0g E.±ďŔ^\µfľđĄ‡ń+żř/µŰ’B‘9WŤFëw|Oőö–€˙÷˙űË(©%ď"YŠÔă( ńżžyáĐ0î}ŤA9VëADi^»Â˘E&nŘ×ŢYĂÉ ‰ťřďÚ—ŐŁłâĘͦ(Š’ÔAíÝwć"ĂLżŠy÷n‘Ü˝T&Ą}Jz9Ě«§ĽăđkU!»Ä‹v…sŽ€1lŰr+‚ @7í餛J•€†Š§bă˛i™ó.“}?łUźk,SŤL$—.>˸TéC°ËÝjżk\Á=-őóňšë9"x€8 ĐëvqňŘ1k+¨~—W¸[éĘN?Šőë®Âs»^„ŢDÝ]—)Ţ0Ľ˙O?ú‰±öłďđ{Z6nŘô®zR3_°zŰÁÇ6[xţůo ®7ĽU`@)çĽ~xćź[de÷ŔÁq­JĘ"¤#&ŁNxDE‡Fq@"/tĘní…Đ|\ÁŚ!ŃHĘ#rčĚF-t}Ş’$Á»Ű:eÝž. ]ciV^t?µ50€5ăăHł Ů(‰ÖŐrĄsó•-Wp7ŻLŐeËeaĹËXhţsĆbâěŮEAaýJ)81hø™'JA„v˝¸[nÜ‚}ű÷âš«7&Ł‚^Ŕ580đ^ňű]Z­óbĄ ńČńăčdf.^@c`Đ:|îOş¸%ţĹF.«ké$vp¬×ÖwwĚkşFE0ý(ĹLćY˝Ç¨(•> ”AËô'Ąą?­řŞ÷ĹN«–ŕĂIfˇš4ĄŤeý‡ľßĘEĄ6nÜĄ D¸ÔK[)ßUEI‰M7áȑËĎUŢ?@sśrD[Ä0Úó h÷ş8|ě®»vłöŘXóRIż — Aݢ'ĄQ„ † SS8~ě0˘ZÍéäTŽRPś—6C˛V~Şă‰ŽĚ™Ëí9ÚŁŽ,ĄţÓ˙ĽMIđČłi–ő…€H:`"1„mĹ~fďN?7±tş0tëć·/ň»—c›Ćkőî˙˘]Ij5 -»ŃéJůî,ŁŁ#8yę¤^-iĘĄTBň)ĺ«R"pňÔ \ś™Ńą ýx ĄâŽęőű€@MDbš+»kË™ÓÇQ«·Jz/j©屿RďpÜź$ĺE3CŘV47Ö3k´âqóMBi# ŮýÖy<©„ś÷F(ą=0$.TlľBŚU% *Ű'aî^ CřR– ~)kđęńńâ˙GZň<ÇúuëpňäIýŐżňqź2ç&5ęçä…óhw{vĎJ’Ěü¸ýö{ęĎ=÷TÇě ś5˛ćÓ’ Z‰ąĐž§Î<‘·|“Ž é?xÇÍ9ĺ@CW']ź"Öh´Š!N•ű„mA–TwŤĽ0n@pü0€+lÎś¤@ág¶µöďipéĹ("Šy/ŚYy`ď—Óý­€sDQTÚHäŰ].eł¸’D)ŻT©ŢOż{ţN(Ś1˝Ç$_ě ¨Îmô“%˛s@@ĆPŽv{…Ôą!ťń\ç5زmëęçž{ę€X €ُN˘4‘Epy®ă앳Z’x«Śť DŹđ‚›Oʸq1rZNLŮł o„Ű0Â3 Zt"%PäR°Âps“@¤€Q QrfökÓ„JËd Ýí :"¶ę‹%OĚ'‚÷$§.Eźą×Ď#´ßSSS‹"×|©a©ĹDŐ:ŐßŐŤ&űI"K]óJŰTKżM.—â|Ő˛.•M©ďŇę>u/÷Ř•Ö]® #VCł “~iUŔýM_äÚćižˇČ k;łŮŔ1==Ý‚ŢWĄ ú@¦˝07aq\i]‚)}‘u«WCeRŢ(„YŠ`ű_bƕΉc2ĂMÁĽ,L9±Üë”R6âĘuä¬óľXd%y®w¶ŃĚš–Ąú¸čH)ËD ÷îĂ0´Ű…U%éjé;ڬ®”Âř訰ÂČđLçZŘ·çĹ@-Uŕ"ÉÜÜ,Z­¦éÜW¸÷®×˝T!ĎuÇyž{D˘9-z»&ťNč &¸°»ą€ë­Ł9ŕÂx‰{úąś3‘fŇ& RP$˛+wO’ ŽÔ[[Q$ CaŹ0ŔKGĹ™¤–ŘĄ%·@˙–śhDI˛ęsŚ+ŠK D)® ”§żk˙A^ä™I­M”~~AĆA4­€JzŰ“čŢłčZPëÄ(?y H…ĐŞ…˛´Ü¤(Šâ’Ćż~ĺRĺr&Tż6~ý—./G›~ăńRďíĄ´ąŇç©¶{)÷vÉ˝"€J˘VĂ«7_ŹN§%”¸ ťť??)‹4Ťsl)  ąo˙Ľöľ×"Ď5uĐbŠ…vďţńwáŹ˙ôżĂćOUnS#™÷· %â ’JBć—9 ĆäV÷/ŇHş0 ޏpa)é= ŰíA™ih±Ěxä5‘KŹsëďĚ­ËÍ™H8/†U´—ÁćÖ3O*](ŻpŻęäXJčÇ=/w{±j›ĺę/e€şś{{)m^Ęó|«îíJÚô»7j÷˛=ʞ˙ői/ńÖďý>´Űm((đ‚Łŕ&†s;vŚó¦’2†QÔ—’ę{÷íAá…»ęUÔúeýŇ{üÇ4ŚŠŔeC†¨+÷P$¶ő3XAN^˛ )$Žřm’đĄ–L¤Ż3rT/ď…ŕJŮĹD”Zę Ť$\úfů2­ăÂŰÄ‚yűŘqĘXěrßĂž‡“Ě$*TH*0ÉćżUDu)`©¶żśëĽ”6/'QůĎôíz˙™^Ęxż”çŃu}[…4ź€ětđηý0Š<‡âF*7 đ„”8tp?8çőBĘe%€@ma~{÷ěĹŤ7ľÚčٰ1Ą]qA;› IDAT(Z˘®Ŕśc¸Ľo Ôuá’™’TŔÜo'(äy˘X÷]OTŐëżÜDĺ·{%‰ęJžçĺ’&^Š´§”B7M‰(č(˝ŃěŢx?šŤ¦K‚Ă4ăLŕěŮ3šžbhč$ś1<úŘc¸ĺÖ›5˘“Ęčö˙îýżż˙ô&ńÁuˇkűjݬăěZTVFgđdŻ- ŕ€…ęąmŔüAU&Ô_·I2-qĂŘ3xMĐ.7Ĺő1{źPÜäbŚ™cťę‹1ş/#ţŐ Čň§ć14Xď’ß9Dőrr·ďd˘şśçůfďíĺhÇNźŕz~K)ˇ¤Öý€_~Ď{‘ç XÉ;%í;ž‡ˇCKüŔâ͉ťPNś8‰C›j&^ßI‘řă˙ô‡PíOa^ëĹ“€¸ą«ď¤ý}ń ¸?ď8é őŁ|-@'´ČóY–›ż Yž!·żuPf<i–#Ë3}ĚüéPâÂ&ßĐm ä…v/ćąDžIäąD–ö\Qä(̵óB·Ď s/y†"Kńě®ý ĄÖU+˙rDE~›+}ëyµ]?Âčwo˵ą’çą’{űV=Oő:W:ŢŻäóÄQ„‡żü8ÎMč°‚‚D–őđŻŢ÷ €™óRI(©PČ “““8~ěc•5äţU Ú?ذęÚÍ7ýT’$8wţîľűN[Éęę ¸zĂF̧)žßńśÉÄ,ű7OÜ\'®^>ďߊ{řŞçÖ"ß ś¸®_ś2« =Ŕ˛(čtý¶NéĽňú°ý…TÚ€©Ľz ş­Rö·*4 R˘Č3ôŇNź>%s\˝a=Š˘X4q/‡»˝î{©64á—jłÔ˝]éuŞĎôízžĺž‰ę/w­WúyHBŽŁ_üňWđŐ§ź±¦(Ął^˝î®{đö·ĽEűţýű€ŢľýɧžŔÂü<ň"Ç}{ţŔ9ł˛Ş ˇ2ĹÔEp6:95…Ç÷ß˙:í´«ąnšgř?ăÇs;·cÇ‹/čÜđ$ö+éͭËÖmI_÷Ĺ}· ¬ŹĐý}ć6AˇUŞ/‘ë«?°NŻ×{J LZMđÄ|eěRgR^[-ŇKÓFIqN‰K ď>iÔĽ¤AŁ÷#Ź=áţ×˝ë×­1Ůu•m{ůEÁ E—ŮđJëű÷t7gݎ®čJö㥶YZ樔’ząčpż+¸_}/äÔÓR˝>},wŹÔC·×Ăń'đůx »DÔ ”„T RI¬Ç/ľű=čuőĆ+\r›+8zô&'/jç]h˙n.QŠTĐHÁq".8{ęégpő5±áŞ –řéÚťţţ#‰·Ľëí8zâ¸!,f ľ}Ŕ rŮaő2ZnKg°8p„AG(:U€ym| ¨˘}ë1{şOŇŰÝoŤÄtηC¸:îîč8#/Šň~q!B$őNť˝O<ř4ę5Dq Q ˇ¶˙{kŞČxéÍyë«!ńŠů˝(xőYYďóîŮg>¬|˛tŽ|ľĺný7ç75cäŃÄe'DKG‚f€„ńBIxŚjjŚe4É!•Ţ’LJŰm(«”‚"{Í=Eű$hË;18-„€S.ů*qhŰFęëëc˝§»—¦':ĘŹ¨Eů¬Č137‡8IP@Gô)¦000ßúőŁ3@s‚i)€1†N·Ý{vs ËÄqhH±D(pa*´;íąj®Ţ¦rÍŃüĚçńsď}šŤ߸§ĺ>÷7ŕ-?ńvś8}ĘlÉ ÷–°ye,xĐ1ĺ}7/Ěá…+=řŕŕ·s÷˘ŻŃŻ~LŞR‰˙ŰLpIŃ€zŞWŤHK‰Ćţoş3×cD•ÔG!ÖŚ aÍř(’8tŇüGc”´Ŕóq†]Šś\D¸x ż'Ř$šUţeë0ä<šöďÇ žŢčť{ťşÔ=—*»Ż}ľąź0P ô˝”VÔď—)ťŹPyˇÂ¦K¤Ş,e08HĂ$¤“č¶J @}*ĺŐőŽy5@«śín‡ŽťŔŁÇĐÉ24MüÖŻ˝EQč-÷$Gť¸´P8gŘţüóvÇqM\śŘ  č'¤ćźyâ+Źß~ďëv~rJéěş<điüÔOľQ•ŢÝ#|ďxß{°k÷. Ě(€›.ŽččĽůô@@-nWŤ7ĘľTTyDLöŃ;i {Çąő±ĄĄ 8b·@ä¤âP `" ‚:ÖŚ`Ýęa»;rU˙óAÖŢ–gKé÷›@¦ô{'ݞúކWĺŘhKB.íh8¬śP"hX@$b"ďĚââőčpI’4čâ†-ˇ[ÂňŽú¶ŻN™Ă{\Řçîű€ňęr\i™ŔL)e6™Ą Ę sׂ˝e;ť-@0†Z­ŽW]w2%193Źßřĺ_…04!ikwĄ“Ú Á±sç.t:](Ą÷}ÂCźúĆăć i\˘Ź  U€ą´Ű=ŐYßD᫊´`Rť›ĂÇxďzçŹ"soŽ#ćyO˙ĹÇđë˙Çoŕsź{˘–đ8I€†`)čGÔJŰĽţ«R«´71 ž.S•ĘĽm90ń‰Ý´T‹ŰŇői ĆѨհzlÄŽŁ®ÇŕÓ‚#6Ç…«ÄkI×¶cĺă¶ťą+ßç˘ţKmÝłŰ!beĐb•/>|,¶‡9પwŐú}UG…ᑢDLjw%Ńšđ±Üyž,á+MČƀޓdµmPÄ1”!lłÓ‰ôŠIÁ'~Vąžľ 4Ҩ ¸íć›±íćm€ &ˇ €qł` AŔ±wď^ĚĚLkoÂ(Višťž8{ć4ôĚÍ—Ľţë Ô¤,ŠWßşíő˝NŔą@ÖËpôřqĽęúëô˘S(§( Ľýކá‘Q<öČŔ¤=.ÍŽ2Żč }fÍâß¶Juö-ężĎq˙+«ÖďWĽ~sVn żĺ·Ú†ch á†Aňl0ănµl–ň,şÝ‘”ŮôSŮŘ“wŘ;M6㬰k78çfË4]f?FÜd"mP79điG}Śsď8sź¬aéýQîÚÚÚ]ŁąŰTĆţé¨MÎíBż­±÷ÇĘX4VśĆž•ľSî 2ę0cHEU$µčĎI$-X}ľhŻ„4Ü]{ŹzâČáçś°“ š}Šs§N¶o»çľ×rĆ‹I÷„ ¸úĘŕŢ0věĂ—AĘ€¨Ý8pRמ+č<Š®ć©,Ě%ą\ün´dŕ‚lžřNĎĺéüô›Än­ă;o‰V*ZkŹŽî‰îJy¬Ľ 1˙XQ”€A˙i˘–…ăřDäŠ20mÔî¸u ®Ű´ÉۦÍÍęBš‚”Ä®]{t0€BI(Y€ ĆĐ .Nś{üË?ôwN˘Âýĺ%;›wďxöŘťŻ»˙Ţ y–3N÷â§OźĂÄů ذa„íc so0ÄŞ<A»ůjać2F-ˇ-ĺ=•ŔvgS•TŹť4ľ}Ňĺ˘zŇrxetđBůb¸&FĺsęÂ'zUćć†ř‹*áŇ;VX‘ľđÄű—(ňÝ´‡ë6mÂkď¸ ő$±ďŔźMJ1Ôj .\¸Ű!Ő‚#i4TTO.|ä?čŽ8  Ôď-•аŔM˙öţŁůéٸčeLđQ!Ś"ˇ79Ś˘÷Ýw76mÜ`cšI·¦‰ĚĂB§ŤßüÝßĆç?ű xŁ© NĄ}Yźď}Ž‘Čj~Ó’^vi®5˘a™~–:sĚ :í˛` …Ć`ćÝ Ş}bQ˙«Wµ062ŕęŇë0SwÇü†2ŚTď]Ś\ĄănŇhn©`ł ‘ŕmĹis]îM2_t÷ń­t̵÷ŻOרԷB–jÇĘ×…ćĘ( ćk7)•Y.iD|sĚęéĘ'n ÚŇ.I 0Çč·"NO’Ô.>'Čľí¤*4pPFúĐýÁôá“TčĄ=¬Çť·lEníoŹ ŻŘőâ^´ÚĄ”&ó5ęjx|LţÉďýÎŻwÚí¦táq"ňĄŠU÷YŢ·{˙kî˙ľďËÓ”É"gDÜdąUŽ=©éi¬]3Ž ÜäˇU@„řˇ7˙ ~čm?ŚCGáŘÁý`aD­ř©tđN™[aÖÍL{ś>Ëb*Ś> šě^}BŘrŐëÁ1v:ZŞę·wňł bZÜ#‰Q‹IĐ+ĘČűÄé˘8F„fŮ5‚ fq¸ăÖŁÂZŇ!“ E§eÓçôDbÂËĆ$¸ÁEŻ D„A€ „!x@„!D!Ca†‚A"B0FE˘a!Śb„Q„ ŠÍ÷A#Ş%k5ÄI Q’ Šc„IÍŔD0ˇźÓ<7gÂóóěćÓ$czŚ8×3>Jčď Šq#‰řźN:!GAA± •Nń.ˇP0ý)W¦ŽN[H‰B\p„~wŚ1dE†5ăăxóďÇ-7ĽÚ‚Š“xôźPKj8{n;vĽXĘŚ¤%ťÚ.ŞŐÔČęŐě“ůçż=qöěsТ?˙˘P° Ŕ¦ ×nľçg~őýś›śRy/g‚ÂQ™ä ÎMs۶[pĂ«6C)w_.zÂ'qŚ=ű÷áţ}<ýµŻB4›6÷\;°×vëóKÇúŐ\}Ó?ŕ·Ăâ¶(K‹9|µ­'}TÚpÎ16ÜÂŞ‘V‰űŰÝŹĚÁ9’ZMoß]Hł\¨Ĺ Ŕ9şiŠv–ąćm†A Q»(Üő­–ĄżEŚ,äV˛b̦E×ŮŮ™Ż0 ÁPä…ÓťŐŢ´eî“™ľHĚ·ădÚ…±_zP&ĎźĂĚä”ůÄM•™?ľTšTŘšS’ÎŻ;{j@†PR˘Űë)¤Ł˙Ă­ţł©P¨ÂőUȲä`®%ĄDąţťT˘űha¸ŐBžĄÄÝ[¶áŞuk d,+Đn/ Ë2gĎPa`ˇÝĹöť»ŃívŤÄ¬iÔĆ9âF˘FÖ¬aźýŘ_pß®ť_pŔśŰo‡»PťĐ€Ŕ€MW_ĂkŢýË˙ę˙šźšy/cś‚a!ˇMË´Z ÜľőV¬[żľ´Ô±MÔ’‡ŹŇ˙äżŐ Á §ň€ L¨}€ zW‰Ôíô2ŔaA6Ó 3¸:ˉ®·j¤…UCMăË'b#BÓź‚sıŢy9Í2´;]a€FŁ .8f:]Ěvşp’‡&ŞŘHišjᇑnMD¨ąF–fPJBnT5â2^ýW«ŐÁ8ěf‰Ý?7Ž"Đźäu±ci"iÔ' í´!8¤Ž>„ó§O Š9„Ň[“FúTČłĽ¤ç“!•,ű…ÔÇZÍ”R™ťµD&µŢ ą89Ç9’@–gž-AşOŻľT­fRJĚÎÍZ±_*ťznŐĐľ÷î×ŕľ;ďB’$h/, B (r´Űäy)•‰łaŘůÂnś>sa ě{Öă ‰ź‡IŁ®†WŹłĎýÝßţîޝۿ-öO@[ýsôáţŔň*€_HęÉdÓ“g_xî;ď{Ó[^ ,ŠŚ’d¸´Y‚ ąÄ±'1qᆆPŻ×íD ÂąŽ"l5[xë÷żď}ĎĎBJ‰í/ěD–Ą ]5Ë‹{Ş`ćÎŮPLđÚ8ź®ůnۨJ—Äaś¨ď$ĎBŻ´ąP-2VÔ{ŘXÚ™B-ÇaI?ő'’ţîěYžŁ—fP`Î#ĐI3t37)µŞŞŔ¸€”J'D‘î™%Ą»ËÜ.!uiÖčŹtmË Íw.ôő5€¨ĹăjĆ–ô[>\Îl iš«Jp.¦W°ĺ…6ČĺyŽéÉ‹źťEQ(ce—(¤r®2c™‡RfČÜZÔ­ő]şM!­Ź]E!Ńévś®0n8Şgţhl!u^éäŻ'wçE‘ŁÓéš<)ň,ĂÖ›nĆ{ěxíí·#Žcôz)”*tJ}ơ”Ţ)3Ž8‰±o˙!<őôłXčvX;7Ć ˘őÁ¦ËţňOţč7ŹÜ˙$€ăpśßşüú•+ €´Űi·żöČĂOßű˝ßżµÖ¨ĺYYĐ–ŐŽk‚1ÁŃë¦8rä¦&§00Ř@˝V×Ďcą“ľPˇ „A×Ţ}ţőŻţK\µv=Žž8†‰“Ç0đnG:1Šű`°łLŞü§”\ÓŻôY!ęŢő– "~s>1 ­·°˘¤TŞ ˘ÓŇ…T Y^ Í2c ĐM3ôŇÜłP Ąg…w?ôF•f3‰˝Ęe ±ŔW7ŽB`ŞŕÄ] ڎđZëG/ń+© šq¦ ‰ß¨&Ežcfj sóvL|÷ší=‘˝ČÉťF×öl\pM(˛@·Űµ`ˇ¤´őotŠy ÎŞď×Őž Q٦gf028€7ŢsŢőöÁćŤ×`x …F-gĚ´4†^†0ŔÇŢ}ńŐÇźÄÔÔ !< ’WƢzŚÁŃDµÚą˙öź>řďf&/î„&ţ ĐÄź–'ëâr9*€_lÎ@ĂÖ¸ęg˙ĹűĺÚnüţŮ‹ÓJf9ăŤ] oămPRbőŘ*\˙ŞÍXµjD[FŤČć¸1qK '8zň8>ú±żĆ_=đ÷ČÚm8ńv&®Šěý[1}‘­` ±.đär<%O‰ÂK´jad’Ş–ŐXÝ9ŠbΑ9:ÝD V« ůn ˝ś…R‹âq ČR}ÎFŢ)č-ÉnOűŻÉř+Ňkő°áÁ zeY’€襩‘öś>f–“žĘ´—„3˝~ÝömU Ij"gÖKĘΞ<‰‹çĎ[‰NO-öJé —sĄôNФÓűÁ=šp¤•bęő:¤”źź/« ¶Ť ô~Rąs‹íä Đ™˘Í&îÚş [nĽ«WŤŁ—öŚ Ŕ1>2„ńá!pĆĐnwĄ= 4Eo<ű<^صÇěź;—,=%éA ®×ÔČęq6qöô“ýă˙ú_ ŁüÎ@űú۸ç©@m €ăÖßőş7Ţ˙¶w˝ű×:sí(ít© cý BłÍ•Ţ= nrí) ´°yóŐXłf ”bFÔ&NKY? çµ$Ćc_{˙Ě'ńů/~`@FnÁe €e[ťä—t=jËđr]¶+`‘-¸>>2ĐÄĐ ­ s°6 ŇŹă(ă y^ ŰK!„@R«sŽ…4ĹB/5/…Ů·d™5(şÓNG× ŚľVžeŠŚ†ş í§hďÝ€IG`Ś!MS/U:Ü3Ŕ€ ˝fÁm^–üÂ$)­0%°8wę4¦.^(©k¤~‘TĄ% 4o$…&V用×jJa~aŢH5Î…č‚~śDø^źĺąV7L">)$¤NWd¸őĆ›q÷m·ăžŰďD–e›ź+Ƈ0:4Ž0`87çžŰŽýű"B@pŹ2 ÁpDqŚúŕ V_űâĂ˙ýÉÇţáa§ˇłüĚ@/÷-°„Îߏ_JapqM#ÖŘôëżő;ď_5ľzËÜÔ´*˛‚ p‰BAhv ´5“kÝ'‰clܰWm¸ Q™”ä$Ţ[ř7˙"@†Ď?ú>ó…‡đĄG D±‰ż4Q[5e‘dĐH€E^ŹkS<P=ďüď6Ž€q 41d’ńĎ€±¸sĆ‘˝4I3vš˘“fž ŻF! Ďr€ŃO1ŠŃŽFćgP…B–Ą¶+ €6NrDÇ1€4Ë,XŘq  ±ŕĘ´KÎ0q}ýˇ+‡Q„(ŠJ€¤¤ÄÄą3™ś\dł!˘Uć;‹"·Ä®M‹T)‘ÔjR˘Ý^đě-eź˝ăę”×AŚTZôϲąĚpË 7áŽ-Űpű–­` Y žÔťnÇ‘±…€a|dVŹbßŢxüń'q~â 4ŢIłš•1ăIÖ`ĆG…H55<>ÎÚťöŹüÁď}8ËłĂĐÄn•_Ëŕü>!żÔ˘g˝ó BKkîýŢ7}Ďüř»~)ë¦őŢBJ*,@†Čo,<‰€SŠ.=éÇÇF°~ýZ ;=ei@AŮý 0@(}â«řěĆ—ľň(:łłŕIÍěWX÷đ%’ĘDŚK€,>®iŢó ďC­Z { €u©é{Ň× ĂĐ• ôŇĚ tłí^ę8ş!†0ł/˘S)<ę Ę÷JR€ń/[—¤GĐa¤]vY@ŕYšYĚş­”±ł8Đ“=Š"Z5Şô¬RJáâů󙚲vc ’F\×jĄ6Ô•ě¶Ž˛Kc•RăRJtÚmmw!÷˘, XU@«-EQ Űí Cl˝éfܱe¶Ü|«¶µČBç—0c”$ Ŕ€^ŻkĄŮl čuqhďlßľEQ ú=ŮMpüˇ1€„˘Z‚ćĐ šCŮSŹ>ň?˙âĂAGöť0 -ňŰ5ţWJÄßl!»€/ ¬°ć}ď˙ß~îU·l}Óüä ň^LiĎ@jŐ 0ŞA vé§ŽoOÂk׎cőę1$q͸qŚ8gŘŁ˙ąbŕB ž$xaĎ‹řÂWĹ—ľüöďz#OUđąőbÂvÜş?7/ŰĘDDëśDAý•ë4hÖKŔˇŰ•ëiź»€Ô¸ąÂ8Fčĺ9şYn_#Ia@A湍ĺ÷ą2…•ĚŢ Ň»tĆY' ů\"’0ňÜŞľČŞźAą|ĄmŁŞÓOéhŇŔě/aúRJaňÂĚÍL[{•EçÁăĐZŕąčל{/Š#(U Ó黀Çń©ž,ĺz˝6mŘ­7ߊ-7ÝŚÍW_Łąż"˘·wmßaśD€RB Ž<¶żÓgÎ" Cł$šžŐ_3Vś3°0@R‹Qo¶ÔČęqvúř‘Ż}ôŹţËGś‚^Ô3 Íő»XĆÍw©ňrő# Ą´m`ŔꡡÍďű×˙ö}kŻÚ¸m~rFiơ%‚0†ĆFŔMô™]3®'ˇRŔ@«‰±±ŚŽ # #d&±¦/ nHz c0î–ľúÔřę_ĂWžü_8wü×D‘ :"˘ďGŘeUÁ'Ř*PĺĐ`" ţ~­F­f}Iâ´Ş1BĄ™ŢźĆ+Í ô˛Ük«_E`Ľ%EQ4Xb·µ XčK’B  !VŇr‚™’`g~IDAT Áä…ŰÖÓ(´Á‘ú3€éĽ-Ěr~Ň‹PÇŽĐ»Ö]`fr ósł†0ˇ €¤ —7Š…‚^sb †šK:˝§Da©¤öĐůB"ÍS¤Ý.VŤ®Âí[·â–nÂŤ×߀ZRÓ[n›ĄąfHŕV2š{P ÍFĂu9|;žŰŽ}ű#0*/Ş›+nĚQ‡5ÇŹQo6ÔČř8›ť™Ţű‰?˙Ó?ť8sz4Çż§ëŰÜ~ËĐć˛ĺĺ*$ DĐ@° Ŕř«nľuë;~ţŢ;42vÝüÔ”’YÎŇ.­0µ×ŔÚtČjhńť’@pcŚiµX5:‚ÁÁÂ0Ňş™4y `Ś I’`rrO<ó4ľţĚÓxňągp|˙> Ž!˘BË^†c—UJ’ág ΠčŘímčÖ8®ĘѬ×Ь×ěyjĎüďŚĐŽł\f„@VH¤fĺ­Ďg„¦SśCÁěŠÄ$¬čfšŇ9e]gTŁ!a(Mč‹ú~bUfS…)ËĺČË@Ćeô\aÔAwAMŔł33X›µý(ŔĆń{.MęŇW\`Ź[@ü P…ÂěüŠ^7mÄ]·mĂ·nĹ–›oĆĐŕććçŃí¤čĺň¬°FÓőśŇO80Ř@- pôĐĽ°cvďÝŻÁ;4 Th0RĹËü9‡ A"Ş%¨5jdl륽“Ź>ř©Źîzî™§ˇ}úŕÄýRfßľ”x™ĺĺę“lCĐ@0zómwŢţöw˙ĚOŹŽŤožźžQEš3&€k "ç5 ©€{FC˝ ‘™mŹF=Ćđŕ ›H˘™ ÎĐEŮĺëŽ4 9碝^ĎîxĎíÜŽçvîŔł;w ›źBÇÎM$b•ă!ůŰ’őł řMíőµÄöĺ÷瀰 w;Ö6ŹBH‹BňšL!Bh ŔF^zÄîź*·m™'ŇŇʲEŕÁ€@€y;őšń,ők,×:ŹIrŇ 0ď ŕĆE¬¨ťá¦ółłčtĚűóţŕ˙v± Ň€‹ÔSf©n‘çčĄ=DQ„­7oÁÖ›n­7Ý„{îĽ ăŁĂČó ť^Š^š!Ë2¤©Ţ&M3äy^–ˇ×ËPH…8 0::„´ł€űbçö]Řđ0BĆ„V=$ÜľW]Éu„dG“őVS Ź­bÝnçÄW>˙ążÝńő'ź„ó' 9ţ<áS\ß/Żř}“ZCÁ 4ŚĽzë¶­?ü“ď~ÇÚ ›nmĎÎ"ďe@ˇ ¸@(B­©@6 n™… F:0Ü/  4ĐjŐQŻŐ0¤ya9€-žNiUsÇ‘ˇ§Oaçî]xaĎněÚł;wżîĚ4†a¤Ő@oĽŕéúî;ŕ<nýA-NP«Ĺ€{Ä€q;á`Ú0h"ç×ŐÁLŢxR\Ęu·®ś1łNꆅĆČăüvzĄŚ)”€°8:]“ú#MăΗđÚďŻďŮÍ)%Ú óčµ;$Đ{ôlÎ]ě–ÚćE†ű±żůäÄéSűˇ9>éř Đ?ĂřőŻ´|+€JęZĐ…#ĆŢő żüćŰîľ÷Mőfs¬3;ŻŠ«ľekµ÷đ€‘bËź“;Ě1… Î=ësy^!wŤ’;ŹnF9.©ş°än·^·‹Âd»ĂŘČ*¬[Ť5ăk±vő:¬]˝«†Gm|>‰ţ”>l‘úŢHsý0ŕH’ĂMŚŹ ä'ĎśÇᣧqđĐiě;tÝNd–"ÍSäiiÚŐcKs $Úk)Ž ¦çc Ý¸Q!©×QkÖŐđŞULI9ło×Î/}ú/˙üahĂŢ$4ן…Óń_Q§ň­*>DĐ^&´T0 `ŕÖ;îÚúć{Ç\łů†»ó4EŻÝQJJĆŤ1 ôęĂŔ…ˇVrĚąÜŮ Č:O†0 P«ĹHÂ@݇öť÷ŇÜ.ł$b Á%‘VÁcĚZ}…ŕ871c'OŕäéS8}ö,Îś?SgĎáü… \Ľöü‚Y=) €›5ű$ÎÓú~H“‚$©Ěn8Ę432=qu’q)äĄWîńţE3¨Vş] Ĺ4qąŕŞí}Wv‰”+c\d€MUČBÇď+‰Z’`tx#ĂŁÁčĐ(šĆřŞŐ:&¤Đ ©h$Ě-ů+;+DO*ĺC¬×c¬ĹŘčÚ ł8uę 9Ž}űŹâÜ…Y­Ź×Ły–"O{HłŠ´‡4K‘÷şH3¸ůe8}mĐK"ĵµF] ±ć@ çNźzţéŻ<öĄí_ňĐÄ> §ßwPÖń_Q§ňí*H=hÁÁĐŰúgŢxç}ŻżőÚő›»ídÝž‚TŚCëÇÖ^„%5!ÂęĘ‚ a$’¸“lę)ÁG!â8@hŚRR) ™ ő&»7ąÉŐ <€°Ş#5™XJiÍf)&.^ÄÄĹ LL^ÄÄÄLÎLcjzS3S™ťĹäĚ4fff07?ŹĽÓ¸- e€8Á¸ýnč™ ďĆ`×ášG)×÷őwe Ş”Ó-ţ)ȧĹă(BŁQG«ŢÂ@«…Vł‰ÁÖZŤ&Z­†‡0<0ŚÁÁ!ŚŤ ŠcČů8BE*iÔX­ŢDRKĐ^źšťšoň’QÍ7Ć#ž]ëC‰+—Ś\ĘfŮ…©/•¤ŢJjé€ňĺIm‹* mŁßE 7Ľk(«2e (¤±xz¸¤ŠdăI:Žł{¦K'Ćű.[ˇ­ý\Ba6( 'Ú˝×ë„ŔüÜěů™ÉÉÎť=zxĎ‹·?őÄ>h—\×üůśť¸űRţ»ŽË/Wţ1@µř`Pő.”@.Ç*0Řc×\˙ŞŤwĽöľk7mľ~ĂřÚµW ŹŽ­ăŚ#K{(˛y‘)’+ĄlŚ óg˛˘ 8L©N%ĹĘ ”MnI’„厾(\Q9\><,R!,áÚcĐjB‰@KÜJ҇ÇŮ—ş¦/ŞŰăľç‚"`÷^ŕ 0ë=ČÖA;a¨˘8bQ#ŞŐ ÇÂüÜäÜĚĚ™™ §Îž:y|ĎŽçź<|čśa®g¨ŁcUb÷uxg¬~o껾üS€j©JdGč') A@@Ş„µ5¬˝jĂÚŰ^sďĆ ×^»nlőš5Ăcc«‡†ĆZCCĂ :ÍVžĺ(˛EQ(UHFâŻuűy€ߢ/°–{gŕ÷Ú¬¨čěî·4ç+{˘¦”â:u–„*ŕÎy}”Ĺ~ŹČý?€4± ŢŕSČ2§ý# GšŁ3Á!x † ŁQ"Š@{a~vAsôóS/ś9węä™ý»^8qöÄń“(´OäýťDůĺ¸ű?:‚Ż–ŠP-ľ ˇŞ:(‘1Dٶŕc8Đ„CCc·ÜvÇš ×m_˝vÝřđŞUcĂĂŁŤFc(©7“Z-†Ň®˝"ËPä…qóe*O3Vd^ ŔŮ ŕ=”;ć|ňŽÉ0VďIUęĂ'dë.ôÚJEaŽúśY¬¤l>\ZpOd7Ü[…aÄDhĽ+a„0ŇŇn7ëő:3ťvgz~nćâěäÔÄ…óg'Ξ8qîŔ®ÎÎLMN LČx•ČI„ďÇŮ˙Qs÷Ë)+ĐżřôUőáRŕŕ«ôG@áźCĂ«n¸ů–Uk6nNęőfśÔâZ2EQ-ŁV†q†‘Âúţ‹BBÉÜř,'7‰1 g;‰ĺVŤđÄoĎ·ďů0@QzĚĘLÜl˙e ťvm8×Ë”ÍFŁR»ó,Ëşy–ϧiŻ“öşÓÝN{®3ßž[›™š™śš;úÔä‘}{/LOM^€&^ź;‘§}ľç•żKst"ňŇÄŢŻ¬Ŕĺ—*(0”Ą‡Ş:á’ÍÁ‹ŞÂ˙í×­ö—´††GV­ŞŤŚŤ5“z=Ş7šµFłY“8¬×ő #\AaĚ[6g Y-ˇ”Rf‡!ĄŚŐQ)ĄŠ<ϲ<ďy–y!‹<ĎóIW'& b990mHG=wNLA|TSG‚[YM\ZLŠ][N‹^\O‹][N‹\ZLŠZXLUSGML@}GF;w98/m'&!cXJ?93.)#  $.7F--'c[XMwtd‡s­”~Âźš‡ÓŁž‹â¤ Śď§˘Žű¬¦’˙­¨”˙ޤ˙¦ Ź˙¤ťŚ˙˘šŠ˙ź˙ť•‡˙›”„˙™‘˙˙—Ž€˙•Ž~˙•Ś~˙”Ś}˙”Ś}˙“Ś|˙”Ť|˙•Ž|˙–˙™“˙ť—˙›–˙—’}ü”Ź{đ’Śy㌉uÔ…€mĂyueŻliYšSRF€-,%eG8.%  #.;]a^S„‚o§™•Ç©¤’าž÷ĂĽ©˙ľ¸Ą˙¸±˘˙´«ž˙˛©ť˙°¦śţŻĄ›˙®¤›˙­˘™˙¬ˇ™˙¬ ˙«ź—˙©ť–˙¨›•˙¦š’˙Ą‘˙Ł–Ź˙ˇ”Ť˙ź‘Š˙śŹ˙šŚ…˙—‰˙”†€˙’„}˙Ź{˙Ťw˙‰|u˙‡yr˙„vo˙€sm˙~qi˙{nf˙yld˙wkb˙vj`˙uja˙vka˙vlaţyoc˙ug˙†}n˙Źu˙‘}˙’‹wřpâzgČnjZ©TRE‡ _</#  +;.-'epm`”“Ź~ľ«§”âŔ»§˙Ĺż¬˙ŔąŞ˙ľ¶©˙ż´«ţŔ·­˙¸°˙Äą±˙Ćął˙Ćşł˙Ćął˙Ÿ˛˙Ĺ·±˙¶Ż˙´­˙Ŕ˛«˙˝®¨˙ş«¦˙·©Ł˙´¦ˇ˙˛¤ž˙Ż ›˙¬ž˙Ş›”˙§‘˙Ł”Ž˙ ‘Ś˙ťŹ‰˙š‹†˙‰˙•†€˙’}˙Ź€z˙Ś}x˙‰{u˙‡xr˙„uo˙rl˙pj˙}mg˙zjd˙wga˙sd^˙qb[˙n^X˙k[U˙hYS˙eWP˙dUN˙bTL˙cUL˙dWN˙g\QţndV˙yoa˙‡l˙Ť†r˙„käwr`Ŕ_\N–.,%g<, *>DB9r€}n© śŠŘ¸˛ ýľ¶¦˙»łĄ˙˝¶«ţĆ»˛˙ĎÄĽ˙ŐĘĂ˙ŮĚĆ˙ÚÍÇ˙ŰÍČ˙ÚĚČ˙ŘĚĆ˙ÖČĂ˙ÔĆÁ˙ŃĂľ˙ÎŔ»˙Ëľ¸˙Čşµ˙Ͱ˙Ŕ˛­˙ľŻ©˙»­¨˙»­¨˙Ľ±Ş˙ż˛®˙Ŕ´Ż˙Ŕ´°˙ż´°˙żł°˙ľ´°˙˝ł®˙»±®˙ş±«˙ąŻ«˙·­©˙µ«¦˙´©¤˙±¤ˇ˙¬˘ś˙¨ž™˙¤”˙ž’Ž˙–Š…˙‹~y˙pj˙vf^˙o^X˙l\V˙k[U˙iYS˙iYS˙gWQ˙fUO˙cRL˙`PI˙^MG˙[JD˙XHB˙UE>˙SD=˙SD<˙SF=˙WJ@˙]SGţmcT˙~k˙–Ťx˙Ś„qÚuo_¬B?5u?+1 Wrpb›”‚Ó´®ś˙µ®ž˙łŞť˙¸­¤ţÁ¶®˙Ëż¸˙ÔÇÂ˙ÜÍÉ˙âÔĎ˙ćŮŐ˙čŰÖ˙ĺ×Ň˙âŐĐ˙ßŇÍ˙ÜÎÉ˙ŮËĆ˙ŮÍČ˙ÚĎË˙ÚĎĚ˙ŮĎË˙ŮÎË˙ŘÎË˙ŘĎĚ˙ŮĐÍ˙ŮĐÍ˙ŮĐÎ˙×ĎË˙ÔËÇ˙ĐÇĂ˙ÍĂŔ˙ËÂľ˙ĘÁ˝˙ÉżĽ˙ÉżĽ˙Çľ»˙Ć˝ş˙ĹĽą˙Ăş·˙Ăą¶˙¸´˙Áµł˙Ŕ¶˛˙Ŕł±˙ľ´Ż˙˝˛®˙ż˛®˙Á´°˙Ĺş¶˙Éż˝˙ÍĂŔ˙ĘŔ˝˙Äş¶˙˝˛Ż˙´ŞĄ˙¬ ś˙˘–’˙—‹†˙‡{w˙naZ˙WF@˙RA;˙S@:˙SB:˙Q@:˙O?8˙M<5˙K94˙H70˙K;2˙\J@˙lZO˙|j\ţ†vf˙Śn˙’Šv˙~ygŐdaQžZ2 1^{wg© ›‰ć˛«™˙«˘•˙®Ł™ţ·«Ł˙Á´­˙ÉĽ¶˙ŇĂ˝˙ÖČĂ˙ŰÍČ˙ŢĐË˙âÔÎ˙ä×Ň˙čŰÖ˙ěŕŰ˙čÜŮ˙ĺŮÖ˙á×Ô˙ŕÖŇ˙ŢŐŃ˙ÚĐÍ˙ÖËÇ˙ŐĘĆ˙ŐÉĆ˙ÔĘĆ˙ÖËÇ˙×ĚÉ˙ŮĎË˙ŮĎÍ˙ŰĐÎ˙ÜŃĎ˙×ÎĚ˙ÉŔ˝˙ľ¶±˙µ¬§˙«˘ś˙¤ť•˙ž—Ž˙™‘‰˙–ކ˙“‹˙‘‰˙‘Š€˙“Š˙”Ś‚˙ʆ˙›‘Š˙ˇ—Ź˙§ť–˙®Łž˙·«¦˙Á´±˙ö˛˙ÁłŻ˙˝Ż¬˙»«¨˙¸©Ą˙µ¦ ˙łŁž˙ł˘›˙´˘›˙·Ąž˙Äł®˙Íżş˙¶±˙´¦˘˙Ł–‘˙Ź‚~˙tgc˙M=6˙@/'˙A0)˙H7/˙ZF=˙mVK˙}dX˙i\˙q]R˙fWL˙`UKţkcV˙…~l˙}léjgX­a2 (Jmi\ťš•䬤“˙¤šŽ˙¨ť”ţ˛¦ž˙Ľ®¨˙õŻ˙É»µ˙ÎŔş˙ŃĂľ˙ÔĆÁ˙ŘĘÄ˙ßÓÎ˙ă×Ó˙ăŮŐ˙ăŮŐ˙áÖÓ˙ÜĐĚ˙ÚÎË˙ŰĎË˙ŰĐÍ˙ŢÓĐ˙ă×Ô˙ćÚŘ˙ÔÉÄ˙¶­§˙ť”‹˙…~r˙qj]˙]WH˙KE4˙;4"˙,&˙˙˙˙˙˙ ˙"˙#˙$˙%˙%˙%˙&˙&˙%˙$˙#˙"˙!˙˙˙˙˙+$˙71˙D<*˙SK:˙cZJ˙ti[˙‡zn˙šŚ€˙Żž•˙żŞŁ˙»§ź˙şĄś˙·Ł™˙łž–˙¶ –˙ľ© ˙ĐŔ¸˙Ç·°˙«ť–˙‚~˙|ne˙jRH˙w]P˙‚g[˙t^S˙fRK˙VG@˙PD>˙THA˙[PGţi`U˙‚|k˙|kćb_Q M)/-,&i…qĹĄžŤ˙ž”˙ ”ŚţŞť–˙´Ą ˙Ľ¬§˙Á˛­˙Ŷ°˙Č·˛˙ĘĽ¶˙ŐÉÄ˙ÝŃÍ˙âÖŇ˙äÚŐ˙ŕÔĐ˙ßÓÎ˙ßÓĎ˙âÖŇ˙čÜŘ˙čŰŮ˙Äął˙ť’‰˙xpc˙WP?˙60˙˙ ˙˙˙,$˙3*˙4,˙6-˙8.˙<1˙;0˙<1˙?3 ˙=1˙>1˙?3˙?3˙@3˙@3˙A4˙A4˙B4˙B5˙B5 ˙B5 ˙@3˙@3˙A4˙A4˙?4˙?3˙?3˙>2˙=3˙<2˙:1˙90˙7.˙5,˙1)˙,& ˙' ˙(# ˙<6 ˙VL7˙laO˙rd˙ Ť˙˝¨ť˙ż©ž˙»¦š˙ż« ˙ĘąŻ˙ŮĚÄ˙ëćŕ˙ŢŮŇ˙ľ±Ş˙–†}˙fTK˙O@9˙OA;˙RD?˙TGB˙UHC˙WLE˙]TLţleY˙…€n˙uqaČ/.'m00B?8yމxŰź—†˙–‹‚˙ź’Š˙Ş›”˙˛˘ś˙¸§˘˙»¬Ą˙Ľ¬§˙Ĺ·˛˙ÔÇĂ˙ŕÔĐ˙ćŰ×˙ä×Ň˙âŐŃ˙â×Ó˙čÜŘ˙íáÝ˙Äą˛˙’‰~˙c\L˙81˙ ˙˙˙$˙( ˙+! ˙.#˙0%˙1&˙3&˙@5$˙F:(˙G;*˙I<+˙J=,˙OA0˙L>-˙M>+˙QB/˙M=(˙N>(˙P@+˙Q@+˙Q@+˙Q@+˙R@+˙SA,˙SB-˙SC-˙SC-˙R@,˙P@*˙QA+˙SB-˙SB-˙RB,˙QB,˙QC-˙QC,˙QC-˙PC,˙PC,˙OC+˙NB+˙MA*˙MB*˙K@(˙H=&˙F=$˙C:#˙@8 ˙:1˙)" ˙"˙˙70˙XO:˙‡{k˙¸Ż¤˙čâÜ˙ěéâ˙ßŰÔ˙ÔÎÇ˙ÎÇľ˙ÎÇľ˙´¬¤˙†˙h^X˙L>9˙SF@˙WJE˙XLG˙YMH˙[QK˙d[Rţ}wh˙}xgßA?6~1+30*nŤ‡wŢšŹ˙’†}ţśŽ‡˙¦—˙®ť—˙˛˘›˙˛˘ś˙ľ°Ş˙ŇĹŔ˙ă×Ň˙čŰ×˙ĺŘÓ˙äŘÔ˙ęÝŮ˙đăß˙ľł­˙yl˙JC2˙˙˙ ˙&˙) ˙+" ˙.$˙0%˙3'˙5(˙7)˙8+˙;,˙=.˙?/˙O@0˙TF6˙VG7˙WH8˙YI:˙_N?˙[J;˙\J:˙bO=˙\I2˙]J4˙`L6˙`L7˙_K6˙`L7˙aM8˙bN9˙cO9˙cO:˙bM8˙^K6˙_K7˙`M8˙bP:˙cQ;˙aP:˙bP:˙bQ:˙bR;˙bR<˙bS<˙bS;˙aS;˙aS;˙`S;˙`S:˙_R:˙\P7˙ZN5˙XL3˙VK2˙OE,˙?4˙<2˙90˙7-˙2+˙0*˙% ˙!˙NH2˙xra˙Ł›Ť˙Áµ«˙»ŻŁ˙·« ˙·¬ź˙Ľ´¨˙»ł©˙—Ť…˙pe`˙QEA˙YLH˙[OK˙]PK˙\SM˙bZRţyre˙}yiâ43+s,M~zkÇ—Ž˙Ťxţ—˙ˇ‘‹˙¨—‘˙Şš“˙°źš˙ÉĽ¶˙áŐĐ˙ęÝŘ˙ćÚŐ˙ćÚŐ˙ďâŢ˙ă×Ó˙›‘†˙XQ?˙˙˙!˙&˙*! ˙," ˙.$˙0%˙3'˙5(˙7*˙:+˙<.˙>.˙@0˙C1˙D3 ˙G5"˙H6"˙ZJ;˙`PC˙bQD˙dSE˙eTG˙lZN˙hUG˙iVG˙o[K˙gT=˙iT>˙lWA˙mWB˙lV@˙mWA˙mWB˙nXC˙pZD˙oZD˙jT?˙kU@˙lWA˙lXB˙p\F˙p]G˙o\F˙o]F˙p^H˙p_H˙q`I˙raJ˙qaJ˙qaJ˙qbJ˙pbJ˙rcK˙pbI˙m_G˙k^E˙j]C˙g[B˙_T:˙K@)˙I>'˙G=%˙D:"˙A8 ˙C:"˙@7˙91˙5.˙1*˙(!˙(!˙QJ3˙}ua˙®¤—˙·­ź˙±©š˙¶«ź˙ş˛¤˙´¬ ˙Ś|˙cXS˙YMH˙^SN˙`UP˙`UQ˙c\Tţ|vh˙spaÍQ  ,OKA‰”Ś{ýŠ}t˙‚z˙›Š„˙˘‘Š˙Ł’‹˙˛Łť˙ÔÇÁ˙ëßÚ˙čÜÖ˙čŰÖ˙íŕÜ˙ćÚÖ˙–Ś‚˙F@,˙ ˙˙#˙( ˙*! ˙,# ˙/$˙2&˙4'˙6*˙9*˙;-˙=.˙?0˙B2˙D3 ˙F5"˙I6$˙K8&˙M9'˙O;(˙Q:)˙eSE˙kZN˙l\O˙n]P˙o^R˙xg[˙r_R˙vdU˙zfW˙q\F˙r]F˙vaJ˙waJ˙u_I˙v_J˙waK˙xbL˙{cM˙t^H˙r]G˙s_H˙t`J˙uaK˙zgP˙{hQ˙yfP˙zhQ˙{jR˙|jT˙~mU˙~nV˙oW˙pW˙€pX˙pW˙€qY˙qX˙{nT˙ylS˙xlR˙wjP˙ocH˙VK4˙TI0˙RG/˙OE,˙LC)˙OE-˙LC*˙E<"˙B: ˙@7˙=4˙;3˙70˙0* ˙& ˙E>$˙wpZ˙ݦ˙µ¬ť˙©ˇ‘˙¦žŤ˙ĆŔ¸˙¬Ą ˙xni˙[OJ˙aWR˙cWR˙bXT˙h`X˙€|m˙LJAŹ-9vpbŔŤv˙zrţ“‚|˙›Š‚˙›‰˙±˘ś˙ÚÍČ˙íŕŰ˙éÜŘ˙ęÝŘ˙őčä˙´© ˙VQ?˙ ˙˙$˙' ˙*! ˙," ˙/$˙2&˙3(˙6)˙9+˙;-˙=.˙@0˙A1˙D4!˙G5"˙H7$˙K8%˙M:(˙P;*˙R=,˙S>-˙V@/˙WA/˙l\O˙scW˙tdY˙veZ˙wf[˙qf˙xh[˙m_˙pa˙xdM˙yeN˙|iR˙}iR˙{gP˙|gQ˙}iR˙~iS˙zfO˙wcM˙xdN˙yfP˙{hQ˙}jS˙‚pX˙qZ˙pX˙‚qZ˙„t[˙†v]˙x_˙‰za˙‰za˙Š|c˙‹}c˙‹~c˙Ťe˙Ś~d˙{a˙‡z_˙†y^˙„x]˙{pV˙_S=˙\Q9˙ZO7˙XM5˙VK2˙YO6˙VL3˙NE+˙LB(˙I@%˙G>#˙E=!˙B:˙>6˙<4˙81˙3, ˙.* ˙TO4˙‚ze˙ĄśŠ˙»µ«˙ľą±˙ął®˙˛­Ş˙}tq˙_TO˙e[V˙cZU˙d\Vţvpd˙nk^Ć=D„|mßwn˙‰yq˙“‚{˙–…~˙§—’˙ÚÍČ˙íŕŰ˙ęÝŘ˙ëŢŮ˙đăß˙‘‡{˙)$˙˙!˙%˙) ˙+" ˙-$˙0%˙2&˙5(˙7*˙9,˙<.˙>0˙@1˙B3 ˙E5"˙H6$˙J8%˙L:'˙N;)˙P<+˙S>-˙U@/˙WB1˙YD3˙\E5˙]E5˙raV˙yj`˙zka˙|lb˙}nd˙yn˙~nb˙…uh˙Šyi˙{iQ˙}kR˙‚pV˙‚pW˙lT˙€nU˙nV˙~kS˙xfO˙{hQ˙{iQ˙|kS˙~mU˙€oW˙‡v]˙‡y^˙…v]˙‡x_˙Šza˙Ś|c˙Źf˙‚h˙’„h˙”†k˙•l˙•‡l˙—‹o˙–Šn˙“‡k˙’…i˙Ź…h˙Ź„g˙„y]˙dXA˙aV?˙_U<˙]S:˙[Q8˙`V<˙^S9˙UJ0˙QH-˙OF+˙NC(˙LC'˙JA$˙F= ˙B:˙@8˙=6˙A:˙=7˙0* ˙50˙‹…u˙żą˛˙˛­§˙µ°­˙©¤ˇ˙˘ťš˙xpk˙cYV˙g]Z˙d]X˙le]˙zugäH@„|mĺri˙xq˙x˙–…~˙Ěľą˙íáÜ˙ęŢŮ˙ęÝŮ˙đăŢ˙‡~q˙˙˙#˙& ˙( ˙+" ˙-$˙0&˙2'˙4(˙7*˙9,˙<.˙>0˙@1˙C3 ˙E5"˙G7$˙J9&˙L;(˙O;*˙Q<,˙S>-˙U@/˙WB1˙YD3˙[F5˙]G7˙`I9˙bJ9˙wi]˙qh˙rh˙€ri˙‚tk˙Źx˙Ś~t˙‚w˙“„y˙Žp˙€q˙‘s˙’„u˙“„u˙•…w˙–‡x˙“…v˙•†x˙–y˙‰{˙™‹|˙šŤ~˙śŽ˙ź‘‚˙ “„˙ˇ”†˙Ł•‡˙¤‰˙¦šŠ˙§śŤ˙©žŽ˙Şź˙¬ ’˙¬˘’˙­Ł“˙®¤”˙®¤•˙­Ł”˙¬˘“˙Şˇ‘˙© ˙˘™‰˙’‰|˙‡y˙Ť…v˙‹‚t˙€q˙‡~p˙„|m˙€xh˙}ue˙zrb˙wo_˙um\˙rjY˙ohV˙leS˙ibP˙f`M˙d^L˙a[H˙[WD˙YSA˙b^O˙b^P˙‰…}˙µ°®˙¤źť˙źš™˙ ś›˙”ŹŚ˙md_˙h_[˙f_Y˙icZ˙zvhęE0zseŐ}pg˙…tm˙Śyr˙©™”˙čÜÖ˙ęÝŘ˙ęÝŘ˙őçă˙ś’‡˙˙˙"˙%˙( ˙*" ˙-$˙/%˙2&˙4(˙7*˙9,˙;.˙>0˙@1˙B3 ˙E5"˙F7$˙I9&˙L:(˙M;)˙P=+˙R>-˙T@/˙VB1˙YD3˙[F5˙\G6˙_H9˙aK;˙bM=˙eM=˙{mc˙vn˙„wo˙…xo˙…yq˙{s˙‰|t˙Š}u˙‹~v˙Ť€x˙Žy˙Ź‚z˙{˙„|˙‘…}˙’†~˙“‡˙”‡€˙•‰˙–Š‚˙–Š˙—Ś„˙Ś…˙™Ť†˙šŹ‡˙šŹ˙›‰˙›‘Š˙ś’‹˙ť“Ś˙ž”Ť˙ž•Ź˙ź—Ź˙ —˙ ‘˙ˇ™’˙˘š“˙˘›”˙˘›”˙ ™“˙ž—˙›”Ť˙‹˙•މ˙“چ˙‘Š˙Ź€˙Ś…}˙‰‚|˙‡€y˙„}u˙{s˙yp˙}vn˙ztk˙xrh˙uoh˙rmc˙pja˙mh^˙jf[˙hcZ˙eaV˙b^S˙^[O˙[XK˙XUI˙‚~x˙ź›š˙›—”˙”’˙›—“˙xs˙h`[˙ha]˙jc]˙uqdŰ4 \WLź~qh˙‚pi˙‡uo˙µ°˙íáÜ˙ęÝŘ˙ěßÚ˙ÖĘĹ˙<6"˙˙ ˙$˙' ˙)! ˙+#˙.%˙1&˙3(˙5)˙8+˙:-˙,˙S?.˙TA0˙VB1˙YE4˙[F6˙]G7˙_J:˙aL<˙cN>˙eP@˙fP@˙~rh˙†{s˙‡|t˙‡|u˙}v˙‰~w˙Šx˙Šx˙‹€y˙Ś€z˙Śz˙Ť‚|˙Ž}˙Ź„~˙…˙‘…˙‘†€˙’‡˙’˙“‰˙”‰˙”Š„˙”‹…˙•‹†˙–ڇ˙–Ť˙—Ž˙—ʉ˙ŹŠ˙™Š˙‘‹˙š’Ś˙š“Ť˙›’Ť˙›”Ź˙›”Ź˙›•˙›”Ź˙›•˙›”Ź˙š“Ž˙’Ś˙–‹˙”މ˙“ڇ˙‘Š„˙ʉ‚˙Ť†€˙Š„}˙‚{˙†€y˙„~w˙‚{t˙zr˙}xp˙zum˙ysj˙vpi˙tof˙rmd˙oka˙li_˙jf]˙hdZ˙ebX˙c`V˙_]R˙\YM˙caV˙‘Ž‹˙—”‘˙”Ť˙”Ť˙Ź„˙lc_˙ia^˙oia˙[XO¦! H…zm˙{kdţ…sm˙ÔĆÁ˙ëßÚ˙éÜ×˙ňĺâ˙š‘…˙˙˙"˙% ˙( ˙*" ˙,#˙/%˙0&˙3(˙5*˙8,˙:-˙˙dO@˙gQB˙gQA˙€tk˙Š~y˙‰x˙‰€y˙Š€z˙‹z˙‹{˙Ś‚|˙Ť}˙Ž„~˙Ž…~˙Ź…˙ʆ€˙†€˙‘‡˙‘‚˙’˙’‰˙’Š„˙’Š…˙”‹†˙”چ˙•Ť‡˙•Ť˙–މ˙–މ˙–މ˙—ŹŠ˙‹˙‘Ś˙‘Ś˙‘Ś˙™’Ť˙™’Ť˙™“Ž˙š“Ž˙š“Ź˙™“Ź˙™“Ž˙’Ž˙—‘Ť˙—‘Ś˙–‹˙•ʉ˙“Ť˙‘‹†˙ŹŠ„˙Ž‚˙ڇ˙Š…˙}˙‡{˙…€y˙~w˙|u˙zs˙}xq˙{vo˙ytm˙wrk˙upi˙rog˙pld˙nkb˙li`˙jg^˙he[˙fcZ˙b`W˙]\Q˙~{v˙—”˙—‘Ś˙ś“˙š’Ž˙nfb˙hb^ţ|wl˙M ]WMĄyjb˙~le˙×ÉÄ˙ęÝŘ˙éÜ×˙ôćâ˙g_P˙˙˙#˙% ˙( ˙*" ˙,#˙/%˙1&˙3(˙6*˙8,˙9-˙=/˙?0˙@3 ˙D5"˙E6#˙G8%˙J:'˙L;)˙N=*˙P?-˙RA/˙TB1˙VC2˙XE4˙YF5˙\G8˙]J:˙`L<˙aM=˙dO?˙fQA˙gRC˙gRC˙rcW˙‰‚|˙‡€z˙{˙{˙‰|˙‰‚}˙Š‚}˙Š~˙Š~˙‹„˙Ś„€˙Ś…€˙Ś…€˙ކ˙Ť†˙އ‚˙އ˙Ź„˙Ź„˙Ź„˙‰„˙‰…˙Š…˙І˙І˙І˙‘‹‡˙‘‹‡˙’Ś˙’Ś˙“ډ˙’Ť‰˙’Ť‰˙’Ť‰˙‘Ť‰˙‘Ť‰˙‘Ť‰˙‘Ť˙‘Ś˙Ś˙‹‡˙ŹŠ†˙ŽŠ…˙Ť‰…˙Ś˙ڇ‚˙І˙‰„€˙~˙†‚}˙†{˙€z˙‚~y˙€|w˙{t˙}zt˙|xr˙zvp˙xun˙wsm˙url˙spj˙roh˙pmg˙nle˙mjc˙kha˙ig`˙hf^˙fd\˙ZUJ˙˘›—˙ ”˙˘›–˙ ™”˙nea˙le`˙^ZP­)cZPărb[ţË˝·˙ęŢŮ˙čÜ×˙óćâ˙UN=˙˙˙#˙% ˙' ˙*" ˙,$˙.%˙1&˙3(˙5*˙7+˙:.˙0˙@2˙B4!˙D5"˙G8%˙I:'˙K;)˙M<*˙O>,˙P?-˙SB0˙UC1˙WE4˙XF5˙[G7˙]I9˙^K;˙`M=˙bN>˙dP@˙fRB˙hSD˙bN@˙N>3˙PGA˙b[W˙c^Y˙e^Z˙e^Z˙f_Z˙f_[˙f`[˙g`]˙g`\˙h`]˙ha\˙ha]˙ib^˙hb^˙gb_˙hc_˙jc_˙je_˙je`˙ke`˙kfa˙kfa˙kfa˙kfb˙lgb˙lgc˙lgc˙lgc˙lhc˙lgc˙lfc˙lfe˙lfc˙lfe˙mge˙lfc˙lfc˙kgc˙kgc˙kfb˙jfb˙hea˙ic`˙hc_˙gb^˙gb^˙e`]˙c`\˙c_Z˙a]Y˙`\X˙_\W˙^[V˙]YU˙]XT˙ZWR˙YVQ˙XUP˙WTO˙URM˙TRL˙SPK˙QOI˙PMH˙OLF˙NLE˙LJD˙MJD˙53)˙˙>9'˙«Łˇ˙¨ ś˙«Łź˙ź”˙f`\˙b^Vč,5\OJ˙˘“Ť˙íŕŰ˙čŰÖ˙ďâŢ˙ogW˙˙ ˙"˙$˙' ˙)! ˙+" ˙-%˙1&˙2(˙4)˙7+˙9-˙:.˙=0˙?1˙A3 ˙D5"˙E7$˙H9&˙J;(˙L<*˙N>,˙P@.˙RB0˙TC1˙VE3˙XF5˙ZG7˙[I9˙^J:˙_L<˙aN>˙cP@˙dQA˙fRC˙gSD˙^L>˙J>5˙Š˙٤Ą˙¤¤¤˙٤¤˙ŁŁ¤˙ŁŁŁ˙ŁŁŁ˙ŁŁŁ˙ŁŁŁ˙˘ŁŁ˙˘˘Ł˙˘˘˘˙ ˘˘˙ ˘˘˙ ˘˘˙ ˘˘˙  ˇ˙  ˇ˙źźˇ˙ź ˇ˙ź ˇ˙źźˇ˙źźź˙źźź˙žžź˙žžź˙žžź˙žžź˙žžź˙ťžž˙ťžž˙ťťť˙ťťť˙ťťť˙ťťť˙ťťť˙śťť˙śśť˙śśś˙śśś˙ťťť˙ťťž˙›ťť˙›ťť˙››ť˙››ť˙›śť˙›ťť˙›ťť˙›ťť˙śśť˙śśś˙śśť˙śśś˙śśś˙śśś˙śśś˙›śś˙›śś˙››ś˙››ś˙››ś˙››ś˙›››˙›››˙››ś˙››ś˙š›ś˙…„˙(%˙˙˙QK;˙˛Ş¦˙®¦Ł˙ł«§˙Š˙XSO˙99^PJ˙ëŢŮ˙čŰÖ˙čŰÖ˙˛¦ž˙ ˙˙ ˙$˙& ˙( ˙*" ˙-$˙/%˙1&˙3(˙5*˙8,˙9.˙;/˙>0˙@2˙B4!˙D6#˙J<*˙PC0˙RD2˙TD4˙UF6˙XH8˙YI9˙\L;˙]M;˙_O>˙aO?˙cPA˙dRC˙fSD˙gUF˙hVG˙jXI˙lYJ˙mZL˙gTE˙•’˙źźź˙žžž˙ťťť˙ťťť˙žžž˙žžž˙ťťť˙ťťť˙ťťť˙śśś˙śśś˙ťťť˙ťťť˙śśś˙śśś˙›››˙›››˙śśś˙śśś˙›››˙›››˙›››˙ššš˙ššš˙›››˙›››˙ššš˙ššš˙™™™˙™™™˙ššš˙ššš˙ššš˙™™™˙™™™˙˙˙™™™˙™™™˙˙˙———˙———˙˙˙———˙———˙———˙–––˙–––˙———˙———˙–––˙–––˙•••˙•••˙–––˙–––˙•••˙•••˙•••˙”””˙”””˙•••˙•••˙”””˙”””˙“““˙”””˙”””˙˙$˙˙„}t˙´¬¨˙µ­©˙Ľ´°˙ZTQ˙D2—Š„˙ëŢŘ˙çÚŐ˙ňäŕ˙!˙˙ ˙"˙$˙' ˙)! ˙+#˙.%˙/%˙1'˙4)˙6+˙8-˙9.˙0˙>1˙B2 ˙B4!˙M?-˙XK:˙YK<˙ZM<˙^P@˙aRB˙cUE˙fWF˙hYI˙k\K˙m]N˙o_O˙qaQ˙scS˙ueT˙wgW˙yiY˙{j[˙|l\˙{iX˙˘ŁĄ˙žžž˙źźź˙źźź˙źźź˙žžž˙žžž˙ťťť˙ťťť˙žžž˙žžž˙ťťť˙ťťť˙śśś˙śśś˙ťťť˙ťťť˙ťťť˙śśś˙śśś˙›››˙›››˙śśś˙śśś˙›››˙›››˙ššš˙ššš˙›››˙›››˙›››˙ššš˙ššš˙™™™˙™™™˙ššš˙ššš˙™™™˙™™™˙™™™˙˙™™™˙™™™˙™™™˙˙˙———˙———˙˙˙———˙———˙–––˙–––˙———˙———˙———˙–––˙–––˙•••˙•••˙–––˙–––˙•••˙•••˙•••˙”””˙•••˙•••˙•••˙śśž˙1,˙& ˙ ˙˙ż·´˙ą±®˙ż·ł˙~˙="Čşµ˙ćŮŐ˙ćŮŐ˙¤›˙˙˙ ˙#˙% ˙( ˙( ˙*! ˙-#˙.$˙2)˙7,˙;/˙>3˙A6!˙F9%˙H<'˙L?+˙OB-˙SE0˙bVA˙reS˙sgV˙viV˙xjX˙zmY˙yoZ˙{n\˙|p]˙~p_˙r_˙sa˙‚tb˙tc˙„ue˙…vf˙‡xh˙xi˙‰zj˙‰xe˙˘ŁĄ˙   ˙źźź˙źźź˙žžž˙žžž˙žžž˙žžž˙žžž˙žžž˙śśś˙śśś˙śśś˙śśś˙śśś˙śśś˙śśś˙›››˙›››˙›››˙›››˙›››˙›››˙ššš˙ššš˙ššš˙ššš˙ššš˙ššš˙ššš˙™™™˙™™™˙™™™˙™™™˙™™™˙™™™˙˙˙˙˙˙˙˙———˙˙˙˙˙˙———˙———˙———˙———˙———˙———˙———˙–––˙–––˙–––˙–––˙–––˙–––˙•••˙•••˙•••˙•••˙•••˙•••˙•••˙”””˙śśž˙3.˙'! ˙" ˙˙‚|r˙ż·´˙Âş¶˙˛Ş§˙,áÔĐ˙ĺ×Ň˙ęÝŮ˙]VE˙˙"˙& ˙*#˙.'˙3+˙7/˙:3˙?5 ˙A:$˙D;$˙G;&˙H=&˙J?(˙L@*˙NA,˙PC.˙RE0˙TG2˙VH1˙h\G˙yp^˙zp^˙|q_˙}qa˙~sb˙€uc˙‚vd˙‚we˙„xg˙…yi˙‡zj˙{j˙‰|l˙Š}m˙‹~n˙Śo˙Ť€p˙Žr˙Žo˙˘ŁĄ˙źźź˙źźź˙źźź˙¤¤¤˙ŻŻŻ˙ŞŞŞ˙ŞŞŞ˙ŞŞŞ˙«««˙«««˙«««˙«««˙¬¬¬˙¬¬¬˙¬¬¬˙­­­˙­­­˙®®®˙®®®˙ŻŻŻ˙ŻŻŻ˙ŻŻŻ˙°°°˙°°°˙°°°˙°°°˙±±±˙±±±˙±±±˙±±±˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙˛˛˛˙°°°˙°°°˙°°°˙°°°˙ŻŻŻ˙®®®˙®®®˙­­­˙­­­˙¬¬¬˙«««˙«««˙ŞŞŞ˙ŞŞŞ˙©©©˙©©©˙¨¨¨˙¨¨¨˙§§§˙§§§˙¦¦¦˙¦¦¦˙¦¦¦˙¤¤¤˙¤¤¤˙¤¤¤˙§§§˙•••˙–––˙–––˙ťžź˙2.˙'" ˙# ˙˙LG7˙ÉŔ˝˙ĆĽş˙ĘÁľ˙äŘÓ˙âÖŃ˙ëŢŰ˙D>,˙&! ˙,&˙0*˙3,˙4.˙7/˙:2˙<4˙?6 ˙@7!˙B9#˙E;$˙G<&˙J>(˙K@*˙MA,˙PD.˙QE/˙TF1˙UH0˙k`L˙‚xg˙‚wg˙yh˙„zi˙†{k˙‡|k˙}m˙‰~n˙Š€o˙Śq˙Śq˙Ť‚s˙Žs˙„t˙‘…u˙’†v˙“‡x˙”y˙”†v˙ˇŁĄ˙ˇˇˇ˙ˇˇˇ˙   ˙¤¤¤˙ÓÓÓ˙ĺĺĺ˙äää˙äää˙äää˙äää˙ĺĺĺ˙ĺĺĺ˙ććć˙ććć˙ććć˙ććć˙ççç˙ççç˙ééé˙ééé˙ééé˙ééé˙ééé˙ëëë˙ęęę˙ëëë˙ëëë˙ëëë˙ííí˙ííí˙ííí˙ííí˙ííí˙îîî˙îîî˙îîî˙ííí˙ííí˙ííí˙ííí˙ííí˙ëëë˙ëëë˙ëëë˙ęęę˙ęęę˙ëëë˙ééé˙ééé˙ééé˙ééé˙ççç˙ççç˙ççç˙ććć˙ććć˙ććć˙ĺĺĺ˙ĺĺĺ˙äää˙ĺĺĺ˙äää˙äää˙äää˙ŕŕŕ˙¸¸¸˙•••˙–––˙–––˙ťťź˙2-˙'! ˙# ˙˙83˙ŃÇĹ˙ĘÁľ˙ĐĆĂ˙âŐŃ˙áŐĐ˙éÝŮ˙UN<˙#˙,'˙0*˙2,˙4.˙70˙91˙<3˙>6˙@7!˙B9"˙E;$˙F<&˙I>'˙K@*˙MB+˙OC-˙QE/˙SF0˙SH0˙ocP˙‰€q˙€p˙Šq˙‹r˙Śt˙Ť„t˙Ź…u˙Ź…v˙‘‡w˙‘‡x˙“‰z˙”‰z˙•‹{˙–‹{˙–Ś|˙—Ť}˙™Ť~˙™Ž˙šŽ}˙ˇŁ¤˙ˇˇˇ˙   ˙   ˙¤¤¤˙ĘĘÉ˙ňňň˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ďďď˙ĐĐĐ˙´µ´˙•••˙–––˙———˙žźˇ˙0,˙& ˙!˙˙FA/˙ÔĘČ˙ĚÂż˙ÍĂŔ˙ßÓÍÉßÓĎţäŘÔ˙†|n˙˙+%˙.(˙2+˙4-˙60˙91˙;3˙=5˙?6˙B8!˙C:$˙F;%˙G='˙J@)˙KA*˙NB,˙OD-˙RF/˙RE/˙qhT˙‘‰z˙z˙‘‰{˙’Š|˙”Š}˙”Ś~˙•Ś~˙–Ť~˙Ž€˙Ź˙™˙š‘‚˙›’˙ś“…˙ť“…˙ž”†˙ž”‡˙ź•˙ •†˙˘˘¤˙ˇˇˇ˙˘˘˘˙˘˘˘˙ĄĄĄ˙ľľľ˙ääă˙îîě˙ěěě˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííë˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ěíí˙ěěí˙ěěí˙ěěí˙ěěí˙ěěí˙ěěí˙ěěí˙ěěí˙íěí˙íěí˙íěí˙íěí˙íěí˙íěí˙íěí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ííě˙ííě˙ěěë˙»»ş˙´´´˙–––˙˙———˙źźˇ˙0*˙$ ˙ ˙˙sl_˙ŇÉĆ˙ËÁľţÍÂľÔ×ĘĆjáŐŃ˙ŢŇÎ˙§ž™˙C;$˙$˙,'˙1*˙2,˙6/˙70˙;3˙<4˙?6˙@7 ˙C8#˙D;%˙F=&˙I>'˙K@(˙MB*˙NC,˙QE.˙QE.˙ukY˙‘„˙—˙„˙™’„˙š“…˙›“†˙ś”†˙ť•‡˙ž–‡˙ź–‰˙ź—‰˙ ‹˙ˇ‹˙˘™Ś˙˘šŤ˙Ł›Ž˙¤śŽ˙ĄśŽ˙ĄťŽ˙˘ŁĄ˙˘˘˘˙˘˘˘˙ˇˇˇ˙¦¦¦˙ÁÁÁ˙ľ˝Ľ˙ĽĽ¸˙Ż®©˙­¬§˙­¬§˙­¬§˙­­§˙®­§˙®­§˙®­§˙®­§˙Ż®§˙Ż®¨˙ŻŻ¨˙ŻŻ¨˙±Ż©˙±Ż©˙±Ż©˙±°©˙±°©˙˛±©˙˛±©˙˛±©˙ł˛«˙ł˛Ş˙ł˛«˙ł˛«˙ł˛«˙łł«˙łł«˙łł«˙´ł«˙µ´«˙µ´«˙µ´«˙µ´«˙µł«˙µ´«˙µ´«˙µµ«˙¶µ«˙¶µ«˙¶µ«˙¶µ¬˙¶µ¬˙·µ¬˙¶µ¬˙·µ¬˙·¶¬˙·¶¬˙·¶¬˙·¶¬˙·¶¬˙¸¶«˙·µŞ˙·µŞ˙¸µ«˙ż˝µ˙˝˝¸˙˝˝˝˙µµµ˙———˙———˙———˙ź ˘˙0*˙ ˙˙;5˙“Ť˙ĚÂż˙ÎĂŔ˙Č˝ąuÜŃĚřÜĐÍţâ×Ó˙SK?˙1*˙(# ˙-(˙2+˙4.˙60˙91˙;3˙<5˙?6 ˙A7!˙C:$˙F<%˙G=&˙I?'˙LA)˙MB+˙OD-˙OD-˙wo]˙ź™Ť˙ź‹˙ ™Ś˙ ™Ť˙ˇšŽ˙˘›Ž˙ŁśŹ˙Łť˙¤ť˙Ąž‘˙¦ź‘˙¦ź’˙¦ “˙¨ “˙¨ˇ”˙©˘•˙Ş˘•˙Ş˘—˙­Ł–˙˘˘¤˙˘˘˘˙ŁŁŁ˙ŁŁŁ˙§§§˙ÁÁÁ˙„‚€˙IG;˙usl˙€x˙„|˙…„|˙†„|˙…{˙…{˙„‚z˙„‚z˙‡…{˙‚€w˙‚€w˙u˙€~t˙}s˙~}s˙‰r˙}{p˙}zo˙|zo˙{ym˙|p˙zwk˙ywk˙yvi˙xvi˙wth˙wug˙wtf˙wse˙vsf˙usf˙vse˙{yh˙use˙vse˙vse˙vsd˙vse˙vtd˙vtd˙wse˙wuf˙xvg˙zxj˙€n˙|n˙‚~p˙„t˙†v˙†x˙Šz˙ŚŠ|˙ŤŠ~˙ŤŚ~˙…‚r˙zxm˙˝˝Ľ˙¶¶¶˙———˙™™™˙™™™˙  ˘˙4/˙#˙,'˙B=1˙ŇÇĹ˙ÍÁľţĚÁľýÖČÄSÜŃĚ˙ŰĐĚ˙¦ź›˙WM<˙)$ ˙)$ ˙/)˙2,˙4/˙70˙91˙;4˙<6˙@7˙A8"˙D;$˙F<$˙G>&˙J?'˙KB)˙MC+˙MB+˙{sa˙§Ł—˙¦ •˙§ˇ•˙§˘–˙¨Ł—˙©Ł—˙©¤˙ŞĄ™˙«Ąš˙«¦š˙¬¦š˙­§›˙®¦›˙®¨ś˙®¨ť˙ݍť˙Ż©ž˙°Şž˙ł«ž˙ŁŁ¤˙¤¤¤˙ŁŁŁ˙ŁŁŁ˙§§§˙ÁÁÂ˙€€z˙NJ:˙°Ż¨˙żľ¶˙Ă»˙ÄÂĽ˙ÄĂĽ˙ÄĂ»˙ĂĂĽ˙ÄĂĽ˙ĂĂĽ˙ËÉľ˙ÂÁą˙ĂÂą˙ĂÂą˙ÂÁ¸˙ÂÁ·˙ÁŔ·˙Ň˱˙ŔŔ¶˙Áżµ˙Ŕżµ˙Ŕż´˙ÉǸ˙żľł˙Áľ´˙żľ˛˙żľ˛˙ż˝±˙ż˝±˙ľ˝±˙ż˝±˙ż˝±˙żľ±˙żľ±˙ÉǶ˙ż˝°˙Áľ˛˙Áľ±˙Áľ±˙Áľ±˙Áľ±˙Áľ±˙ÁÁ±˙ĂÁ˛˙ĂŔ˛˙Ă´˙ÎËş˙ĆĶ˙ČƸ˙ĘÇą˙ËĘş˙ÍË˝˙ÍĚľ˙ĐÍľ˙ÎÍŔ˙ŇĐÂ˙«¦Ź˙‚€r˙˝˝»˙µµµ˙˙™™™˙———˙ ˇŁ˙/+˙&! ˙IB1˙“Ž‹˙ÎÂż˙ÍĂż˙Ç»·_ÔÇÄźŰĎĚ˙ßÔŃ˙rlj˙`VD˙.(˙(# ˙.(˙2,˙4.˙60˙92˙<4˙=5˙?7 ˙B8!˙C:#˙F=%˙G>&˙I@'˙LB*˙K@(˙|td˙¬§ť˙ŞĄś˙«¦ś˙«§ť˙¬§ť˙­¨ť˙­¨ť˙®©ź˙®©ž˙®Ş ˙°Ş ˙°«ˇ˙°«ˇ˙±«ˇ˙±«ˇ˙˛­˘˙˛­˘˙˛¬Ł˙´®Ł˙٤Ą˙ŁŁŁ˙ŁŁŁ˙ŁŁŁ˙¨¨¨˙ÁÁÂ˙€z˙@=)˙ĄŁš˙ĚĚĆ˙ŇĐË˙ŇŃĚ˙ŇŃĚ˙ŇŃĚ˙ŇŃĚ˙ÓŃË˙ŇŇË˙ŘÖÍ˙ŃŃË˙ŇŃË˙ŇŃË˙ŇŃË˙ÓŃË˙ŃŃË˙ßŘż˙ŃŃË˙ŇŃĘ˙ÓŃĘ˙ŃŃĘ˙ÚŘĚ˙ŃŃĘ˙ÓŇĘ˙ÓŇĘ˙ÓŇĘ˙ÓŇĘ˙ÓŇĘ˙ÓŇĘ˙ÔÓĘ˙ÔÓĘ˙ÔŇĘ˙ÓŃČ˙ŰŮË˙ÔŇÉ˙ŐÓÉ˙ÔÓÉ˙ÖÓÉ˙ÖÔÉ˙ÖŐÉ˙ÖŐĘ˙ŐÔĘ˙ŐŐĘ˙ÖŐË˙ÖÔĚ˙ŢÜÍ˙ÖŐË˙××Í˙Ř×Í˙ŘŘÍ˙ŮŘÍ˙ŮŘÎ˙ŰÚÎ˙ŰŮĎ˙ŃĐĂ˙“w˙‚€q˙˝˝»˙µµµ˙˙ššš˙ššš˙˘˘¤˙4/˙SI8˙]ZW˙ÔĘĆ˙ÎĂľ˙Ç»¸«ÔČĂĽŮÎĘ˙ÜŇÎ˙e`]˙cYI˙A9!˙#˙.(˙2,˙5/˙71˙:2˙<3˙=6˙?7 ˙B9!˙D;"˙D=%˙G>%˙I?'˙D;#˙hcT˙ډ˙‹‡€˙Љ€˙‹‰˙‹˙‹˙ډ˙ډ‚˙ŤŠ‚˙ŤŠ‚˙ŤŠ‚˙ŤŠ˙ŽŠ˙Ž‹˙Ž‹˙Ź‹˙Ź‹˙Ź‹„˙ŤŠ‚˙¦¦§˙ĄĄĄ˙ĄĄĄ˙¤¤¤˙¨¨¨˙ÁÁÂ˙€€z˙JG4˙d`H˙YT6˙]Y;˙_[=˙a]=˙d_@˙faB˙hbC˙idD˙~zY˙kgE˙ojI˙pkJ˙rmK˙tnL˙rnM˙ž”g˙vpN˙ytQ˙{uR˙{vR˙“Ťh˙|wQ˙€zU˙‚{U˙‚|V˙}W˙„}W˙„~X˙†X˙†X˙Z˙†X˙ ™r˙‚Z˙Š„[˙Š„[˙‹„[˙‹„[˙‹…Z˙‹…[˙‹…Z˙‹„Y˙‹…Z˙‰‚X˙ ™n˙‡T˙‹„W˙Š„V˙ŠU˙ŠU˙ŠT˙‰‚S˙R˙•Žc˙˘ť€˙„s˙˝˝»˙µµµ˙™™™˙ššš˙ššš˙žžź˙VO?˙NJH˙ÓËÇ˙ÎĂż˙Č˝¸ĹŃĹÁ¬ÖËÇ˙ÚĐÍţrmk˙[RF˙`X?˙#˙+&˙1+˙4.˙60˙81˙;3˙=5˙?7˙@8 ˙C:"˙E=$˙F=%˙90˙¤ˇť˙ި¤˙¬Ş¦˙¬Ş¦˙¬Ş¦˙¬Ş¦˙¬Ş§˙¬©¦˙¬Ş¦˙¬Ş¦˙¬Ş¦˙¬Ş§˙¬«§˙¬«§˙¬«§˙­«§˙­«§˙­«§˙­«§˙Ż­¨˙ĄĄĄ˙ĄĄĄ˙¤¤¤˙¤¤¤˙©©©˙ÁÁÂ˙€€z˙><+˙‹‡d˙ڇb˙‡‚]˙‰…_˙‹†_˙‹‡`˙Ťa˙ʉb˙Šc˙ˇ›s˙‘Ťc˙•Źh˙—‘i˙“j˙š”k˙™”l˙Ľ±~˙ť—n˙ˇ›q˙˘ťr˙Łťs˙µŻ„˙Ąźt˙¨Łv˙©Łx˙«Ąy˙«¦y˙­§z˙­§{˙­¨{˙ݍ{˙´®˙wqK˙’j˙}wO˙€zQ˙zP˙€{R˙zQ˙€{P˙€{P˙€{Q˙{P˙|P˙|O˙»´‹˙«¤z˙{M˙€zL˙€yK˙€yJ˙€yK˙xI˙wG˙Ś…Z˙™•y˙‚€r˙˝˝»˙µµ¶˙™™™˙ššš˙›››˙ź  ˙fb`˙ÔĘÇ˙ÎĂľ˙ČĽ··ÍÁ˝uŇČÄ˙ŮĐĚţ–˙OG@˙wmX˙H@'˙ ˙.(˙2,˙5/˙71˙:3˙<4˙>6˙@8˙B9!˙D;#˙4,˙ôőř˙îîî˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ňňň˙ńńń˙ńńń˙ńńń˙řřř˙źźź˙¦¦¦˙¦¦¦˙¦¦¦˙ŞŞŞ˙ÁÁÂ˙€€{˙>:)˙®Ş~˙şµ‡˙¶±˙˛­˙ł­˙˛­€˙ł®€˙´Ż˙µŻ‚˙ŔşŚ˙¶°‚˙ş´„˙»¶‡˙ľ¸‰˙Ŕş‹˙Ŕ»‹˙ŘÍ”˙ĹŔ˙ĘÄ“˙ĚĆ•˙ÎČ•˙Úҡ˙ÓÍš˙ÖĐť˙ŘŇź˙ÚÓ ˙ÜÖ˘˙Ýף˙Ýף˙ÝŘŁ˙ŢŘŁ˙ńě˛˙piC˙–i˙ztL˙}wO˙}xO˙~wN˙xO˙~xN˙yN˙yN˙yN˙xM˙‘‰_˙ÇŔ˙±¬‚˙™”i˙~wJ˙~xJ˙xJ˙~wI˙~vH˙}tG˙‹„Y˙™•y˙‚€r˙˝˝»˙¶¶µ˙ššš˙śśś˙›››˙—™˙ÍÄŔţĚÁ˝˙Äą´€Ę˝¸,ÎĂżéÔĘÇ˙ÁĽą˙c\Y˙g^S˙xnW˙@8 ˙!˙.)˙3-˙6/˙82˙:3˙<5˙?7˙@9˙3)˙ôô÷˙ďďď˙ôôô˙ôôô˙ôôô˙ôôô˙őőő˙ôôô˙ôôô˙ôôô˙ôôô˙ôôô˙ôôô˙ôôô˙ôôô˙ôôô˙őőő˙őőő˙őőő˙ýýý˙   ˙¦¦¦˙¦¦¦˙ĄĄĄ˙«««˙ÁÁÂ˙€€{˙=9)˙¤ v˙¬¨|˙®Ş~˙ඉ˙ş·Š˙»¸‹˙˝ąŚ˙°«~˙°¬˙Ć“˙ľşŚ˙ÄÁ”˙Âľ˙żşŚ˙ĂľŹ˙Ć“˙ŰŇ›˙ČĂ“˙ĘÇ•˙ĐËš˙ŇĚś˙ŮÔŁ˙ÔĐž˙ŰÖ¤˙ŰŐŁ˙ßÚ§˙ßۨ˙Ţؤ˙ÜŐˇ˙ÜŐˇ˙ßآ˙ňíł˙le>˙”Ťf˙vpH˙ysK˙zsK˙{tK˙{uJ˙{uK˙|tJ˙|uJ˙|uI˙{uJ˙…S˙ŃËŁ˙Ź]˙¬Ą{˙yrE˙|uG˙{tF˙{tF˙zsE˙zrC˙†€T˙™”x˙‚€q˙˝˝»˙¶¶¶˙ššš˙›››˙›››˙™™ţÄąµíľ´Ż3ËŔĽĚÂľ˙ŐÍĘ˙ śš˙`YS˙yna˙}r\˙G@'˙ ˙-(˙3+˙60˙82˙:4˙=5˙.' ˙öřú˙ńńń˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙ööö˙÷÷÷˙řřř˙˙˙˙˙žžž˙¦¦¦˙§§§˙§§§˙«««˙ÁÁÂ˙€€{˙?:(˙š–o˙ˇťs˙¤źv˙˘ťt˙š”l˙ź›q˙źšq˙ťn˙¦ˇw˙«¦{˙“i˙ťm˙ˇ›o˙©¤w˙¨˘v˙­§z˙ĚŔ˙ł­˙ą˛˙Ľ´…˙ľ¸‡˙ÍÇ–˙ÄżŤ˙ĘÄ’˙ÍÇ”˙ĐĘ–˙ÓÍ™˙×Ńť˙ŮÓž˙ÚÔ ˙éă¨˙ëć°˙gb;˙’‹c˙rlD˙upG˙voG˙wpG˙vqG˙vpG˙xqF˙xqG˙xqF˙xrF˙pj>˙ŐΧ˙™“h˙¸°˙sm@˙xqD˙xqC˙woA˙tm?˙}uI˙•Žh˙•u˙q˙˝˝»˙¶¶¸˙›››˙ťťť˙ťťť˙›śś˙’•–Á°®ÇľşĄËÁľ˙ĐÉÇ˙š•“˙jb^˙€ui˙Žl˙]T;˙(# ˙'" ˙0+˙5.˙83˙*#˙÷řú˙ńńń˙ööö˙ööö˙ööö˙ööö˙ööö˙ôôô˙ööö˙÷÷÷˙ööö˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙ööö˙÷÷÷˙˙˙˙˙   ˙¨¨¨˙§§§˙§§§˙ŞŞŞ˙ÁÁÂ˙€z˙?:(˙•‘j˙š”n˙š”l˙˛­˙ަ}˙ žs˙¨¤z˙›—n˙ŹŠd˙ž—n˙Ź‹a˙•g˙™•i˙ź™m˙Łžq˙§˘u˙ÎĂ‹˙±­~˙¸ł„˙Ľ·‡˙Ŕą‰˙ÍÇ—˙ĆżŽ˙ÉÄ‘˙ÎČ•˙ŃË˙ÓÍ™˙×Ńť˙ŘŇť˙ÚÓž˙ęă©˙ěćŻ˙c]5˙Ť‡_˙mh@˙qkB˙qjB˙qkB˙qkB˙rlB˙rlA˙rlA˙rlB˙smA˙oj<˙¶±‡˙ľ·Ž˙şł‹˙nh:˙ph;˙yrF˙}S˙‹…]˙Y˙‘Śg˙”Źt˙‚q˙˝˝»˙¸¸¸˙›››˙ťťť˙śśś˙śśś˙   ÁµłÄ»·ˇČżĽ˙ĎÇĹ˙¨ˇźţ|tp˙€vn˙ž’˙€t]˙QI.˙!˙($ ˙!˙÷řů˙ńńń˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙őőő˙ööö˙÷÷÷˙řřř˙őőő˙íěë˙ëęé˙ęéč˙ëëę˙ôőő˙˙˙˙˙ˇˇˇ˙¨¨¨˙§§§˙§§§˙¬¬¬˙ÁÁÁ˙€z˙KF4˙ť™r˙©¤{˙ł®˙±¬‚˙´®„˙®Ş˙Ż©˙´°…˙łŻ„˙°¬˙ł®‚˙¶±…˙°«˙®©{˙˛­€˙µ°‚˙ŰŃ™˙ĂľŹ˙ÉÄ“˙ĚÇ–˙ÎÇ–˙ŐĎť˙ÓÎś˙ÓÍš˙ÖĐś˙ŮÓź˙ŰÔ ˙ß٤˙ŢŘŁ˙éă©˙ĺß©˙ńëł˙yT˙’j˙Š„\˙Ť‡_˙Ś_˙Ž`˙Ť_˙Ť_˙Ť_˙Ž^˙Ť^˙Ť]˙‹…[˙’g˙âܵ˙ĘĂś˙—‘i˙Ąźy˙¤žx˙ št˙›”n˙“Že˙˘›x˙§˘„˙„‚s˙˝Ľ»˙¸¸¸ţśśś˙žžž˙žžž˙ťťť˙ˇˇˇ˝Ż©ø´Äą¶ńĎÇÄ˙şµ˛ţ‘Ź˙†}x˙Ť‚˙¬ž‹˙†{b˙H@#˙óóö˙đđđ˙ööö˙őőő˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙óóó˙ęéč˙ćăă˙äŕŕ˙čää˙ĺáá˙ăÝŢ˙ŕŮÚ˙×ŃŇ˙Ý×Ř˙٤¤˙©©©˙©©©˙¨¨¨˙¬¬¬˙ÁÁÂ˙€z˙=9&˙š•n˙¦ˇw˙±¬˙Ż©~˙¬§|˙ł®‚˙˘śp˙¤źt˙Ąˇu˙°«~˙Łťp˙¦˘u˙§˘s˙¦ r˙ŞĄv˙¬§x˙ŘΕ˙ş¶†˙½Ś˙Ŕş‰˙ÇÁŽ˙ÓĎś˙ĚĆ“˙ĐĘ–˙ÓÍ™˙ÖĐś˙ŘŇť˙ÖŇś˙ŘŇť˙äŢĄ˙áŰĄ˙îč±˙^Y2˙ʉa˙b\4˙e^6˙e_6˙f`6˙f`6˙e`6˙f_5˙d^3˙b]0˙nh>˙xrJ˙źs˙ľ·’˙ČÁ›˙‡[˙„}W˙|xO˙|vO˙|wO˙jc9˙ic:˙“Žs˙~p˙˝Ľ»˙ąąąţťťť˙žžž˙žžž˙ťťť˙ˇˇˇÁµ±CŔł®®Č˝ą˙ĚĂŔ˙ą˛Żţ˘›˙™Ž‰˙˘•‰˙ëíî˙đđđ˙őőő˙őőő˙ööö˙ööö˙ööö˙őőő˙ööö˙ëęé˙îěě˙ňđđ˙îëě˙ëéé˙éćć˙çăä˙äŕŕ˙âÝÝ˙ßÚÚ˙áŰÜ˙¤¤¤˙©©©˙¨¨¨˙¨¨¨˙­­­˙ÁÁÁ˙€{˙>:(˙—‘k˙źšr˙™”k˙”j˙ťn˙˘ťs˙™“i˙‚Y˙‰Z˙ś—l˙ڇ\˙‹`˙’Ťa˙”Źb˙–‘e˙ˇťq˙͉˙Ą r˙ ›l˙˘ťm˙¤źp˙·±˙©¤s˙­§v˙ŻŞy˙ł­{˙µ°}˙¸˛˙ÂĽ‡˙ŘÓś˙ŢŘ ˙ěć®˙VP*˙…X˙`\3˙d^5˙c]4˙`[0˙fa6˙soE˙€zT˙Žc˙š•p˙™“o˙”Ťh˙Łžz˙˝·˙ăÜ·˙{wN˙‚|U˙pjA˙\V(˙KD˙KC˙`Z/˙•‘u˙~q˙˝Ľ»˙¸ąąţťťť˙žžž˙źźź˙źźź˙ŁŁŁ˝±«V»®Ş´Ĺş¶˙ĘÁż˙ż·´˙éęë˙đđđ˙őőő˙őőő˙őőő˙őőő˙őőő˙óóó˙îíí˙ůřů˙őôô˙óńń˙đîî˙îëë˙ęčč˙čĺĺ˙ćââ˙äßß˙áÜÜ˙ăÜÝ˙¤ĄĄ˙ŞŞŞ˙ŞŞŞ˙ŞŞŞ˙­­­˙ÁÁÁ˙€{˙?;(˙{Z˙‚Z˙€Z˙‡„^˙•‘j˙Śe˙Ť‰c˙‚}V˙plF˙\˙toH˙xsM˙{vO˙xQ˙€|R˙Ť‰_˙ĸ˙’Ťc˙›–j˙ťk˙ ›n˙˛­˙©¤k˙­¨s˙¬§u˙®¨y˙±«{˙µ°€˙Ŕş‡˙ÚÔž˙ÜÖś˙ëĺ«˙OI"˙‡[˙oiB˙|wQ˙‰„`˙“o˙žu˙ž—t˙™“p˙”Žk˙Źe˙]˙„Z˙ś–s˙ŐĎ©˙őîÉ˙–Źe˙D=˙IB˙JD˙LE˙KD˙_Y0˙”u˙€~q˙˝Ľ»˙¸¸¸ţžžž˙   ˙źźź˙źźź˙˘˘˘ş¬§CŻžëëë˙đđđ˙őőő˙őőő˙őőő˙ôôô˙ňňň˙ńďď˙űűű˙úůů˙÷öö˙őóó˙ňđđ˙ďíí˙íęę˙ęçç˙çää˙ĺáâ˙ăŢß˙ĺßß˙Ą¦¦˙ŞŞŞ˙ŞŞŞ˙©©©˙®®®˙ÁÁÁ˙€{˙@;)˙~yX˙{W˙}X˙€zW˙„_˙Śa˙Ťf˙Ťf˙‡‚\˙”Źh˙wsL˙snH˙vqJ˙ytL˙}xO˙Š…]˙¶˙‘Žc˙™”g˙”c˙±­_˙ŃÍj˙×Ôb˙·ła˙ťh˙˘śl˙¨ˇs˙­¦v˙»µ‚˙ŮÓž˙ß٤˙ďčł˙}xT˙ŞĄ˙‹h˙’Śj˙‘Ťh˙‹h˙Še˙چc˙چb˙Ťd˙~yS˙lg?˙VP&˙a[/˙ňëĹ˙—‘g˙÷ďĘ˙F?˙IC˙JD˙KD˙JC˙^X0˙“Žs˙€}p˙˝Ľ»˙¸¸¸ţźźź˙źźź˙źźź˙źźź˙ĄĄĄëęę˙đđđ˙őőő˙őőő˙őöö˙ôôô˙ěęé˙÷÷÷˙ůřř˙űűű˙ůřř˙öőő˙óňó˙ńďđ˙ďěě˙ěéé˙éćć˙ćăă˙äŕŕ˙çáâ˙Ą¦¦˙ŞŞŞ˙«««˙«««˙®®®˙ÁÁÁ˙€€{˙?:)˙yuU˙yuR˙{vR˙†‚]˙‡‚]˙ŽŠd˙Ť‰c˙ŤŠc˙‹d˙’Ťf˙kf@˙pkE˙snI˙wrK˙{vN˙Š…]˙ĸ˙”Źe˙ź›p˙Ąźo˙ŮŐ`˙âŕo˙Ű×i˙ĚÇm˙§˘w˙¬¦y˙ŻŞ{˙˛¬~˙ż¸‡˙ŘŇź˙ßŘĄ˙îéł˙yuQ˙¨Ł€˙ŹŠh˙“Žl˙’Ťj˙~Z˙smH˙b\5˙QK#˙A;˙@:˙D>˙B<˙le;˙˙üŘ˙61˙éă˝˙˘śs˙C=˙IC˙IC˙JB˙\W.˙’Žr˙€}p˙˝Ľ»˙ąąąţźźź˙ˇˇˇ˙   ˙   ˙ĄĄĄëëë˙đđđ˙őőő˙őőő˙őöö˙éçć˙őóó˙öôô˙ř÷÷˙ůůů˙úűű˙řřř˙öőô˙óńń˙đîî˙îëë˙ëčč˙éĺĺ˙ćâă˙éää˙¦¦¦˙¬¬¬˙«««˙«««˙ŻŻŻ˙ÁÁÁ˙€€{˙@:)˙wtT˙wqN˙wrO˙zU˙‡]˙…[˙‚~Y˙zuQ˙{vQ˙‹e˙e`;˙kf@˙pkD˙smH˙wrJ˙yvN˙Ŕ˛{˙‡[˙•e˙–‘f˙łŻ`˙ŮŐn˙ŕÝg˙ÂŔo˙­¨{˙˛¬€˙şµ˙żą‹˙ËĹ•˙ÝÖ§˙ß٦˙đéł˙a[7˙†€\˙TN(˙GB˙:6 ˙<6 ˙@:˙B<˙C<˙C>˙D>˙D?˙A;˙’Šc˙ŮҬ˙71˙ś•m˙ŕŮ´˙TN"˙GA˙HB˙IA˙[U/˙‘Ťs˙}p˙ĽĽ»˙ąąąţźźź˙ˇˇˇ˙   ˙   ˙¦¦¦ëëë˙ďďď˙őőő˙ôôô˙đďď˙íęę˙ňđđ˙őóó˙öőő˙ř÷÷˙úúú˙úůů˙÷ö÷˙ôóó˙ňđń˙đíî˙íęë˙ęçč˙çää˙ëĺć˙§§§˙«««˙«««˙«««˙ŻŻŻ˙ÁÁÁ˙€€{˙@;*˙€|]˙‹†c˙ŽŠh˙‘Śi˙˘ťw˙˛®†˙®©˙ˇśv˙¬¨˙łŻ˙­©˙ˇžv˙«§~˙¦˘z˙®Ş˙ş¶Ś˙ŢÔž˙©¤|˙¨¤z˙ş¶Š˙˛­‚˙Ć—˙¸ł}˙­©r˙¬¦v˙»·˙«¦v˙źši˙¨Łn˙Äľ…˙ĚĆŚ˙çá¤˙)%˙fa;˙:5 ˙?:˙@;˙A;˙A<˙A<˙B=˙C=˙C>˙D>˙?9˙¨˘y˙§ y˙?9˙UO$˙×Đ©˙¬¦~˙?9 ˙GA˙GA˙ZU.˙‘Śq˙~|p˙ĽĽ»˙ąąąţ   ˙˘˘˘˙˘˘˘˙˘˘˘˙¦¦¦ëëë˙ďďď˙ôôô˙ööö˙éçĺ˙đěě˙ńďď˙óńń˙őôô˙öőő˙řřř˙úűű˙ůřř˙őőő˙ěëě˙ćää˙ăáá˙ĺââ˙čĺć˙ěçé˙§§§˙­­­˙­­­˙¬¬¬˙ŻŻ°˙ÁÁÁ˙€€{˙@<)˙rnP˙kfE˙kgD˙}yV˙yuQ˙tpL˙ysO˙vqN˙}zT˙Žc˙xuO˙okF˙_[5˙pkD˙ztM˙zvN˙Č˝†˙zwN˙ni?˙ni=˙qm?˙ʉ\˙ytF˙|M˙…€Q˙S˙ŤW˙’Ť[˙Ą k˙Ă˝„˙ĚĆŚ˙čâĄ˙*&˙gb<˙95˙?9˙?:˙@:˙@;˙A;˙A;˙B<˙B<˙C=˙:4 ˙Ŕş’˙xqI˙C=˙=7 ˙ݧ€˙Áş“˙ga7˙E?˙F?˙YT.˙‹q˙~|p˙ĽĽ»˙ąąąţˇˇˇ˙˘˘˘˙˘˘˘˙ˇˇˇ˙¦¦¦ëëë˙ďďď˙ôôô˙ööö˙äßŢ˙îęę˙đíí˙ňďď˙óňň˙öôô˙÷÷÷˙ůůů˙ööö˙ëëë˙óóó˙÷÷÷˙ůůů˙óňó˙áÝß˙ęăč˙§¨¨˙­­­˙¬¬¬˙¬¬¬˙°°°˙ÁÁÁ˙€€{˙?<)˙smP˙lgF˙lgF˙}yU˙…`˙snK˙‰†`˙…[˙~zU˙ŹŠe˙~zT˙{wQ˙miC˙vsK˙†Y˙|yP˙Ęż‡˙}yO˙{vL˙upE˙upD˙’‹^˙{wJ˙‚}O˙T˙‰„U˙ʉY˙’Ť\˙Ąźk˙Ŕ»˙ÉÄŠ˙ćáĄ˙*%˙ga;˙:5˙>9˙?9˙?:˙@:˙>8˙ke>˙=8˙B<˙A;˙D?˙×Ń«˙LF˙C<˙C=˙lf<˙µ®‡˙¨ˇy˙@:˙D>˙WS-˙ŽŠp˙~|o˙ĽĽ»˙şşşţˇˇˇ˙˘˘˘˙ŁŁŁ˙ŁŁŁ˙¨¨¨ëëë˙ďďď˙ôôô˙ęęé˙ëćć˙íčč˙îęę˙ńîî˙óđđ˙ôóó˙öőő˙öőő˙ííí˙řřř˙őőő˙ôóô˙öőö˙űüű˙üüű˙ăäć˙©©©˙­­­˙®®®˙®®®˙°°°˙ÁÁÁ˙€€{˙@<(˙qmO˙kgF˙ieD˙“Źi˙Ťf˙•m˙š—p˙Ž‹d˙–m˙©¦}˙—“l˙›o˙”h˙Ť‰`˙Ź‹b˙‰†]˙ĘŔ˙Ś_˙źťq˙•’e˙”i˙Ż«}˙Łźq˙˘žo˙«§x˙¨¤t˙¬§w˙´°€˙·ł€˙ĚÇ˙ŃĚ”˙ĺŕ¤˙)%˙e`:˙94 ˙=8˙=8˙>9˙>9˙=7˙ztL˙UO)˙=7˙94 ˙‰[˙´­‡˙84 ˙B<˙B=˙=7 ˙¦ y˙˘›t˙rlC˙A;˙VR,˙Žp˙}{o˙ĽĽ»˙şşşţŁŁŁ˙¤¤¤˙ŁŁŁ˙ŁŁŁ˙§§§ëëë˙ďďď˙őőő˙čćć˙éĺĺ˙ëçç˙íčč˙ďëë˙ńíí˙óńń˙őóó˙ěěě˙ööö˙őőő˙óóó˙ńďď˙ôňó˙ööö˙úúú˙ůűű˙©¨¨˙®®®˙®®®˙­­­˙±±±˙ÁÁÁ˙€€z˙@;)˙qmO˙|wG˙mhD˙hdC˙rnL˙}yU˙xtQ˙€}X˙zvQ˙І`˙qnI˙vqL˙jeA˙okE˙tqJ˙pmF˙Ć»‚˙pmD˙ni?˙je;˙mh=˙Š^˙uoC˙{vJ˙„P˙T˙‡‚R˙‹…U˙Ąźm˙Ľ·€˙ÇÁ˙äޤ˙(#˙d^9˙72 ˙;6˙<7˙<7˙=8˙<7˙\V/˙Ť‡a˙toG˙‹…^˙ť–o˙‡Y˙<6 ˙@:˙A;˙?9˙nh@˙•Žg˙’‹d˙FA˙TO+˙چm˙}{o˙ĽĽ»˙şşşţ¤¤¤˙ŁŁŁ˙ŁŁŁ˙¤¤¤˙©©©ëëë˙ďďď˙őőő˙ćăă˙éăă˙éää˙ëçç˙íéé˙đěě˙ňďî˙ôńň˙éçç˙ůůů˙ňńń˙îëě˙őóó˙÷őő˙őôô˙÷÷÷˙˙˙˙˙¨¨¨˙®®®˙ŻŻŻ˙ŻŻŻ˙˛˛˛˙ÁÁÁ˙€€z˙LF4˙{wZ˙¬©[˙ަZ˙ť™n˙™“p˙źśv˙–’m˙›–p˙ˇťw˙™•n˙źśt˙›–o˙Łžw˙¨Łz˙¦˘x˙‰†_˙ÔČŹ˙”h˙ťn˙ť™n˙‘Śa˙Ą r˙ŹŠ]˙”Ža˙“d˙›–g˙źšj˙Łťm˙ł­z˙ĆŔ‰˙ĎÉ‘˙ëĺ©˙SO+˙toJ˙a\7˙d_9˙d_9˙e`9˙f`:˙fa:˙e`9˙›•o˙˘św˙¦ź{˙Łťv˙unG˙d^7˙f`9˙f`8˙e`8˙ia:˙¦źy˙źq˙چ_˙pkG˙ ›˙€}q˙ĽĽ»˙şşşţ¤¤¤˙ĄĄĄ˙ĄĄĄ˙¤¤¤˙©©©ęęę˙îîî˙őőő˙ĺâá˙çáá˙čăă˙ęĺć˙ëçč˙íéë˙îëí˙đíń˙äăç˙÷÷÷˙ňńń˙ďíí˙óđđ˙ôóó˙ńđđ˙÷÷÷˙˙˙˙˙©©©˙°°°˙ŻŻŻ˙ŻŻŻ˙˛˛˛˙ÁÁÁ˙€€z˙>9'˙roN˙žšO˙}yG˙zvS˙}zV˙„`˙{W˙„]˙wrQ˙’Źj˙}zT˙yvP˙€{U˙wrL˙„X˙a_9˙Ćş€˙ZW1˙mi@˙d_6˙hc:˙W˙pjA˙wsF˙{wI˙€{M˙„P˙‰T˙ť—d˙ł®w˙żş‚˙âܢ˙!˙`[6˙1+˙50 ˙61 ˙61 ˙71 ˙72 ˙61 ˙62 ˙ID˙KG˙4/˙c\6˙72 ˙:5 ˙:5 ˙;5 ˙94 ˙@;˙B<˙FA˙PL(˙‡‚k˙|zn˙ĽĽ»˙şşşţĄĄĄ˙ĄĄĄ˙¤¤¤˙¤¤¤˙ŞŞŞęęę˙îîî˙ôôô˙ĺâă˙äŢá˙ĺŢă˙ĺáĺ˙ćâč˙çăę˙çĺí˙čćď˙ŮÜé˙ôňň˙ńďď˙ôňň˙íéę˙ěéę˙óńň˙ööö˙˙˙˙˙Ş©©˙ŻŻŻ˙ŻŻŻ˙ŻŻŻ˙łłł˙ŔŔÁ˙€€{˙?;)˙nkN˙hcE˙hdC˙plK˙xuR˙‚[˙zvS˙{wT˙~zW˙‰…b˙ieC˙miF˙soJ˙І`˙‚}V˙|V˙Ęľ„˙jfA˙zQ˙hc;˙jf<˙‰„Y˙rmC˙yuI˙~yL˙‚}O˙†S˙‹…W˙žf˙˛¬w˙żş˙ăݢ˙'"˙b]9˙61 ˙:4˙:5˙;6˙;6˙;6˙<6˙<7˙=7˙=7˙:5˙e^8˙;5˙>9˙>9˙>9˙?9˙?9˙?9˙>8˙RM*˙‰„m˙|zn˙ĽĽ»˙şşşţĄĄĄ˙¦¦¦˙¦¦¦˙¦¦¦˙ŞŞŞęęę˙îîî˙ôôô˙ćĺć˙ŢŘŕ˙ŕÚă˙áÜĺ˙âŢč˙áŢę˙ßßí˙Űăď˙Öçě˙ăęë˙ôńń˙ňđđ˙ôóó˙ôőő˙ôóó˙ůřř˙őôô˙«««˙±±±˙±±±˙°°°˙łłł˙ÁÁŔ˙€{˙?;)˙nkN˙hdE˙eaC˙ډf˙Ž‹f˙•p˙„€^˙ŽŠf˙™–p˙Łźy˙‹‡b˙“i˙•’j˙›p˙€|V˙vsM˙Ї˙SO+˙`[4˙f`9˙id;˙‡W˙qlA˙xsH˙|xK˙|N˙…€R˙‰„U˙ťf˙ŻŞu˙ľ·€˙âܡ˙%!˙a[8˙50 ˙84˙94˙:4˙:5˙:5˙;5˙;6˙<6˙<6˙94 ˙c]7˙:4˙<8˙=8˙=8˙=8˙=8˙=8˙<7˙PL*˙l˙|zn˙ĽĽ»˙şşşţ¦¦¦˙¦¦¦˙¦¦¦˙ĄĄĄ˙ŞŞŞęęę˙îîî˙óóó˙đđđ˙×ŃÚ˙Ü×â˙ÜÖĺ˙Ů×č˙Ößé˙Öçë˙Úíě˙âîí˙ăŕŰ˙íęé˙óňň˙őóó˙öôô˙÷öö˙ňńń˙ňńń˙«««˙±±±˙°°°˙°°°˙´´´˙ŔŔŔ˙€{˙?:(˙nkO˙heE˙eaB˙jfG˙rnN˙spN˙yvT˙hdC˙a\>˙wrR˙hcB˙jdD˙lhE˙kgD˙snJ˙plI˙ŇÇ˙nkE˙id=˙miA˙rmD˙І[˙ytJ˙|P˙zN˙‡‚V˙…€R˙‡‚U˙ś—f˙¬§s˙»µ~˙áŰ ˙%˙`Z7˙4. ˙83˙83˙94˙94˙95˙:5˙:5˙:5˙:6˙83 ˙b\7˙83˙<7˙;7˙<7˙<7˙<7˙<7˙;6˙OK)˙‡‚k˙|yn˙ĽĽ»˙»»»ţĄĄĄ˙¦¦¦˙§§§˙§§§˙¬¬¬ęęę˙îîî˙óóó˙őőő˙ÖĐÝ˙ÔÓâ˙ĐÜä˙Ńăĺ˙Öćć˙Űčç˙âéč˙ëäß˙đëč˙ëéč˙çĺĺ˙ěëë˙îíí˙ěëë˙ňňň˙ţţţ˙«««˙˛˛˛˙˛˛˛˙˛˛˛˙´´´˙ŔŔŔ˙€{˙?:(˙okO˙ieF˙fbD˙‚]˙‰‡c˙†`˙xuS˙‚\˙‚~\˙Їb˙njH˙wrO˙‡^˙okG˙{U˙zwR˙ÖÇŤ˙~zU˙xrJ˙vrI˙yuL˙Š…\˙qmC˙ytI˙}xM˙…€S˙„R˙†‚T˙š•d˙ŞĄp˙ş´}˙ŕÚź˙$˙_Y5˙3. ˙72˙73˙83˙83˙84˙84˙94˙94˙:5˙72 ˙`[6˙72 ˙:5˙;6˙;6˙;6˙;6˙;6˙:5˙NI(˙…j˙{yn˙ĽĽ»˙»»»ţ¦¦¦˙¨¨¨˙§§§˙§§§˙ŞŞŞęęę˙îîî˙óóó˙óóň˙ŕäć˙ĚŢŕ˙Ňŕŕ˙Öââ˙Ůää˙áäâ˙ęŕŘ˙íćä˙ďëę˙ńîî˙óńń˙ňńń˙ôóó˙ůůů˙úúú˙˙˙˙˙¬¬¬˙˛˛˛˙˛˛˛˙±±±˙µµµ˙ŔŔż˙{˙>:'˙olO˙ifG˙eaD˙…_˙~|Z˙soP˙trR˙UQ5˙da@˙Іc˙€}Y˙ŽŠe˙€[˙}Y˙—”m˙Ź‹f˙ŢŃ˙’Žh˙•‘h˙ŹŚb˙–“h˙Ą u˙’Ža˙š–i˙{O˙}xL˙‚}O˙…S˙™”d˙§˘o˙¸ł}˙ßŮź˙#˙]X5˙2- ˙61˙62˙62˙72˙73˙83˙83˙83˙84˙50 ˙^Z6˙61 ˙94˙94˙95˙95˙:5˙95˙94˙LH(˙„€i˙zxn˙ĽĽ»˙»»»ţ¦¦¦˙§§§˙§§§˙¨¨¨˙­­­ęęę˙ííí˙óóó˙ňňň˙öőő˙ÎŘÖ˙ÓßŢ˙Řŕŕ˙ŕßŰ˙čŰÔ˙ęâŕ˙ěçć˙îęę˙ďíí˙ňďď˙óňň˙őôô˙ř÷÷˙ůřř˙˙˙˙˙¬¬¬˙˛˛˛˙łłł˙łłł˙µµµ˙ŔŔŔ˙€{˙?:'˙plO˙jfH˙idG˙fcD˙c^@˙^\>˙XT8˙ZX:˙ZW8˙xsR˙_[;˙e`@˙idB˙vqN˙yuQ˙{wS˙ÖČŠ˙~X˙Ťa˙Ť‰`˙tpH˙“Ťd˙}yO˙Š„[˙ztJ˙|xL˙|O˙„€S˙™“b˙Ąźm˙·±{˙ŢŘž˙"˙[W4˙1, ˙50˙50˙61˙61˙62˙72˙72˙72˙73˙4/ ˙^X5˙50 ˙83˙83˙83˙83˙83˙83˙72˙KG'˙h˙zxn˙ĽĽ»˙»»»ţ§§§˙©©©˙©©©˙¨¨¨˙­­­ęęę˙ííí˙ňňň˙ňňň˙ňňň˙éęę˙ŇŘŘ˙ßŮŐ˙ćŘĐ˙çŢÜ˙čâá˙ęćĺ˙ěçç˙îęę˙đíí˙ňđđ˙ôňň˙öőő˙řřř˙˙˙˙˙­­­˙µµµ˙łłł˙łłł˙¶¶¶˙ŔŔŔ˙€{˙?9'˙qmQ˙khH˙gcE˙’Źk˙zvV˙’Źk˙^˙’Źk˙vtR˙‚~\˙njH˙okJ˙qmK˙€|V˙„_˙\˙ŢŃ•˙xtO˙„€X˙Š…]˙…‚Y˙Ź‹a˙uqH˙}xN˙wrF˙{vL˙{O˙„R˙—’b˙˘ťk˙µŻz˙Ýמ˙!˙ZV3˙0, ˙4/ ˙4/ ˙50˙50˙51˙51˙51˙61˙62˙3. ˙\W4˙4/ ˙72˙72˙72˙72˙72˙72˙61 ˙JF'˙‚~f˙zxm˙Ľ»»˙»»»ţ¨¨¨˙©©©˙¨¨¨˙¨¨¨˙®®®ęęę˙ííí˙ňňň˙ňňň˙ňňň˙ôôô˙äŕŢ˙ăŇË˙äŰŮ˙ĺŢÝ˙çáá˙éăă˙ëćć˙ěéé˙îëë˙đíí˙óđđ˙őóó˙÷őő˙˙˙˙˙®®®˙łłł˙łłł˙łłł˙¶¶¶˙ŔŔŔ˙€~y˙=9'˙rnQ˙rnN˙|xW˙xsT˙yuV˙|[˙}{X˙|[˙urQ˙…b˙_˙‡_˙plJ˙njG˙|X˙yvR˙ÜĚ˙vrN˙}V˙…€Y˙†‚Y˙Śc˙mi@˙qmD˙wqG˙{vK˙~{N˙Q˙–‘a˙ ši˙ł­z˙Ýם˙ ˙YU2˙/+ ˙2. ˙3.˙3/˙3/˙40 ˙4/ ˙50˙40˙50˙2- ˙[V3˙2. ˙61˙61˙61˙61˙61˙61˙40˙IE&˙|e˙ywm˙Ľ»»˙»»»ţ¨¨¨˙ŞŞŞ˙ŞŞŞ˙©©©˙®®®ęęę˙ííí˙ňňň˙ňňň˙ňňň˙ńńń˙ôôô˙ăßŢ˙áŘŐ˙äÝÝ˙ĺßŕ˙çââ˙ęää˙ěçç˙íéé˙ďëë˙ńîî˙óńń˙öôô˙ţüü˙®®®˙µµµ˙µµµ˙´´´˙¶¶¶˙ŔŔŔ˙~y˙<9&˙soS˙wsT˙‡a˙‚~\˙zuV˙‰†d˙‚~]˙‡„a˙]˙Śj˙„]˙‰…a˙€|Y˙~zV˙ŹŚf˙†`˙âÔ˙Z˙ŽŠb˙‚}V˙†‚Z˙š–l˙niA˙qmD˙uqG˙zvK˙~zN˙~Q˙•`˙žh˙˛­x˙ÜÖž˙˙WS2˙.* ˙1. ˙2- ˙2.˙3.˙3/ ˙3.˙3/˙4/˙3/ ˙1, ˙YT2˙1- ˙40 ˙4/ ˙40˙40˙4/ ˙40 ˙3/ ˙HC%˙€{f˙ywm˙Ľ»»˙»»»ţ©©©˙ŞŞŞ˙ŞŞŞ˙©©©˙®®®ęęę˙ííí˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙óóó˙çćĺ˙ÝŐŐ˙ĺŢŢ˙ćŕŕ˙čăă˙ęĺĺ˙ěçç˙îęę˙ďěě˙ňđđ˙ôňň˙üűű˙ŻŻŻ˙µµµ˙´´´˙´´´˙···˙ŔŔŔ˙~y˙<8%˙tqS˙plL˙njK˙kgH˙urQ˙yvW˙vqS˙qmM˙rmN˙†‚a˙wrR˙xuR˙vrO˙„€\˙€|X˙yuS˙âŇ•˙~Y˙„€Y˙}xR˙€{T˙—’h˙€}S˙pkB˙toE˙zsK˙}xM˙}P˙•Ź`˙›–d˙°Şw˙ŰÖť˙˙VQ1˙,(˙/, ˙0+ ˙0, ˙1, ˙0- ˙1- ˙1- ˙1- ˙2- ˙.* ˙WR1˙/+ ˙2. ˙2. ˙2. ˙2. ˙2. ˙2. ˙1, ˙EA$˙}yd˙xvm˙»»»˙»»»ţ©©©˙ŞŞŞ˙«««˙«««˙°°°ééé˙ííí˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ńňń˙ăŕÝ˙ßŘ×˙čáá˙éää˙ęćć˙ěčč˙îëë˙ňíí˙óńń˙ýűű˙ŻŻŻ˙¶¶¶˙¶¶¶˙¶¶¶˙···˙ŔŔż˙~y˙GD/˙}_˙|[˙„c˙}yY˙‡b˙ŽŠh˙‹‡f˙‰…d˙b˙•‘n˙‚|[˙~[˙‚~\˙…^˙…€]˙zY˙ćÔ“˙\˙Žb˙‹c˙’Ťe˙ťo˙—’h˙–‘h˙Š…[˙ŹŠ_˙“Žb˙—’e˙¦ˇq˙¬Ąv˙˝¸„˙âÜŁ˙E@#˙e`@˙SN.˙VQ1˙VQ1˙VQ1˙VQ1˙WR1˙WR1˙WR1˙VR1˙VR1˙UP/˙gb?˙UP/˙VR0˙VQ0˙UQ/˙UP/˙TP/˙TO.˙TN-˙c_A˙’Ťv˙{yo˙»»»˙»»»ţŞŞŞ˙¬¬¬˙«««˙«««˙ŻŻŻééé˙ěěě˙ňňň˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňóó˙óóó˙çćĺ˙ĺââ˙ŕÝÝ˙âÝÚ˙äßÝ˙ĺŕŕ˙ĺâŕ˙čäă˙˛˛˛˙¶¶¶˙¶¶¶˙µµµ˙¸¸¸˙ŔŔż˙~y˙:6#˙vrV˙qmM˙‰…c˙okK˙wsS˙{xX˙xuT˙vrR˙vrS˙{yZ˙WT9˙\Y<˙gcC˙mhG˙mhF˙gcC˙čŐ’˙liH˙wrM˙zuO˙zuO˙Іa˙trL˙zwQ˙{vN˙upF˙yuJ˙~yM˙‘Ś]˙”Ź`˙­§t˙ŮÓś˙˙QL-˙&"˙)&˙)&˙*&˙*&˙*&˙+'˙+'˙+'˙+'˙($˙RN.˙($˙+'˙+'˙+'˙+'˙+'˙+'˙*'˙?< ˙yta˙wvl˙»»»˙»»»ţ¬¬¬˙«««˙«««˙«««˙±±±ééé˙ěěě˙ńńń˙ńńń˙ňňň˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ńńń˙óóó˙ńńđ˙ćŕÝ˙âŘÖ˙ĺÝÜ˙çŕŕ˙íćć˙˛˛˛˙¶¶¶˙···˙···˙ąąą˙ŔŔż˙~y˙;8%˙zvW˙wsS˙uqQ˙}[˙‹‡c˙Š…c˙†a˙Ť‰f˙a˙˙ů«˙˙ü¬˙˙˙˛˙…‚`˙ډc˙˘źv˙Ąˇv˙žśq˙Ť‰_˙‰†]˙މa˙xtP˙˙˙±˙˙ř«˙˙ů«˙}V˙}xN˙}xN˙€}Q˙’Ť`˙”b˙®¨v˙ÚŐś˙˙SN/˙*&˙-* ˙.* ˙.* ˙.* ˙.* ˙.+ ˙0+ ˙.* ˙0+ ˙,( ˙TO/˙,( ˙/+ ˙/+ ˙/+ ˙/+ ˙/+ ˙/+ ˙.) ˙B>#˙{ua˙wum˙»»»˙˝˝˝ţ¬¬¬˙­­­˙¬¬¬˙¬¬¬˙±±±ééé˙ěěě˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňń˙ňńń˙ďîî˙çââ˙âÜÜ˙äŢŢ˙ěää˙łłł˙¸¸¸˙···˙···˙ąąą˙ŔŔż˙}y˙:7$˙|xZ˙yuU˙xsT˙|xV˙Їd˙‹‡e˙„b˙xtT˙qnQ˙˙ů¬˙^\C˙nkL˙€}S˙€|R˙Ś]˙±®e˙±­d˙«¨_˙‘ŽZ˙Ť[˙…€T˙ŽŠd˙nkJ˙˙÷Ş˙}V˙މ^˙|xM˙€{Q˙‘Ť`˙“Ža˙®¨v˙ÚÔś˙˙RM.˙(%˙,( ˙,) ˙,) ˙-) ˙-) ˙-) ˙-* ˙.* ˙.* ˙*' ˙RN.˙+' ˙.* ˙.* ˙.* ˙.* ˙.) ˙.* ˙-) ˙A=#˙zta˙wul˙»»»˙˝˝˝ţ­­­˙­­­˙¬¬¬˙¬¬¬˙˛˛˛ééé˙ěěě˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ńńń˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňńń˙ňňň˙đđđ˙ęčč˙ĺßß˙čââ˙ł´´˙···˙···˙···˙ąąą˙ŔŔż˙~}y˙;6$˙}yZ˙{wV˙zvV˙“m˙žšu˙śšt˙śs˙‘Ťj˙–t˙˙˙Ż˙Ť‹i˙Ť‹c˙ާX˙ˇž\˙˛®`˙¶łH˙˙ýg˙´˛H˙Âż`˙‘ŹV˙±®R˙™•i˙zvR˙˙˙Ż˙€~W˙މ_˙Ť^˙zO˙‘Ś^˙“Ť_˙¬§v˙ŮÔś˙˙OL-˙'$˙+' ˙+( ˙,' ˙,( ˙,( ˙,( ˙,( ˙,) ˙,) ˙)&˙QL.˙*&˙-) ˙-) ˙-) ˙,) ˙,) ˙,( ˙,' ˙?<"˙ws`˙wul˙»»»˙˝˝˝ţ­­­˙®®®˙®®®˙®®®˙˛˛˛ééé˙ěěě˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ńńń˙ďîî˙đîî˙ł´´˙ąąą˙ąąą˙¸¸¸˙şşş˙ŔŔż˙~}y˙;6#˙~|\˙|zX˙}yX˙„€^˙|yX˙zwV˙€|[˙yvU˙wrS˙{xZ˙}yX˙|yS˙ŽŠU˙ş·S˙ÇÄ_˙ýűg˙řőd˙ţüg˙ËÉ^˙µ˛T˙–U˙š–i˙„Y˙|V˙‹‡]˙ŹŠ`˙‘Ťb˙‹†\˙‹^˙‘Ť_˙­¦v˙ÚÔś˙˙NJ,˙&#˙*& ˙*' ˙*' ˙+' ˙+' ˙+' ˙+' ˙+' ˙+( ˙(%˙OK-˙(%˙+( ˙+( ˙+( ˙+' ˙+' ˙+' ˙*& ˙>;!˙vq_˙utl˙»»ş˙ľľľţ®®®˙®®®˙®®®˙­­­˙˛˛˛ččč˙ěěě˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňńń˙ňňň˙÷÷÷˙łłł˙ąąą˙¸¸¸˙¸¸¸˙»»»˙ŔŔż˙}}y˙96"˙}]˙{Z˙|Z˙Іd˙Ťi˙ډf˙‡„a˙„€^˙Ž‹h˙Žg˙„€]˙Ťc˙•‘c˙˝»U˙ÔŇd˙ů÷e˙řöe˙řöe˙ŐÓ`˙ľ»T˙Ť‰X˙š–k˙†‚Z˙Š…^˙Ť_˙Ša˙’Ťb˙–‘e˙•c˙‘Ś_˙­§v˙ÚÔť˙˙LH,˙%"˙(% ˙)& ˙)& ˙)% ˙)& ˙*& ˙*& ˙*& ˙*& ˙'#˙MI,˙'#˙*& ˙*& ˙*& ˙)& ˙*& ˙)& ˙(% ˙=9 ˙up^˙vtk˙»»ş˙ľľľţ®®®˙®®®˙ŻŻŻ˙ŻŻŻ˙´´´ččč˙ëëë˙ńńń˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙ňňň˙÷÷÷˙´´´˙şşş˙şşş˙şşş˙»»»˙ŔŔż˙}}y˙96#˙‚_˙‚~]˙~\˙ŹŤh˙’Źk˙ˇźy˙¦¤}˙Ź‹i˙‡a˙—’o˙‚`˙‡_˙“Ź]˙ŐŇd˙ńďf˙đîe˙ů÷e˙đíd˙ěéc˙ŐÓa˙”Z˙š•k˙‡‚\˙‹‡^˙މ`˙Śb˙“Žd˙•e˙Łžp˙“Ža˙­§v˙ÚÔť˙˙KG+˙$!˙($ ˙'$ ˙(% ˙(% ˙(% ˙(% ˙)% ˙)% ˙)% ˙&"˙LH+˙&"˙)% ˙)% ˙)% ˙(% ˙(% ˙($ ˙'%˙;8 ˙so]˙utk˙»»ş˙ľľľţ°°°˙°°°˙ŻŻŻ˙ŻŻŻ˙łłłččč˙ëëë˙đđđ˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ńńń˙ńńń˙ňňň˙ňňň˙ňňň˙÷÷÷˙µµµ˙şşş˙şşş˙ąąą˙ĽĽĽ˙ŔŔż˙}}y˙51!˙‚~_˙€}\˙€|]˙~{[˙ŹŤk˙Ť‹j˙ډg˙†e˙‚_˙•n˙‡`˙Ž‹c˙ť™]˙úře˙řöf˙őňf˙ďěg˙óńf˙ů÷f˙űůe˙¦˘`˙ˇśp˙]˙ڇ`˙†^˙Š`˙ŽŠb˙‘Śd˙ť™m˙ž™m˙¨¤s˙×Óś˙˙A=#˙˙˙˙˙˙˙˙˙˙˙˙EA&˙˙!˙!˙!˙"˙"˙"˙"˙53˙pl\˙usk˙»»ş˙ľľľţ°°°˙ŻŻŻ˙ŻŻŻ˙°°°˙µµµččč˙ëëë˙đđđ˙đđđ˙đđđ˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙ńńń˙ňňň˙÷÷÷˙µµµ˙şşş˙»»»˙»»»˙ĽĽĽ˙ŔŔż˙zzw˙phE˙®¤x˙´¨x˙ĐĆ˙×Ě”˙ŇĹŤ˙ĺל˙âÔ—˙č×™˙ńŢś˙®¬‡˙ާ˙«¨z˙ݬc˙űůf˙ů÷f˙űřf˙çĺg˙űřf˙úřf˙úře˙»¸i˙©Ąs˙І^˙_˙éו˙áŃ‘˙ŕĎ˙ŕÎŹ˙âŃ‘˙âŃ’˙ĺŐ”˙őä˘˙˘“^˙·¨s˙Ł•`˙ˇ“`˙ž]˙›Ž[˙—ŠY˙”‡W˙„S˙Ť‚Q˙Š}O˙‡{M˙€uH˙”Z˙zoC˙xmB˙tj@˙qg=˙md;˙j`9˙f_5˙bZ3˙meA˙•Ťn˙}q˙»»ş˙ľľľţ°°°˙±±±˙±±±˙°°°˙µµµččč˙ëëë˙đđđ˙đđđ˙đđđ˙ďďď˙đđđ˙đđđ˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙÷÷÷˙¶¶¶˙ĽĽĽ˙»»»˙»»»˙˝˝˝˙ŔŔż˙}}y˙3/˙…‚b˙„€`˙•’p˙Śj˙”‘n˙™–s˙‘Źm˙Ť‹j˙…d˙™•p˙Ž‹b˙™–a˙·´Y˙ů÷e˙ů÷f˙ú÷e˙ćăg˙ú÷f˙ů÷e˙úře˙ş·[˙©¤l˙ŹŠ^˙ŹŠb˙І`˙ŤŠa˙Śc˙’Žd˙ťn˙Łžr˙·´‚˙ŰÖ ˙˙=:!˙˙˙˙˙˙˙˙˙˙˙˙@>$˙˙˙˙˙˙˙˙˙30˙mhZ˙srj˙»»ş˙ľľľţ±±±˙±±±˙°°°˙°°°˙¶¶¶ččč˙ëëë˙đđđ˙đđđ˙đđđ˙đđđ˙đđđ˙ďďď˙đđđ˙ńńń˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙÷÷÷˙···˙»»»˙»»»˙»»»˙˝˝˝˙ŔŔż˙}|y˙72"˙Іf˙Š…d˙–’n˙“Źl˙™”q˙ św˙žšu˙›—s˙•p˙ śu˙›W˙ł°T˙­ŞW˙äác˙÷öe˙ř÷e˙éćd˙ř÷e˙÷öe˙ćăc˙˛ŻY˙Ľą\˙ĄŁ[˙“Ťc˙“Ťe˙•g˙—’h˙™“h˙Łžq˙ޤv˙Ľ·„˙äާ˙˙DA'˙˙"˙"˙"˙"˙"˙"˙# ˙# ˙# ˙ ˙EB&˙ ˙"˙"˙"˙"˙"˙!˙"˙53˙njZ˙srj˙»»ş˙ľľľţ±±±˙˛˛˛˙˛˛˛˙˛˛˛˙¶¶¶ççç˙ëëë˙đđđ˙đđđ˙đđđ˙đđđ˙đđđ˙đđđ˙đđđ˙ďďď˙đđđ˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ńńń˙ööö˙···˙˝˝˝˙˝˝˝˙ĽĽĽ˙˝˝˝˙ŔŔż˙||y˙A=*˙”m˙•‘n˙´°Š˙®«„˙˛­‡˙˛®‡˙˛°‡˙Łźx˙ˇťx˙ś™u˙–k˙ť™j˙·ł\˙Áżg˙řög˙öôg˙ďěi˙őôg˙řög˙Áľh˙Ľ¸[˙ާq˙ ›o˙š–o˙˘žt˙¦ˇu˙§˘x˙ޤy˙±¬˙ął˙ĆÁŽ˙čâ«˙QM5˙QM3˙A>%˙DA'˙CA'˙EA'˙EA'˙EA'˙EA'˙DA'˙DA'˙D@'˙B?%˙RN4˙B?%˙D@'˙D@&˙C?&˙B?&˙B>%˙B>%˙@<$˙QN6˙}j˙vsl˙»»ş˙ľľľţ˛˛˛˙˛˛˛˙˛˛˛˙±±±˙¶¶¶ńô÷˙öúţ˙ű˙˙˙ű˙˙˙ü˙˙˙ü˙˙˙ü˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ąąą˙˝˝˝˙ĽĽĽ˙ĽĽĽ˙żżż˙ŔŔż˙||x˙50 ˙Ť‰h˙Ť‰f˙Ž‹g˙’Ťj˙”l˙”p˙™–q˙ŤŠg˙…‚b˙˙ý­˙…`˙’Źd˙ľ»V˙ž›d˙µ˛k˙ÓĐh˙¬¨k˙ŇĎh˙·´j˙©¦j˙ÁľW˙¨¤t˙‘Źf˙˙ú«˙‘Žf˙Łťs˙š•k˙™–j˙Łžq˙­¨x˙˝¸…˙ăݦ˙2/˙VQ7˙˙˙˙˙˙˙˙˙˙˙˙@=$˙˙˙˙˙˙˙˙˙/-˙hdV˙spj˙»»ş˙˝˝˝ţłłł˙˛˛˛˙łłł˙łłł˙¸¸¸i>˙h<˙g;˙e:˙a7˙`7 ˙\4 ˙Z3 ˙V2 ˙T0˙R/˙O-˙L+˙I*˙G(˙D&˙B%˙>#˙="˙/˙ÇĘÍ˙ľľľ˙ľľľ˙ľľľ˙ľľľ˙ŔŔż˙|{x˙61 ˙Śj˙‘Žj˙¬©‚˙©¦˙±Ż†˙¤ˇz˙ަ€˙˘źy˙Ť‹i˙˙ö©˙vtV˙€\˙˛®W˙“e˙Łźs˙ź›o˙źśo˙źśo˙žšl˙ śn˙»¸]˙ˇ u˙……a˙˙ő¨˙Ž‹d˙“j˙š–k˙śn˙Ą r˙±­}˙Ŕ»˙ĺß§˙63˙b_E˙*'˙˙˙˙ ˙ ˙ ˙ ˙ ˙ ˙˙A>%˙˙˙˙˙˙˙˙˙2/˙jfW˙rqk˙»»ş˙ľľľţ´´´˙´´´˙łłł˙łłł˙···sK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE!˙gD ˙dC˙bA˙^<˙]>˙[=˙V8˙U9˙Q6˙J. ˙K2˙K3˙7˙ÉĚĎ˙ľľľ˙ľľľ˙˝˝˝˙żżľ˙ŔŔż˙||x˙41 ˙’Žl˙”Źl˙¤ˇz˙Ą˘{˙¤ˇz˙™•q˙ˇžx˙Ź‹g˙„a˙˙öŞ˙˙÷©˙˙ţŻ˙„^˙‘Žg˙š—p˙™–p˙•p˙”n˙š–o˙ śr˙–n˙˙ú«˙˙ô¨˙˙ô¨˙‘Žh˙š–k˙śm˙žšo˙Ą t˙łŻ˙½‰˙ćŕ©˙52˙`]C˙B?'˙" ˙˙˙˙˙˙˙˙˙˙@<$˙˙˙˙˙˙˙˙˙0.˙ieV˙qpk˙»»ş˙ľľľţ´´´˙łłł˙łłł˙´´´˙ąąąsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙cC˙Žx`˙\=˙Y:˙}f˙N0 ˙v`˙Ś{g˙‹|h˙^I-˙‚p˙ĹÇÉ˙ľľľ˙żżż˙żżż˙żżż˙ŔŔż˙|{x˙4/ ˙”m˙–’n˙ˇťw˙ť™s˙˘žx˙›—q˙źśv˙‘Ťh˙‘‹h˙“n˙„€a˙…a˙Ť‰e˙“Žk˙›—q˙•“m˙ńßť˙”’m˙śq˙ ›t˙ź›s˙Ł z˙Ťh˙’Źi˙™”l˙ś–m˙ť™n˙ź›p˙¦ˇu˙¶˛˙ÄľŠ˙çáŞ˙52˙`\C˙@=&˙@>'˙˙˙˙˙˙˙˙˙˙>:$˙˙˙˙˙˙˙˙˙/-˙gdU˙qok˙»şş˙żżżţµµµ˙µµµ˙µµµ˙´´´˙ąąąsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙cC˙•€j˙T3 ˙T5˙›Śx˙E'˙šŠx˙K0 ˙“„q˙’„r˙2˙ĘĚĎ˙ŔŔŔ˙żżż˙żżż˙Ŕżż˙ŔŔż˙{{x˙3/˙•‘o˙™•p˙™•q˙ަ~˙®Ş˙¤ y˙˘žx˙ śv˙ź›u˙©Ą~˙š—s˙•‘l˙‘Śg˙”k˙źšt˙–“o˙ç×—˙‹e˙’Źh˙“Źh˙”i˙¤žw˙–’i˙™•l˙›–m˙›o˙źšp˙ śq˙§Łv˙ął˙ÄŔŚ˙čâŞ˙52˙`\B˙@>&˙B?)˙85˙˙˙˙˙˙˙˙˙<9"˙˙˙˙˙˙˙˙˙-+˙fbT˙qoj˙»şş˙żżżţµµµ˙µµµ˙´´´˙´´´˙şşşsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙bB˙¸«˙š‡r˙‡r˙©š‰˙R4˙Ł—‡˙D(˙ˇ•…˙‰ye˙C* ˙ĚÍĐ˙żżż˙żżż˙ŔŔŔ˙ŔŔŔ˙ŔŔż˙{{x˙3.˙—“p˙›—r˙śs˙ˇťx˙¦˘{˙¤ z˙¤ˇz˙Łźy˙Łźx˙©¤~˙‘Ťi˙“Žj˙“Źj˙–’m˙Łźw˙—”p˙čŘš˙š–q˙¤ w˙¦ˇx˙Łźv˙­©˙Ąˇx˙¨Ły˙«§|˙¦ˇv˙©¤x˙˘ťr˙¨¤w˙»¶…˙ĆŔŤ˙éâ«˙52˙_[B˙A>'˙C@(˙C?)˙+)˙˙˙˙˙˙˙˙:6"˙˙˙˙˙˙˙˙˙,*˙eaS˙poj˙şşş˙żżżţ¶¶¶˙¶¶¶˙¶¶¶˙µµµ˙şşşsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙cC˙“€i˙P.˙§‡˙_D"˙‚mT˙Y?˙Žk˙]E)˙G/ ˙|jT˙ÇÉË˙ÁÁÁ˙ÁÁÁ˙ŔŔŔ˙ŔŔŔ˙ŔŔż˙{{x˙1.˙™•r˙ť™t˙źšu˙Ą z˙¬¨˙§Ł|˙ˇťx˙™•p˙—“n˙ˇťw˙”Źk˙–’l˙•‘l˙™”o˙ śu˙š–r˙äÔ–˙źťv˙Łźw˙ˇťu˙ śt˙ŻŞ€˙Łźv˙Ąˇw˙Łžu˙ ›q˙ˇťs˙¤ t˙©Ąx˙˝¸‡˙ČÂŽ˙ęä«˙52˙_[C˙A>'˙C@)˙A>(˙C?)˙ ˙˙˙˙˙˙˙95 ˙˙˙˙˙˙˙˙˙*(˙c`R˙ppj˙şşş˙żżżţ¶¶¶˙¶¶¶˙¶¶¶˙µµµ˙şşşsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙aA˙Ą”‚˙śŠu˙v^A˙W9˙U:˙R7˙P6˙M4˙L4˙=$˙ĚÎŃ˙ÁÁÁ˙ŔŔŔ˙ŔŔŔ˙ÁÁÁ˙żżż˙{zx˙1.˙ś™s˙Ąˇz˙´°˙µ˛‰˙łŻ†˙·µ‹˙µ˛Š˙ş·Ť˙·´‹˙ş·Ž˙¨¤}˙—“n˙”n˙ˇžv˙Łźx˙ žw˙äÖ™˙˘ y˙˘žv˙š–n˙™–o˙¨¤y˙›—n˙žšq˙ ›r˙˘ťs˙¤źt˙Ąˇv˙ŞĄy˙Ŕ»‰˙ĘÄŹ˙ëä­˙53 ˙_[C˙B?)˙C@*˙A>(˙@=(˙>;&˙˙˙˙˙˙˙64 ˙˙˙˙˙˙˙˙˙)'˙b^Q˙pnj˙şşş˙żżżţ···˙¶¶¶˙···˙···˙ĽĽĽsK$˙sK$˙sK$˙qJ#˙nH"˙lG!˙iE ˙gD˙dC˙bA˙^>˙[;˙Y;˙X;˙V:˙S8˙Q7˙N5˙L5˙>$˙ÍĎŇ˙ÂÂÂ˙ÂÂÂ˙ÁÁÁ˙ÁÁÁ˙ŔŔż˙{zx˙1-˙ž™u˙Ąˇy˙¬¨€˙ަ~˙ݬ˙ݬ˙«¦˙ˇťv˙śr˙¨Ł{˙ś™r˙š–p˙š–p˙ź›u˙ž™s˙•p˙ßĐ“˙™–p˙ť™r˙śp˙śp˙©Ą|˙žšq˙ ťr˙˘ťt˙Łźt˙¦ u˙§Łw˙ާz˙Äľ‹˙ĚÇ‘˙ěç­˙52 ˙_[B˙A?*˙C@+˙A>)˙@=(˙>;'˙53 ˙˙˙˙˙˙43˙˙˙˙˙˙˙˙˙(&˙`]P˙pmh˙şşş˙żżżţ¸¸¸˙¸¸¸˙···˙···˙»»»l@˙i?˙i?˙g<˙d:˙b9˙_7˙[6˙Y4 ˙W3 ˙S1 ˙Q0 ˙O. ˙L-˙J+˙F)˙D(˙B&˙?%˙1˙ÎĎŇ˙ÂÂÂ˙ÂÂÂ˙ÁÁÁ˙ÁÁÁ˙ŔŔż˙{zx˙0,˙ śv˙¤ z˙¦˘{˙§Ł{˙±­„˙«§˙¨¤}˙ ›u˙ź›u˙§˘{˙ś™r˙ťr˙śr˙›q˙›q˙—“n˙ÜÍ‘˙—”o˙ś™q˙žšq˙ťšr˙¬¦|˙ śr˙˘žt˙¤ u˙Ąˇv˙§˘w˙©¤y˙«¨{˙ĹŔŤ˙ÍČ”˙ěç­˙63!˙^[C˙B?*˙C@+˙A>*˙@=(˙>;(˙>=(˙)'˙˙˙˙˙31˙˙˙˙˙˙˙˙˙&%˙_\O˙noh˙şşş˙żżżţ¸¸¸˙···˙···˙···˙˝˝˝ďóő˙őřý˙ůü˙˙ůü˙˙ůý˙˙ůý˙˙úý˙˙úý˙˙úţ˙˙ű˙˙˙ü˙˙˙ü˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ý˙˙˙ţ˙˙˙˙˙˙˙żżż˙ÂÂÂ˙ĂĂĂ˙ĂĂĂ˙ĂĂĂ˙żżż˙zzx˙0,˙Łžw˙§Ł{˙ŞĄ}˙©Ą}˙łŻ†˙°¬˙«§˙˘ťw˙˘śv˙©¤}˙ž›t˙ź›t˙źśu˙©¦}˙ަ}˙َy˙ŢŃ–˙§¤|˙ަ}˙©Ą{˙¤ w˙¬¨~˙Łťs˙¤ v˙¦ˇv˙§Łx˙¨¤x˙ŞĄy˙­¨{˙ČĂŹ˙ÎČ“˙ěć­˙64"˙]ZC˙A?+˙B?,˙@=*˙?<(˙=;(˙>;&˙>;'˙ ˙˙˙˙1/˙˙˙˙˙˙˙˙˙#"˙^[N˙nmh˙şşş˙ŔŔŔţąąą˙ąąą˙¸¸¸˙¸¸¸˙˝˝˝ććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ěěě˙îîî˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ňňň˙żżż˙ÄÄÄ˙ĂĂĂ˙ĂĂĂ˙ĂĂĂ˙żżż˙{zy˙94%˙©Ą}˙ŻŞ‚˙˛­„˙°¬˙´Ż…˙±¬„˙®¨˙¬¦~˙«§~˙®©˙ަ~˙¬¦}˙«¦~˙µ±˙¶±˙°¬…˙âÔ›˙˛®†˙µ˛˙´±‡˙ą´‰˙´®˙ŻŞ˙±«€˙˛­˙ł®˙´°„˙µ˛…˙¸ł…˙ĐË—˙ŐĐš˙ďé±˙PM:˙gdL˙[XA˙ZWA˙YV@˙WU?˙WT>˙UT=˙US<˙SP:˙0.˙/.˙.,˙<:'˙.,˙0-˙/,˙/,˙.,˙.+˙.+˙,*˙=:+˙ok]˙qpi˙şşş˙ŔŔŔţąąą˙ąąą˙¸¸¸˙¸¸¸˙ľľľććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ďďď˙ňňň˙żżż˙ĂĂĂ˙ĂĂĂ˙ÄÄÄ˙ÄÄÄ˙żżż˙{zy˙/+˙¦˘z˙´°…˙Á˝’˙ŔĽ‘˙ĂŔ•˙ş¶Ś˙ą´‹˙şµŤ˙»·Ť˙Ŕľ’˙ˇťv˙¤źw˙Łžx˙Ż«‚˙Ż«‚˙©¦~˙ÜĐ–˙«§˙­©€˙Ż«˙¬¨~˙˛®„˙©¤y˙«§|˙¬¨}˙®©~˙«§{˙­¨|˙­©|˙ĘĹ‘˙ĎÉ•˙íç®˙42!˙[XC˙>=*˙?=*˙><)˙=:(˙;:&˙:8%˙87$˙86$˙/.˙ ˙ ˙,*˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙˙WVK˙mlg˙şşş˙ŔŔŔţşşş˙şşş˙şşş˙ąąą˙ľľľććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ííí˙îîî˙îîî˙îîî˙ďďď˙ďďď˙ďďď˙ňňň˙ŔŔŔ˙ĹĹĹ˙ĹĹĹ˙ÄÄÄ˙ÄÄÄ˙żżż˙{zy˙/+˙©Ą|˙ŻŞ€˙˛®˙´°…˙ąµŠ˙·ł‰˙·ł‰˙łŻ†˙¬Ą~˙°«‚˙§Łz˙§Łz˙­©€˙°¬˙˛®˙´±x˙ŮÍŹ˙¦Ł{˙ަ}˙¬¨~˙«§|˙·ł‡˙¬¨~˙Ż«˙±¬˙±¬˙Ż©~˙°«~˙®Ş~˙ÍČ”˙ŇÍ—˙íčŻ˙64$˙\YD˙B?-˙DA-˙B?,˙A>,˙?=*˙><)˙<:(˙;8'˙:8%˙'&˙ ˙-)˙ ˙˙˙˙ ˙ ˙ ˙ ˙! ˙ZWL˙lmg˙şşş˙ÁÁÁţ»»»˙şşş˙şşş˙ąąą˙ľľľććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ííí˙îîî˙ďďď˙îîî˙ďďď˙ňňň˙ŔŔŔ˙ĹĹĹ˙ÄÄÄ˙ÄÄÄ˙ĹĹĹ˙żżż˙{zy˙/,˙«§˙¶´˙Âż“˙Âľ’˙·´‰˙»¸Ś˙Á˝’˙«¨}˙­¨˙ł®„˙ŞĄ|˙ަ|˙¬¨˙«§}˙«§{˙˝ąt˙áŐ„˙ĄŁw˙©Ą{˙©Ą{˙ަ{˙ł®„˙«Ą{˙¬¨}˙®©}˙ŻŞ~˙°«˙°«~˙®©~˙ĎÉ•˙ÓÎ˙íçŻ˙75&˙\XD˙C@/˙DA.˙B@-˙A>,˙?=+˙>;)˙<:)˙:8(˙:7&˙;9'˙˙)(˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙XUJ˙mmg˙şşş˙ÁÁÁţ»»»˙şşş˙şşş˙»»»˙ŔŔŔććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ííí˙îîî˙ďďď˙ňňň˙ÂÂÂ˙ĆĆĆ˙ĆĆĆ˙ĆĆĆ˙ĹĹĹ˙żżż˙{zy˙/+˙­©€˙¶±†˙Á˝‘˙Ĺ•˙Ăż“˙ľşŹ˙żşŽ˙·ł˙Ż«˙µ°†˙­¨~˙­©˙łŻ„˙¶°†˙ł°…˙Ľąz˙ÝÓŹ˙˛Ż„˙°¬‚˙¬¨}˙­¨}˙µ°„˙­©}˙ŻŞ˙°«˙±¬€˙±¬€˙Ż«˙®©}˙ĐË–˙ÓĎ™˙íçŻ˙85&˙\XD˙C@.˙DB/˙C@-˙A?,˙?=,˙><*˙=:)˙<8(˙:8'˙86%˙64#˙+(˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙˙XUJ˙nmh˙şşş˙ŔŔŔţĽĽĽ˙»»»˙»»»˙»»»˙żżżććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ííí˙îîî˙ňňň˙ĂĂĂ˙ĆĆĆ˙ĆĆĆ˙ĹĹĹ˙ĆĆĆ˙żżż˙{zy˙.*˙Ż«€˙şµ‰˙ĽµŠ˙Ľ¸Ś˙ĆĂ•˙Ŕ»Ź˙ŔşŹ˙łŻ˙˛®‚˙·˛‡˙°«€˙°«€˙Ż«€˙ŻŞ˙®Ş€˙«¨|˙ŐÇŹ˙«§}˙®Ş˙ŻŞ˙Ż«˙ął†˙°«€˙±¬€˙˛­˙±¬˙±¬€˙°¬€˙®Ş~˙ŇÍ–˙ÔĐš˙îčŻ˙85'˙\XD˙C@/˙DB0˙B@.˙A?-˙?=,˙><+˙=:)˙<9)˙:8'˙97&˙64$˙HF4˙˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙˙WTH˙mmh˙şşş˙ŔŔŔţĽĽĽ˙»»»˙»»»˙ĽĽĽ˙ÁÁÁććć˙ęęę˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙îîî˙ńńń˙ĂĂĂ˙ĆĆĆ˙ÇÇÇ˙ÇÇÇ˙ĆĆĆ˙żżż˙{zy˙-)˙˛­˙żşŤ˙Č•˙ÎĘť˙ÇĂ–˙ľ»Ž˙ş¶Š˙µ±†˙´±„˙ąµ˙˛®˙˛®˙˛­‚˙±­˙±­˙®©˙ÔÇ˙®Ş˙±¬˙±­˙±­˙»µ˙˛®‚˙łŻ˙˛®‚˙˛­€˙˛¬˙°­˙®Ş~˙ÓΙ˙ÖŃ›˙îčŻ˙96)˙]YE˙DA0˙FC1˙DB0˙CA/˙A?-˙@>,˙><+˙=;*˙<9(˙;8(˙76$˙NK8˙&%˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙˙VSH˙mlh˙şşş˙ŔŔŔţ˝˝˝˙˝˝˝˙˝˝˝˙ĽĽĽ˙ÁÁÁććć˙ęęę˙îîî˙îîî˙îîî˙ííí˙ííí˙ííí˙ííí˙ííí˙ííí˙ěěě˙ěěě˙ěěě˙ěěě˙ěěě˙ěěě˙ěěě˙ěěě˙ńńń˙ÄÄÄ˙ČČČ˙ÇÇÇ˙ÇÇÇ˙ĆĆĆ˙żżż˙{zy˙-)˙şµŠ˙ľşŤ˙Ă˝Ź˙Ăľ˙Ç•˙ľąŚ˙Ľ·Š˙·˛…˙¶±…˙»¶Š˙łŻ˙µŻ…˙´®‚˙˛­‚˙´­˙°¬˙ÓÇŹ˙ݬ˙˛­˙˛­˙˛­˙»·‡˙˛®˙˛®˙±­€˙±¬€˙°«˙°«˙­©|˙ÓÎ˙×Ňš˙îçŻ˙;8*˙_ZE˙GC1˙FC2˙EC1˙CA/˙B@.˙@>-˙?=,˙>;*˙=:)˙;9(˙87%˙NK8˙86%˙ ˙ ˙ ˙ ˙ ˙ ˙ ˙˙VSG˙mlh˙şşş˙ÁÁÁţ˝˝˝˙˝˝˝˙ĽĽĽ˙ĽĽĽ˙ÂÂÂóóó˙ňňň˙ôôô˙ôôô˙ôôô˙ôôô˙őőő˙őőő˙őőő˙őőő˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙÷÷÷˙üüü˙ĂĂĂ˙ÇÇÇ˙ÇÇÇ˙ČČČ˙ÇÇÇ˙żżż˙{zy˙+)˙ĚÇ˙ŘŐŁ˙×Óˇ˙ŰÖ¤˙ŰÖ¤˙×ҡ˙ÓÍž˙ÎÉš˙ÎÉ™˙ŇÍś˙ÎÉ™˙ÎÉ™˙ÎÉ™˙ĎÉ™˙ĎĘ™˙ÍÉ™˙äŘť˙ÎÉš˙ŃĚ›˙ŇĚś˙ŇÍś˙×Ń ˙ÓÎť˙ÔÎť˙ÔĎť˙ÔĎś˙ÔÎś˙ÓÍť˙ŃĚ›˙čá«˙éä¬˙ňěł˙=;,˙]ZF˙HD4˙HE3˙GD2˙EB1˙DB0˙B@.˙A?-˙?=,˙><+˙=:)˙97'˙NL9˙74%˙97&˙˙ ˙ ˙ ˙ ˙ ˙˙TRG˙mlg˙şşş˙ÁÁÁţľľľ˙ľľľ˙ľľľ˙ľľľ˙ÂÂÂňňň“řřř˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙÷÷÷˙űűű˙ÄÄÄ˙ÉÉÉ˙ÉÉÉ˙ČČČ˙ČČČ˙żżż˙{{y˙-)˙ą´‡˙½Ž˙ĹŔ‘˙ĚÇ—˙ĘÄ•˙ĘĹ”˙ÇĂ’˙ÉÄ•˙ËĆ—˙ČĂ’˙½Ž˙Ăż˙ĂľŹ˙ÄżŹ˙ĹŔ˙ĹŔ˙ÝŃ—˙Ç‘˙ĘĆ’˙ËÇ“˙ĚÇ”˙ÔΙ˙ĐĚ–˙ŇÎ˙ÔĐš˙ŘŃ›˙ÚŐś˙Üן˙Ýן˙đę­˙őđ±˙ŹŤh˙HF4˙^[F˙HF4˙IF4˙GD2˙FC2˙DB0˙CA/˙A?-˙@>-˙><+˙>;*˙;8(˙OM:˙96%˙96%˙42"˙ ˙ ˙ ˙ ˙ ˙˙TRG˙mlg˙şşş˙ÁÁÁţżżż˙ľľľ˙ľľľ˙˝˝˝˙šššôôô˙÷÷÷˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙űűű˙ÄÄÄ˙ÉÉÉ˙ČČČ˙ČČČ˙ČČČ˙żżż˙{{y˙/+˙ˇśw˙ަ˙ާ~˙©¦~˙ŞĄ˙©¤}˙¨¤}˙¨¤}˙¨¤}˙®Ş‚˙©¤|˙©¤|˙«¨}˙­©˙®Ş€˙­©˙ÎĂŚ˙±¬‚˙´Ż„˙·˛…˙¸´†˙Ŕ»Ť˙Ľ¸‰˙żş‹˙½Ť˙ĹżŽ˙ÇÂ˙ĘĹ’˙ËĆ“˙ęĺ¨˙ĎË–˙HE4˙LJ7˙^\G˙IH5˙KH5˙IF4˙HE3˙FC1˙EB1˙CA/˙B@.˙@>-˙?=+˙;9)˙PL:˙:7'˙:7'˙97%˙+(˙ ˙ ˙ ˙ ˙˙SPF˙mlh˙şşş˙ÂÂÂţżżż˙ľľľ˙żżż˙żżż˙ĹĹĹŮŮŮžűűű˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙űűű˙ĹĹĹ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙żżż˙{{y˙0+˙ ť|˙§Ł˙©¦˙¤ˇ~˙«¨„˙ź›y˙Ł ~˙ˇťz˙±­˙«¦‚˙´±Š˙µł‹˙™•r˙›—r˙žt˙ťt˙¶„˙ˇžw˙§Łz˙¨Ą|˙ަ|˙µ°…˙ݬ˙´Ż˙·˛…˙ş¶‡˙ľ¸‰˙ÁĽ‹˙Ă˝Ś˙éă¨˙mjO˙NL9˙NL9˙^\H˙JH5˙JH6˙JG5˙HE2˙GD1˙EC0˙DB/˙CA/˙A>-˙?>-˙<:)˙PM;˙:7'˙;9(˙97&˙:8&˙˙ ˙ ˙ ˙˙QOD˙mlh˙şşş˙ÂÂÂţżżż˙ŔŔŔ˙żżż˙żżż˙ÄÄÄBBBôôô˙řřřţřřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙řřř˙ýýý˙ÇÇÇ˙ĘĘĘ˙ĘĘĘ˙ÉÉÉ˙ĘĘĘ˙żżż˙{{y˙74"˙zw`˙€{d˙„€g˙„g˙†‚h˙‰†j˙ڇj˙މk˙‹l˙•‘q˙“Žo˙–’p˙™–u˙ś™u˙ź›w˙ź›x˙¶‡˙Ą {˙ŞĄ~˙­¨˙Ż«˙µ°…˙µ°„˙¸ł†˙»¶˙ľąŠ˙ÁĽŤ˙ÄżŹ˙ÇĂ’˙ČĂ“˙[XF˙b^I˙`]H˙fdN˙][F˙\ZE˙\XD˙[WC˙YVB˙XT@˙VS@˙US?˙SQ>˙SP=˙PN;˙WTA˙NK8˙MJ8˙LI7˙JI6˙KI6˙&%˙" ˙" ˙1/"˙_\P˙nnh˙şşş˙ÂÂÂţŔŔŔ˙żżż˙żżż˙ŔŔŔ˙ĆĆĆóóóUüüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙üüü˙ýýý˙ÉÉÉţËËË˙ĘĘĘ˙ËËË˙ĚĚĚ˙ąąą˙zzw˙+(˙¤ y˙§˘z˙¨Ł|˙§Ł{˙¦Łz˙¦˘z˙¦ˇy˙§˘y˙§˘y˙­¨€˙¨Łz˙©Ą{˙«§{˙¬¨}˙®©~˙­©~˙Éż‹˙±­˙¶±„˙¸ł…˙şµ†˙½Ť˙ľşŠ˙ĂľŚ˙ĹÁŽ˙ČÄ˙ĚÇ“˙ĐĘ•˙ŮÔś˙nkO˙MJ6˙LI5˙JG4˙ZWA˙GE1˙GE1˙FC0˙EB/˙DA.˙B?,˙B?+˙@=+˙?=)˙=;(˙:8%˙KJ5˙75#˙96#˙84#˙64!˙53!˙10˙ ˙ ˙˙JH<˙jid˙ąą¸˙ÁÁÁţÁÁÁ˙ÁÁÁ˙ÁÁÁ˙ÂÂÂ˙ĆĆĆĎĎĎůËËË˙ËËË˙ËËË˙ĚĚĚ˙ÁÁÁ˙rrm˙$ ˙PM7˙RN7˙RN6˙RN5˙QM5˙PL4˙OK3˙OJ2˙LI0˙TP7˙JE.˙IE-˙HF-˙GD,˙FB+˙A>)˙umH˙@<&˙B>(˙A>'˙?;%˙JF0˙<8#˙;8#˙:6#˙96!˙85˙63˙62˙>:$˙>;$˙>:$˙<8!˙IE-˙:7˙:7 ˙96˙85˙84˙73˙52˙51˙41˙30˙1.˙?<&˙/,˙/,˙/+˙.*˙-*˙,)˙%! ˙ ˙˙=;.˙a`Z˙»şş˙ÂÂÂ˙ÁÁÁ˙ÁÁÁ˙ŔŔŔ˙ÄÄÄ˙ĎĎϲĘĘĘţĘĘĘ˙ËËË˙ËËË˙ĚĚĚ˙şşą˙‘‰˙ť›“˙ť›’˙ť›’˙ś›’˙ś›‘˙śš‘˙›š˙›™˙›™˙ť›’˙š™Ź˙šŹ˙šŹ˙™—Ž˙™Ž˙——Ž˙ާš˙–•Ť˙—Ž˙•Ť˙—•Ś˙š™Ź˙–•Ś˙—•Ś˙–•‹˙–•‹˙•”‹˙•”‹˙•”‹˙•“‹˙”“Š˙”“Š˙“’‰˙—–Ť˙“‘˙“‘‰˙’‘‰˙’‘˙’˙‘˙’‡˙‘‡˙‡˙ʆ˙ʆ˙“’‰˙ŹŽ…˙ŹŽ…˙ŹŽ…˙ŹŤ…˙ŹŤ…˙ŽŤ„˙ŽŤ„˙‡€˙‰‚˙“’Ś˙©¨§˙ÄÄÄ˙ÁÁÁ˙ÁÁÁ˙ÂÂÂ˙ÂÂÂţĹĹĹľĐĐĐ8ÎÎÎ˙ËËË˙ËËË˙ËËË˙ËËË˙ĚĚĚ˙ĚĚÍ˙ÍÍÍ˙ĚĚÍ˙ĚĚÍ˙ĚĚÍ˙ĚĚÍ˙ËËĚ˙ĚÍÍ˙ĚÍÍ˙ËĚĚ˙ËĚĚ˙ĘËË˙ĘËË˙ËĚĚ˙ĚĚĚ˙ËËË˙ĘËË˙ĘËË˙ÉÉĘ˙ĘĘĘ˙ËËË˙ËËË˙ÉĘĘ˙ÉĘĘ˙ČČÉ˙ČČÉ˙ĘĘĘ˙ĘĘĘ˙ČČÉ˙ČČÉ˙ÇÇČ˙ÇÇČ˙ČČÉ˙ČČÉ˙ČČÉ˙ÇÇČ˙ÇÇČ˙ĆĆÇ˙ĆĆÇ˙ÇÇČ˙ÇÇČ˙ĆĆÇ˙ĆĆÇ˙ĆĆÇ˙ÇÇĆ˙ĹĹĆ˙ÇÇĆ˙ČČÇ˙ĹÇČ˙ĹÄĂ˙ĹĆČ˙ÄĹĆ˙ÄĆÇ˙ĹÄÄ˙ÄĹĆ˙ĆĆĹ˙ÂÂĂ˙ĹĹÄ˙ĂĂÂ˙ĂĂĂ˙ĂĂĂ˙ÂÂÂ˙ĂĂĂ˙ČČČDÖÖÖąÓÓÓţÍÍÍ˙ËËË˙ĘĘĘ˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ÉÉÉ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ÉÉÉ˙ÉÉÉ˙ČČČ˙ČČČ˙ČČČ˙ÉÉÉ˙ČČČ˙ČČČ˙ČČČ˙ÇÇÇ˙ČČČ˙ČČČ˙ČČČ˙ÇÇÇ˙ÇÇÇ˙ĆĆĆ˙ĆĆĆ˙ĆĆĆ˙ÇÇÇ˙ÇÇÇ˙ĆĆĆ˙ĆĆĆ˙ĹĹĹ˙ĹĹĹ˙ĆĆĆ˙ĐĐÇ˙Ľ˙>>ą˙ĘĘĹ˙Á±¬˙ÓY˙Ŕ˘”˙ÄÇÉ˙Ä}Q˙Ë\ ˙ÄËĎ˙ÉÉÄ˙ż˙cc·˙ĹĹĂ˙ĂĂĂ˙ÂÂÂ˙ĆĆĆţËËËŔęęęÜÜÜřÖÖÖţĎĎĎ˙ĚĚĚ˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ËËË˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ĘĘĘ˙ÉÉÉ˙ÉÉÉ˙ÉÉÉ˙ÉÉÉ˙ÉÉÉ˙ÉÉÉ˙ČČČ˙ČČČ˙ČČČ˙ČČČ˙ČČČ˙ČČČ˙ÇÇÇ˙ÇÇÇ˙ÇÇÇ˙ÇÇÇ˙ÇÇÇ˙ÇÇÇ˙ÇÇÇ˙ĆĆĆ˙ËËÇ˙ppĆ˙„„Ľ˙ĘĘÇ˙ÄÁÁ˙͆L˙ø¶˙ÄÇČ˙Ǩ˙Ç‹b˙ĆÉË˙ÉÉÄ˙YYĹ˙šš»˙ĆĆĹ˙ĆĆĆ˙ÎÎÎţŮŮŮ˙ěěě ŕŕŕ3ŕŕŕ˙ÝÝÝţŘŘŘ˙ŐŐŐ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÔÔÔ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÔÔÔ˙ÔÔÔ˙ÓÓÓ˙ÔÔÔ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ÓÓÓ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ŃŃŃ˙ĐĐĐ˙ĐĐĐ˙ĎĎĎ˙ĎĎĎ˙ĎĎĎ˙ŃŃĐ˙ÓÓĐ˙ŇŇĐ˙ŃŃĐ˙ĎĐĐ˙ĎŃŇ˙ĎĐŃ˙ĎĐĐ˙ÎĎŃ˙ÎĐŃ˙ĎĎĎ˙ĐĐĎ˙ŃŃĎ˙ŃŃĎ˙ŇŇŇ˙ŘŘŘ˙ŢŢŢ˙ĺĺĺmÝÝÝpŢŢŢ˙ßßß˙âââ˙âââ˙ăăă˙ăăă˙ăăă˙äää˙ĺĺĺ˙ĺĺĺ˙ĺĺĺ˙ććć˙ććć˙ççç˙ççç˙ččč˙ééé˙ééé˙ęęę˙ëëë˙ëëë˙ëëë˙ěěě˙ííí˙ííí˙îîî˙îîî˙ďďď˙đđđ˙đđđ˙đđđ˙ňňň˙đđđ˙ďďď˙ďďď˙îîî˙îîî˙ííí˙ííí˙ěěě˙ěěě˙ëëë˙ęęę˙ęęę˙ěěě˙îîî˙đđđ˙óóó˙ööő˙÷÷÷˙ůůů˙řřř˙ööö˙ôôô˙đđđ˙ěěě˙ééé˙ĺĺĺ˙âââ˙ááá˙ááá˙ŕŕŕ˙ßßß˙ŕŕŕˇŮŮŮ®ŮŮŮ˙ŘŘŘ˙ŮŮŮ˙ŮŮŮ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ŮŮŮ˙ÚÚÚ˙ŰŰŰ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ŰŰŰ˙ŰŰŰ˙ÚÚÚ˙ÚÚÚ˙ŰŰŰ˙ŰŰŰ˙ŰŰŰ˙ŰŰŰ˙ÚÚÚ˙ÚÚÚ˙ŰŰŰ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ÚÚÚ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ÚÚÚ˙ŘŘŘ˙ŘŘŘ˙ÚÚÚ˙ŮŮŮ˙ŮŮŮ˙ÚÚÚ˙ŮŮŮ˙ÚÚÚ˙ÚÚÚ˙ŮŮŮ˙ŘŘŘ˙×××ţŘŘŘÍŰŰŰŢŮŮŮţŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮţŮŮŮóÝÝÝŕŕŕ ßßßűßßßţßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßß˙ßßßţááá˙ááá&ĺĺĺ/ććć˙äääţäää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äää˙äääţććć˙éééRîîîęęęĎëëë˙ééé˙éééţééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙ééé˙éééţééé˙ëëë˙ëëëęîîî6ööö'ôôômôôô€őőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőőôôôôôôrööö9˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙÷÷˙˙˙˙˙˙˙˙˙˙˙˙ü˙˙˙˙˙˙˙˙˙ţ?˙˙˙˙˙˙˙˙€˙˙˙˙˙˙˙ř˙˙˙˙˙˙€˙˙˙˙˙ü˙˙˙˙ŕ˙˙˙˙˙˙ü˙˙đ˙˙Ŕ˙˙€˙˙üřđŕŕŔŔ€€€€€€€Ŕŕŕŕđđřüţ?˙˙€˙˙ŕ˙˙đ˙˙ü˙˙˙˙˙˙ŕ˙˙˙ü˙˙˙˙€˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙ŕ˙˙˙˙đ˙˙˙˙đ˙˙˙˙ř˙˙˙˙˙˙ţ˙˙˙˙˙˙ţ˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙€˙˙˙˙˙˙˙Ŕ˙˙˙˙˙˙˙ŕ?˙˙˙˙˙˙˙đ?˙˙˙˙˙˙˙đ˙˙˙˙˙˙˙ř˙˙˙˙˙˙˙˙ü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙(0` €%  0.)1KH?>RPEA::17 'heXH‹‡x’„¦ŁśŽË©˘•ݱ§›ü¸®ˇ˙µ«ť˙­Ł–˙ŁŚ˙śŹ…˙”}˙’†z˙Ź…x˙…w˙Ťs˙yk˙zqcčul^Ôoh[¶pjZ’dbS[ % li]W‘‹~©®¦™čĘż´˙ŮÍĆ˙ßÓÍ˙ßŇÎ˙ÜĐË˙ŘĚČ˙ŐÉĹ˙ÔÉÄ˙ŃĆĂ˙ŃĹÄ˙ĎÄÂ˙ÍÂŔ˙ÉľĽ˙ø¶˙Ľ°®˙˛¦Ł˙§š—˙žŹ‹˙Ťz˙zlh˙l^ZţJ83˙O>5˙]PD˙xiZú{q`ĹhdUv $LIACŠvş¬ˇ•˙»®Ą˙Ě˝ą˙ŢŇÍ˙ěßÜ˙óçä˙çÜÚ˙¸Ż©˙–Ť‚˙zp˙mfX˙XQA˙LE2˙G?+˙A7$˙:2˙8/˙=4 ˙D;'˙I@,˙ND2˙^TB˙peU˙‚te˙•†z˙Ľ­Ł˙Ľ«˘˙ˇ‰˙źŽ†˙ŠtjţO?9˙d[P˙g`Ußb^Qu XTIVŠ‚uߣ•‹˙¶ĄˇţŐÇÁ˙đăŕ˙ŮÍČ˙’~˙WN>˙0(˙˙%˙- ˙K>-˙RD3˙WF7˙ZI4˙\H3˙\I2˙_L6˙^J4˙]J4˙aN9˙^N8˙`P9˙^P8˙^P8˙UJ0˙KA(˙,$ ˙.' ˙QH3˙|j˙ޤ•˙ľµŞ˙—Ť…˙rebţUIC˙ldYýf`U” xpcş“„z˙°źšţâŇÎ˙ćÚÔ˙€vi˙+%˙˙) ˙5(˙=-˙C2˙J7%˙M8&˙k[P˙p_T˙xfZ˙wdO˙wbJ˙vbI˙xbJ˙s]F˙wbK˙~kR˙~lS˙sY˙…v\˙x^˙tY˙|pT˙UJ2˙QE,˙PF+˙@8˙6.˙.'˙YS8˙Š„k˙Ćż»˙†~zţbXS˙ng]ň?<5>{qeŰ”‚|˙ŢĐË˙ăŐĐ˙SK:˙ ˙' ˙2&˙9,˙?0˙E5"˙K:'˙R>,˙WB1˙ZD3˙|oe˙€sj˙Š|s˙Ś~q˙Ž€r˙‚t˙‘‚u˙”…y˙‰}˙śŹ‚˙ž‘…˙˘—‰˙ĄšŚ˙¦ťŹ˙¦ť˙¤›Ť˙ʇ|˙Šv˙…}p˙|ug˙vo`˙mfW˙f`Q˙VQ>˙gcW˙چ˙Ąˇź˙zqnţle]˙BA9Eh`V—šŠ‚˙űîë˙vh˙ ˙& ˙.$˙5*˙;.˙A2˙G6#˙M;)˙S>.˙XD4˙]H7˙aK:˙…yr˙‰x˙‰€z˙‹‚|˙Ť~˙Ź…€˙ʇ˙‘‰˙“Š…˙”ڇ˙•Ť‰˙–ŽŠ˙—‹˙‘Ť˙’Ž˙—’Ž˙–‹˙’ڇ˙Ť‚˙}˙„x˙zs˙yun˙sog˙mia˙daX˙omf˙’‹†˙އ‚ţlg_ôriďýńí˙XR@˙˙( ˙/%˙5)˙:.˙?1˙TG5˙YI8˙]O>˙cQA˙gUG˙lZJ˙mZL˙jd_˙‡†„˙‡…˙‡…˙‡„˙‡…˙‡…„˙‡…„˙‡…„˙†…˙‡…„˙‡…˙†…„˙†…˙„˙„‚˙‚˙‚€˙‚€˙~˙€}˙~}{˙~}{˙}{z˙{zx˙zyw˙ZYT˙˙Ąť˙”Ť˙QNEKČ»µţ§ť“˙ ˙$˙)! ˙/%˙8+˙>1˙D7$˙tiZ˙uj[˙zn^˙~qc˙‚ug˙†xj˙‰yk˙˘ŁŁ˙   ˙›››˙ššš˙™™™˙™™™˙™™™˙˙˙———˙–––˙–––˙•••˙•••˙•••˙”””˙”””˙“““˙“““˙“““˙“““˙’’’˙’’’˙’’’˙’’’˙””•˙˘ŁĄ˙˙>8&˙ĘÂŔ˙_[SUçŮÔţ`YI˙(# ˙4-˙=4˙D;%˙J?(˙OD-˙SF1˙•Ť€˙“Š|˙•Ť~˙Ź˙›‘„˙ž“…˙ •†˙ˇˇ˘˙ˇˇˇ˙ŰŰŰ˙ŢÝÝ˙ŢÝŢ˙ÝÝŢ˙ŢŢß˙ßŢß˙ßßŕ˙ááá˙ŕŕá˙âââ˙ááâ˙ââá˙ŕŕá˙ááá˙áßŕ˙ßßŕ˙ŢŢß˙ÝÝŢ˙ÝÝŢ˙ÜÜÝ˙ŰŰÜ˙ÜÜÜ˙Ř××˙ˇˇ ˙ˇ˘¤˙ ˙ ˙ÔËĘ˙±Ş¦Aä×ŇĂŽxţ!˙5.˙;3˙A8!˙F<&˙LA*˙OD-˙¬¦ť˙¨ˇ–˙ŞŁ˙¬Ąš˙®§›˙Ż©ž˙˛«ž˙˘˘Ł˙ĄĄĄ˙»Ľ¸˙®­Ş˙®®Ş˙ŻŻŞ˙ŻŻŞ˙ŻŻ«˙ŻŻŞ˙±°«˙Ż®Ş˙±°«˙±Ż«˙˛°«˙±°«˙˛±«˙˛±¬˙˛±¬˙˛±«˙łł«˙ł˛¬˙˛˛«˙´˛«˙¶´¬˙·¶ł˙   ˙ŁŁ¦˙˙0+˙ÜŇĎ˙˘‘ÎÁĽ/ŐËČ˙F?+ţ'" ˙60˙=5˙C:#˙H>%˙KA(˙y˙€{p˙‚}q˙…~s˙†€t˙‡u˙‚t˙ŁŁ¤˙¦¦¦˙vtl˙¨§ ˙¸·˛˙ş¸˛˙ÂŔ¶˙»şł˙şşł˙ŃĘŻ˙»ş˛˙ĆÄ·˙˝˝ł˙ż˝ł˙Ŕľ´˙ŇĎŔ˙ËÉ˝˙ÍË˝˙ĚĘĽ˙ĚĘĽ˙ÖÔÁ˙ĎĚľ˙ĐÍż˙ŇĐż˙”‘€˙˘˘Ł˙¤¤¦˙ ˙•Ť†˙ĚÁľŁŇĆÂQÁ¶´˙UN:ţ1+˙4-˙<4˙A9 ˙7,˙őő÷˙ňňó˙ňóó˙óóó˙ňňó˙ňňň˙řřř˙˘˘˘˙­­®˙uto˙ÂĽ‡˙Ŕ»†˙Ŕş‡˙ĘĂ‘˙ČÁŽ˙ËĹ’˙ŕÔ™˙ÔΙ˙ŕŮŁ˙ŕ١˙âÚŁ˙îč­˙„~U˙|vJ˙}uJ˙“Ś`˙•Žb˙[˙}vF˙}vD˙†}M˙—–˙¤¤¤˙  ˘˙}un˙ÔČŽǸ´$ÉŔľÝ‡˙NG2ţ0*˙3,˙,$˙řřů˙÷÷÷˙÷ö÷˙řřř˙řřř˙ůůů˙˙˙˙˙˘˘˘˙­­Ż˙utn˙Łžs˙ž™p˙ť™n˙¦˘w˙ťn˙¦ u˙ÎÁ‹˙ą´„˙ĚĆ–˙ÎČ•˙ÖĎś˙íçŻ˙}uP˙qkB˙slB˙§ x˙Ąžu˙}Q˙sl>˙wpB˙‡€U˙•“‡˙§¦¦˙ťžž˙­˘žÔÉÄN»ł˛ËŞ ›˙tkX˙?7˙óôö˙őőő˙ööö˙óóó˙ďěě˙ćáâ˙äßß˙¤¤¤˙ŻŻ°˙ywq˙®©|˙´®˙­§z˙´Ż˙°Ş}˙·ł„˙ÝĐ•˙ČĂ’˙ŘÓž˙ÚÔź˙ßÚŁ˙đę±˙…Z˙~xP˙~yO˙‘h˙ĐĘŁ˙š”l˙—‘k˙“m˙‚Z˙šŠ˙ŞŞ¬ý¤¤¤˙&Ǹ±!ÎÄÁ‰´©Ąâóôô˙ööő˙óňň˙ůúú˙ôňň˙íęę˙ěçç˙Ą¦¦˙ŻŻŻ˙xwp˙}yV˙€[˙„^˙}W˙qmF˙vqJ˙ş¬v˙†U˙ł®k˙›–g˙Łžn˙ěĺ­˙ztQ˙ztN˙Ťc˙ŽŠf˙ÝÖ±˙wqJ˙UN#˙E>˙RL˙–”˙«¬­ű§§§˙'óóó˙ôôô˙ńďď˙ř÷÷˙řůů˙ńđđ˙đëě˙§§§˙±±˛˙ywq˙|xV˙…€\˙І`˙’Ťg˙snH˙}xQ˙Çą˙¤źf˙ŕÝt˙Ż©|˙Ż©|˙ěć®˙vpL˙_Z4˙PJ!˙60˙ĆŔ˙jd<˙C=˙GB˙SM"˙–”‡˙­®®ű©©©˙'%ööö˙íëë˙ďěě˙ôóó˙ööö˙ńńń˙úůů˙¨¨¨˙˛łł˙zwq˙plJ˙lgF˙okG˙}X˙kgA˙]Y3˙»¬s˙fa9˙‰‚W˙{M˙Š…T˙Ý×™˙MG"˙82 ˙<8˙0*˙Ćż™˙Îȡ˙61˙B<˙NH˙–’†˙®ŻŻűŞŞŞ˙'%őöö˙éćĺ˙ëçç˙ňîî˙ńđń˙ňđđ˙ýüü˙ŞŞŞ˙´µµ˙{zs˙‡T˙|xS˙}Z˙‹‡b˙„Z˙id@˙Ŷ|˙uqH˙•e˙“Ž_˙š”d˙ŢŘž˙e`<˙WQ+˙[V/˙jd=˙ޤ}˙Áş”˙yQ˙ZS,˙e_7˙™–Š˙ݰ°ű®®®˙'%őőő˙ĺáĺ˙âÜĺ˙ŕŕí˙ßćě˙ôńń˙ýúú˙¬¬¬˙µ¶¶˙ywp˙wsI˙gcC˙plJ˙€|Y˙hdA˙ea>˙Ăłw˙ZV1˙…€T˙|vJ˙†€R˙ĐĘ‘˙KF#˙1,˙50 ˙toI˙b\6˙lf@˙Á»•˙4/˙E@˙’Ź…˙°°±ű®®®˙'%őőő˙éçë˙ĐŰă˙Úçĺ˙ěčä˙îěí˙úůů˙­­­˙·¸¸˙xwp˙kgI˙hdF˙fcD˙snM˙d`?˙ea@˙ÓÆ˙WS.˙~R˙zuI˙„€Q˙ĚĹŤ˙PK)˙PK(˙,'˙ť—s˙2-˙LG"˙ś•p˙rlF˙C=˙’Ž„˙˛˛łű±±±˙'%ňňň˙őôô˙ŰŰÚ˙čŰ×˙ëçć˙đíí˙ýüü˙ŻŻŻ˙ąąą˙xvo˙njK˙c^@˙\X<˙okK˙ea@˙fbA˙ŮÇŠ˙ge@˙~yP˙wrG˙‚~P˙Ĺż‰˙E@˙}xU˙†]˙upL˙1, ˙RM)˙UQ,˙‘Śh˙GC˙Ź˙łłłű˛˛˛˙'%óóó˙óóó˙ňňń˙âÝÝ˙çŕŕ˙íéé˙ůöö˙°°°˙şşş˙vvn˙qlM˙miJ˙rnN˙|wW˙soM˙fdD˙ßÎŽ˙okH˙…€W˙snD˙€{O˙ľą˙EA!˙,(˙B>˙.*˙-)˙MH&˙.*˙>:˙D?˙Ž‹˙´´´ű´´´˙'%ńńń˙ńńń˙ńńń˙ňôô˙ííě˙çäă˙ęâá˙˛łł˙ĽĽĽ˙wwp˙€{[˙{Y˙…`˙„b˙pnO˙uqQ˙ńŢ›˙|X˙•’j˙~{S˙Ź‹^˙ÄżŠ˙YU6˙HC$˙KG'˙KG'˙JD$˙^[:˙IE$˙IE%˙QL-˙’…˙¶¶¶űµµµ˙'%ńńń˙ńńń˙ńńń˙ňňň˙ńńń˙ňóó˙đîî˙ł´´˙˝˝˝˙usm˙{wW˙{wW˙mlO˙ëŘ–˙ľŻw˙plK˙‚N˙{wO˙ÎÁ„˙íŮ–˙trI˙¶±|˙B>!˙%#˙*' ˙+' ˙)%˙FA#˙)%˙*&˙41˙‹‰€˙···ű···˙'%ńńń˙ńńń˙ńńń˙đđđ˙ńńń˙ňňň˙řřř˙µµµ˙ľżŔ˙trk˙€~[˙|xX˙pnQ˙É»„˙…O˙ˇžW˙ëéa˙¦˘X˙ˇž_˙É»˙…\˙´°}˙B>"˙%"˙*' ˙*' ˙'$˙D?#˙(%˙*' ˙3/˙ډ˙¸¸¸ű¸¸¸˙'%ńńń˙đđđ˙đďď˙ńđđ˙đđđ˙đđđ˙ööö˙¶¶¶˙ŔŔŔ˙nmj˙‚~]˙}]˙†b˙Śh˙€_˙ÔŃa˙×Ôb˙ÓĐa˙•‘g˙…^˙‘Ťd˙şµ„˙40˙˙˙˙˙74˙˙˙(&˙†}˙ąąąűşşş˙'%űţ˙˙ý˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙»»Ľ˙ŔÁÁ˙–{˙ĸ˙ŐĆŚ˙îŰš˙›—v˙›—h˙ňďf˙Ů×g˙ńďf˙Ż«r˙—”m˙đÜš˙öĺ˘˙Ć·~˙µ§p˙ݎl˙Ą™f˙›Ž`˙ž‘c˙‰}Q˙tL˙{rJ˙›—‡˙şşşű»»»˙'$yO&˙iA˙a;˙[:˙R1 ˙J- ˙E)˙ÂĂĹ˙ŔÁÁ˙ljg˙Ž‹h˙ŽŚj˙Ž‹i˙–’i˙ťšX˙éće˙áŢd˙ěée˙©Ąb˙•’b˙•‘h˙ĹÁŹ˙SP8˙˙˙˙˙-,˙˙˙ ˙{˙»»Ľű˝˝˝˙'$~V.˙oJ"˙iF˙~dF˙kO/˙—‡s˙jS7˙ÇÉË˙ÂÂÂ˙nmg˙š•p˙™•p˙“n˙ÔÇŹ˙Łź_˙–’g˙’Žg˙ś™h˙¬©e˙ĎÁ‰˙—”l˙ĎĘ–˙\Z@˙=9#˙˙˙˙41˙˙˙#! ˙…‚z˙˝ľľűľľľ˙'$zQ(˙kD˙d?˙iJ'˙nS4˙J- ˙<˙ĆÇÉ˙ÄĂĂ˙lkg˙źśt˙˘ťw˙›u˙ńŢ›˙ËĽ‡˙‘Ťj˙Śi˙“j˙ÔĆŤ˙îŰ˙šo˙ÖŃš˙]ZA˙@>(˙40˙˙˙/,˙˙˙  ˙‚€y˙˝ľľűÁÁÁ˙'$Ŕ°ź˙»«ś˙¸©›˙µ¨™˙ł¦˙°Ą—˙«ź‘˙ÄĹĆ˙ĆÇÇ˙jif˙¦ˇy˙ަ˙¦˘|˙ś™u˙“‘l˙•‘m˙ńÜš˙–’m˙ˇžw˙›™q˙Ą v˙ŮÔž˙\YA˙?<(˙@=*˙#!˙˙)'˙˙˙ ˙€x˙ŔŔŔűĂĂĂ˙'%ńńň˙ńńň˙ńńň˙đđń˙ńńň˙ňňó˙őőő˙ÂÂÂ˙ÉÉÉ˙kjg˙±¬˙µ°‡˙±®„˙Ż«˙¨Ł|˙Łźy˙ĺŐ•˙Ąˇz˙ł®‚˙°¬˙˛­€˙âܤ˙heM˙QN:˙QO9˙PM8˙((˙53!˙%#˙$"˙*)˙„{˙ÁÁÁűÄÄÄ˙'%ďďď˙ďďď˙îîî˙îîî˙îîî˙ííí˙ňňň˙ÂÂÂ˙ĘĘĘ˙igd˙´°˙´Ż…˙±­˙±¬˙ޤ|˙©¦x˙ŕÔŤ˙َy˙±­˙®©~˙¬¨{˙âۤ˙]YD˙@=,˙><+˙<9(˙42!˙˙ ˙ ˙˙~|v˙ÂÂÂűĆĆĆ˙'$îîî˙íííűíííűíííűíííűěěěűđđđűÄÄÄ˙ĚĚĚ˙gfc˙¸ł‡˙˝¸Ś˙µ±…˙´°…˙­¨~˙¨Ą|˙×ÉŹ˙§¤{˙´Ż˙­¨}˙¨Ły˙ĺߦ˙`^G˙C@/˙A@.˙>;*˙97&˙><+˙˙ ˙˙}{w˙ĂĂĂűÇÇÇ˙'ëëëÜűűű˙ůůů˙ůůů˙ůůů˙ůůů˙˙˙˙˙ĹĹĹţÍÍÍ˙fea˙ÓĎ™˙ÚŐˇ˙ŮÓž˙ÚÖˇ˙ÖŃť˙ÖŇť˙ëß ˙ŰÖ ˙äݦ˙äߦ˙čâ©˙ÚŐ ˙SQ>˙FC1˙EC1˙A?-˙<9(˙JH4˙!˙ ˙˙}{u˙ÄÄÄűÉÉÉ˙']]]_˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ĘĘĘ˙ĎĎĎ˙kkfţ“s˙•u˙š–u˙˘ť{˙˘źy˙Ą˘{˙ÎĂŽ˙łŻ„˙ÁĽŽ˙ĆÁ‘˙ŐĎš˙yw[˙a_K˙VSA˙TQ?˙QN;˙KI7˙UR?˙IE3˙"!˙ ˙~|w˙ĹĹĹűĘĘĘ˙'25555@ÍÍÍúĎĎĎţiha˙MI-˙JE*˙FA'˙HC*˙@<"˙95˙g_9˙2.˙:5˙/+˙,)˙1-˙:6˙.+˙-)˙+(˙(% ˙0,˙$" ˙! ˙ ˙sqi˙ĆĆĆýĹĹĹů ®®®®ĐĐĐ˙ŇŇŇ˙××Ů˙××Ű˙××Ű˙×ŘÚ˙ÖŘÚ˙Ö×Ú˙ÔÔ×˙ÖÖÚ˙ŐÖŮ˙ŐÖŮ˙ŐÖŘ˙ŐŐŘ˙ÔŐ×˙ÔŐ×˙ÔÔ×˙ÔŐ×˙ĽĽĐ˙śŘ˙ÖŞ˙Ö˛š˙ĎĆÄ˙„„Ę˙ÉÉČ˙©©©±$ŘŘŘčÚÚÚţŘŘŘ˙ŮŘŘ˙ŘŘŘ˙ŮŮŮ˙ÜÜÜ˙ÜÜÜ˙ÝÜÜ˙ÜÜÜ˙ŢŢŢ˙ßßß˙ßßß˙ßßß˙ÝÝÝ˙ÜÜÜ˙ŰŰŰ˙ŰŰŰ˙ááŢ˙ĺćá˙ßăć˙ŮÝŕ˙×ŮŘ˙ÝÝŘţŰŰÚî, =ÝÝÝúÜÜÜţÚÚÚ˙ŮŮŮ˙ŘŮŮ˙ŮŮŮ˙ŘŘŘ˙ŘŘŘ˙ŮŮŮ˙ŮŮŮ˙ŘŘŘ˙ŮŮŮ˙ŮŮŮ˙ŮŮŮ˙ŘŘŘ˙ŘŘŘ˙ŮŮŮ˙ŘŘŘ˙ŘŘŘ˙ŘŘŘ˙ŮŮŮ˙ŰŰŰţßßßţ$$$H  ___Vćććęööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙čččďjjjb "$$$$$$$$$$$$$$$$$#˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ŕ˙˙˙ŕ˙˙˙üđŔ€€€€€€€Ŕŕřţ˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙€˙Ŕ˙˙˙˙˙˙€˙˙Ŕ˙˙ŕ?˙˙˙˙˙˙˙˙˙˙˙˙( @ €-/%9;0!]\M1“Žl°©ś¤»˛§Đ˝ł¨ëżłŞ˙Ľ±¦˙¸¬˘˙®˘›˙¦™‘˙ś‡˙Žw˙~qf˙pe[ňf[O×aWJ±d]O{ljYCfdVCŹ«µ« öÜĎČ˙öčć˙ůíęţČľ¸˙ŞŁš˙“Ś‚˙ym˙wob˙ofX˙mcV˙rh\˙zrd˙†|p˙Ťw˙‘{˙žŚ†ţ†sn˙™„z˙gXM˙[RHÁfbTbWTH;ŚvÜ˝®¦˙éŰŘţµŞ˘˙sk\˙:1˙˙&˙K=-˙VE6˙]H2˙`K4˙cM8˙aK5˙gR<˙hU=˙fV<˙`S9˙NB)˙0'˙D:!˙pkV˙’Šy˙ –Ťţwt˙c[Qö_[PhbZOhźŹ˙ăÖŃţ€wi˙!˙#˙6)˙C3 ˙N:(˙U?-˙zmc˙„tl˙†vd˙xe˙vd˙Ś|i˙•†r˙šŚx˙ “˙Ł˙–‹y˙|s`˙tkX˙g^J˙VN8˙E?%˙…u˙ˇ›ţ~ur˙c^Vݦ—˙Äą±ţ˙& ˙3(˙?0˙F6#˙O=+˙WC3˙]G6˙wmf˙|sn˙vp˙‚xt˙„|w˙†~y˙†€{˙~˙‚€˙‰€˙Š„˙˙}y˙}xr˙vqk˙njc˙d`X˙YWO˙`YM˙‘Ž˙WTK^J@˙ÍÇŤ˙SN.˙!˙‚|W˙b]7˙˘śv˙1+˙š™“ýµµµ˙99˙˙˙˙ŕăá˙çŢŰ˙đíě˙˙˙˙˙­­®˙•“Ź˙njH˙WS7˙upP˙fb?˙ieB˙äŃ‘˙he=˙Ăż‡˙pkK˙|uR˙GB ˙XR/˙xrN˙TO,˙™“ý···˙99˙˙˙˙óóô˙éĺĺ˙čăă˙öńń˙°°±˙›™”˙†‚^˙urU˙|zZ˙}zX˙‚\˙ôŕž˙X˙ĘÄŽ˙OK/˙ZW5˙VQ0˙hc@˙VP0˙ZU4˙ś›–ýąąş˙99˙˙˙˙ńńń˙ňóó˙ňóó˙ďęé˙łµµ˙’‘Ť˙~yV˙a^D˙÷âť˙ކZ˙yvL˙¤ g˙‰„T˙˝µz˙čÓ‘˙˙$ ˙QN.˙# ˙(%˙—•’ýĽĽ˝˙99ýýý˙ńńń˙đđđ˙ńńń˙ůůů˙¶¶·˙‘ŹŤ˙‰„`˙rnQ˙¦ťr˙ŹŤO˙¸µY˙őň`˙ľĽ]˙ÉĹu˙h`<˙˙"˙LH,˙!˙$!˙–—‘ýŔŔŔ˙99˙˙˙˙ő÷ú˙÷ůű˙÷řú˙űüý˙ĽĽ˝˙”“Ź˙›—p˙މh˙’Źn˙–‘f˙čäe˙üúg˙çĺe˙ÔΑ˙IE0˙97˙:7 ˙LI/˙<9"˙>:"˙š”ýÂÂÂ˙99pB˙[2˙Y7˙U8˙K2˙ÉËĎ˙‰‰‡˙Ćş„˙ßÎ˙Śl˙¤ˇb˙˙ţe˙ńđh˙ţüc˙ŢÚ‰˙DB0˙λ|˙¨šd˙§h˙vk@˙_V0˙ŹŤýÄÄĹ˙99oA˙[1˙fF"˙\?˙=#˙ÎĐŇ˙Ї˙¤źw˙‘Ťl˙Ąˇq˙µ±\˙˙ýe˙öóh˙ţűd˙ŘŐt˙d`>˙)'˙˙,*˙˙ ˙”“ýČČČ˙99˙˙˙˙ůü˙˙ůü˙˙űţ˙˙˙˙˙˙ÄÄĹ˙ŹŽŚ˙ş´˙¦Ł~˙¸˙µłf˙ŘŐp˙âŢq˙ÚŘq˙ÜŮ‚˙…}\˙RO=˙JG2˙:9%˙/-˙-+˙——’ýĘĘĘ˙99űűű˙îîî˙îîí˙ííí˙óóó˙ÄÄÄ˙‡‡˙˝ą‰˙¦˘|˙úĺź˙Ŕąz˙¦˘w˙®Ş‚˙§˘y˙ăÜ”˙ďŮ—˙-- ˙97%˙76%˙˙˙“’ŽýĚĚÍ˙92ţţţ˙ňňňüńńńüńńńüöööüÇÇÇ˙‡‡‡˙ËĹ“˙ą´˙´˛˙®Ş˙«¨˙đßť˙§¤{˙çä©˙?=3˙A>.˙<:)˙SP=˙ ˙˙’‘ŽýĐĐĐ˙9ÉÉÉÁ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ÎÎÎ˙‡„˙°Ş{˙¦˘v˙®¨{˙˛­}˙ą´‚˙ßŃ‘˙ĎĘ‘˙·˛~˙RO7˙LI2˙GD-˙LH1˙<:#˙˙ŽŽýŇŇŇ˙8!:99GÂÂÂëĎĎĎţĹĹÇ˙ĂĹĆ˙ÄÄĆ˙ŔÁĂ˙ľżÁ˙˝˝Ŕ˙ąşľ˙ľľÁ˙ĆĆĆ˙ÄĹĹ˙ĆĹÄ˙­ŻĆ˙Ä·¬˙ŶŞ˙±˛ČţĽĽ»é" ***dâââ˙ŰŰŰţŮŮŮ˙ŮŮŮ˙ÚÚÚ˙ÚÚÚ˙ÜÜÜ˙ÜÜÜ˙ÜÜÜ˙ŰŰŰ˙ŮŮŮ˙ÜÜŰ˙ŇÓÝ˙ŢŘŐ˙ÜŐŃţŐŐŕ˙===dbbbďďď˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙ööö˙÷÷÷˙ďđď˙ggg„ ,888888888888- ˙˙˙˙˙ř˙ţ?đŔ€€€ŕřřřřřřřřřřřřřřřü˙Ŕ˙ŕ˙đ˙˙˙˙(0 ` VOF„|nIŹ…xjxpgXSL‹ng^›lf[ťKF>ŽD>7…wm_ori[RUOE sj^ldX?tneş°§ăŕÔÎ˙×ĚÇ˙ł¨ˇ˙›’˙Ťy˙…{p˙€vj˙~ti˙|pe˙~qg˙rjţ‚ri˙‡wjďJC:¦ke[UWSLQJ@1‰~tĚČąłţś‘†˙k`T˙>2˙2$˙L<+˙dSF˙iU@˙jV>˙iT>˙n\E˙qbI˙oaG˙RG.˙H>%˙haJ˙wo[˙…|rţnf^ăJF@OOH?'©š“ö”Š€˙.&˙2'˙@1˙L:(˙WC2˙o]Q˙‡{s˙Ś€w˙Ź„z˙”˙Ž…˙ť“Š˙ź—Ž˙‘˙‹„{˙yo˙rmb˙gcW˙‚~x˙ztţkg_O‰~s{{p˙#˙2'˙>1˙eXH˙n_P˙vgX˙€vn˙’‘˙ŹŽ˙ŹŽ˙ŹŽŽ˙ŽŤŤ˙ŽŤŚ˙ŤŚ‹˙‹‹Š˙ŠŠ‰˙‰‰˙‡†˙‡†…˙‚‚˙F@/˙~x§Şź–pMG4ţ80˙E;%˙OC-˙ź—‹˙ ™Ś˙Ąť˙Ą š˙··¶˙ĆĹĂ˙ĆĆÄ˙ÇĆĹ˙ČÇĹ˙ÉČĆ˙ÉČĆ˙ÉČĆ˙ČÇĹ˙ČÇÄ˙ÇĆĂ˙ČÇÄ˙ˇˇ˘˙˙Ŕ·´•…zo «ˇšÓ82ţ<4˙B9˙»ą´˙»¸˛˙Ľął˙±Ż¬˙ŹŽ‹˙¸µ—˙Á˝ ˙Âľˇ˙Đɤ˙ĐĚ«˙ÓĎ­˙§Ł‡˙ŞĄ˙±­Ž˙¦ˇ˙ ť…˙˘˘Ł˙ynî’Ť(zpd © ™ŠxqcńD<#˙őöö˙öőö˙ńďď˙ĘÉÉ˙’‘Ź˙¨Łx˙©¤x˙ŞĄy˙ËÂŤ˙ÓÍš˙äާ˙|uO˙Ś…\˙¤žu˙†€V˙Ź‹p˙¤¤Ąţlh_+˘š’‰‚aôôô˙őôô˙ňńń˙ĘÇČ˙”“˙€|X˙‰…_˙uqJ˙Şˇl˙·˛p˙ĘÄ‘˙rlG˙hc<˙ˇšs˙IB˙tpT˙ŞŞŞý@>6XVSđďď˙đíí˙ňńň˙ŇŃŃ˙––“˙wsM˙{V˙mhC˙–Ť\˙چZ˙·˛{˙PJ$˙LG˙żą’˙TN%˙xsY˙­­­ý=<2`_]îěî˙Űßć˙ëęë˙ÔÓÓ˙——“˙lhF˙rnM˙ea?˙‘‡W˙zN˙©Łp˙GB˙\W2˙SM(˙€zT˙kfN˙°°°ý97-a_]óóó˙ĺáß˙ëçç˙ŐÔÔ˙—”˙kgH˙njK˙ieD˙Ł™h˙{vL˙ˇśj˙LH'˙ZV3˙?:˙TP-˙jgP˙łłłý53*[XUńńń˙ńňň˙ííě˙ĎÍÍ˙™•˙}yX˙‘i˙„~X˙›”d˙ł©u˙ź›k˙B> ˙:7˙EA"˙95˙heQ˙¶¶¶ý20'ZWSđđđ˙đđđ˙đđđ˙ÖÖÖ˙—•˙|[˙’Ťg˙ ťY˙ÎË_˙ˇ›i˙ˇťp˙,(˙"˙.+˙# ˙[YG˙¸¸¸ý0/'ZWS¶ŁŽ˙®ś‰˙¦—„˙°©ˇ˙ ź™˙­Ąx˙«Łx˙ÄÁb˙ĺăe˙ˇťh˙ĐÄŚ˙woI˙^V4˙]V6˙LE'˙niU˙»»»ý-,%XURtM$˙mL(˙nU7˙Ś€r˙—”˙ťr˙Ľł˙Ąžm˙”h˙Ď„˙µ±‚˙MJ3˙  ˙$"˙˙RPC˙ľľľý,+%TQM×ĎÇ˙ÓĚĹ˙ŃËĹ˙ÉĆĂ˙™—˙­¨€˙¨Ą}˙ś™s˙Äą…˙§¤z˙ÄżŽ˙UR<˙A>*˙%$˙ ˙RPE˙ÂÂÂý.-(QMIîîîţíííýíííýÚÚÚţ™—˙·˛†˙˛®„˙ŞĄ{˙Ŕ¸„˙°«˙ĆÁŹ˙PM9˙><*˙20 ˙ ˙HF>˙ÄÄÄý32.rkcĐĐĐÎüüü˙üüü˙ăăăţ››ţ·ł˙»·‹˙Ľą‹˙ŃÉ”˙ÓΚ˙ÄżŹ˙TQ>˙JH6˙IG4˙%#˙KJA˙ÇÇÇý22.WUS`^\`_Z^^^}¶¶´ţ‘Ź‚˙ŹŚ˙‰}˙Ť€˙„x˙€u˙„‚w˙€~s˙kjr˙|gM˙sp}˙żżżé320 €x ©©©ÇŮŮŮţŘŘŘ˙ÚÚÚ˙ÚÚÚ˙ŰŰŰ˙ÜÜÜ˙ÚÚÚ˙ŮŮŮ˙ÝÝŰ˙ÚÜÝ˙ŰÜÚţ[ZYZmlgwww{{{‘{{{‘{{{‘{{{‘{{{‘{{{‘{{{‘{{{‘{{{‘TTT\WVS˙˙˙üŕ€€ŕđđđđđđđđđđř˙˙€˙˙˙(  @ł˘źJŁ“““«ž ·Ä»ľÍŢ×Úă÷óöďůőřőňďńüíéëüÔŃŇő\[\ďtss㏏ŹÍ«««·ĆĹĹ“×ÖÖJ´¤ˇ˙Ą•—ţ°¤¨˙ÍÄË˙ęćě˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙ćĺé˙\]`˙{z}˙—š˙ł´¶˙ĚËĚţŘ××˙ˇ‰{˙iO:ţ[?$˙S7˙J.˙?"˙3˙)˙%˙1˙0˙/˙3& ˙?5˙`[Kţźť–˙/Yëîđ˙ćçč˙íđń˙†‡Š˙„‡Ž˙†Ź˙†Ź˙…Ž˙…‡Ž˙‹Ś“˙Š‘˙‰Š’˙ŠŚ“˙pokţCţ˙˙˙ööö˙đëě˙wy}˙uo@˙id9˙e`3˙‰V˙‚Mţ3-ýmf7ýf^,ýE<ýŽŽ“˙ůřř˙őôô˙ţüü˙~€„˙lf;˙_Z5˙YT-˙•Ť_˙~xH˙:4 ˙jc8˙†S˙D=˙””™˙ňňô˙Ţăç˙˙ýü˙……‰˙b^4˙TP,˙HD ˙ť•f˙smA˙72 ˙3-˙¨ˇy˙81˙™šž˙űýý˙ĺÝÜ˙ýúú˙‹‹˙[U/˙HD$˙83˙¨žq˙hc9˙2- ˙GB˙Íǡ˙C=˙ťźŁ˙úúú˙ňňň˙őóň˙‘“–˙RN)˙/-˙˙ľ´„˙QO+˙˙mhE˙61˙ šr˙žźŁ˙˙˙˙˙˙˙˙˙˙˙˙˙™ť˙@=˙ňÝ—˙Á°w˙˙Őć˙řć¨˙mhK˙#˙d_<˙·¶˛˙k?˙];˙U:˙Ş­ł˙85˙Äłz˙(' ˙ĄˇJ˙VT1˙ľ­u˙ ˙˙˙¸·¶˙k?˙W4 ˙3˙­Ż·˙š’e˙()˙hg2˙ŇŃc˙’ŽQ˙˙¨źu˙yrO˙EA"˙´µ¸˙˙˙˙˙ý˙˙˙˙˙˙˙§©¬˙A@$˙Ĺ´|˙YY.˙—•L˙{yH˙Żźj˙˙ ˙˙ľľż˙ęęęů˙˙˙˙˙˙˙˙ŻŻ˛ţZZ7˙üçź˙ÍĽ˙@?*˙ÚĎ’˙íŮ”˙˙ ˙˙ÄÄĹ˙ ĹĹĆ˙ü˙˙d]=˙˙˙˙˙˙ÇÇČ˙łłłĎľľżüľľżüľľżü¸¸şüľľżüľľżüľľżüľľżüľľżüłłłĎđgammaray-2.3.0/resources/authors000066400000000000000000000013551255003167400167430ustar00rootroot00000000000000Allen Winter Andreas Holzammer Anton Kreuzkamp David Faure Frank Osterfeld James Turner Jan Dalheimer Kevin Funk Laurent Montel Mathias Hasselmann Milian Wolff Patrick Spendrin Peter KĂĽmmel Rafael Roquetto Stephen Kelly Thomas McGuire Till Adam Tobias Koenig Volker Krause gammaray-2.3.0/resources/classes/000077500000000000000000000000001255003167400167645ustar00rootroot00000000000000gammaray-2.3.0/resources/classes/README000066400000000000000000000000361255003167400176430ustar00rootroot00000000000000images taken from Qt Designer gammaray-2.3.0/resources/classes/calendarwidget.png000066400000000000000000000017101255003167400224460ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dtEXtSoftwarewww.inkscape.org›î<ZIDAT8ËĄ•[kAÇ˙;»ÉćŇ4IŰ(­‰­ŐV« ×ި­‚Ż}ńŠw*úĽ=ř`ż—7ńÁ ‚ EE-«/JmŃzÁVSlsßÍ:gÚÝn“(˘“Ěśýť˙ś9;+ŐÎ[šRćnßHř/+ Hާ>tg“ś9×ĺó0¬ď8‰·C?đż–w{ Ť “tÝ@b<‹ţĎń’Ŕć9U7:Š7§NăÉŞŐč;t±GŹ-(Ť@PÎfłˇ¸, CCč;|ąX ™áKíÇ+Wńńň„ÚŰ‘ůň/wďáëĂJ úĺ\.)Q,¶Ćž¬YI–!{<ČŰ’˛YDöďCăąłXŘŐ%ţ˝PMÓŕóůř §ĎV,ńf&°©J≚». ĽsŻX -1n<}ĘÚzĽ§GĚ©á0Á„{HH>_ÇË0Á4šŮ˝‹gŕ ‹'JkôéSôź9‹Šć&۶µvą\Čd23ŘD¸$ě`S˝#Xe•Â< äŕ ^8g(„ćkWQŕkĺµ ţŰˬ7śđ+i+WśO$,h~l }{÷A⇾äĆuČ55BßľđI¸¬ŘA”­¸WI±žLBç€ć×h©Q¦ŢÍm"^ť5 ·˘Ę[Ť–”I0,p±…ÚŰŔÜ.hüŮí†Â…ŹvZí%Ňé´ ĽľDš›V\˝q‚ë[­RToŰ ˙–͢¦ćÖÉ HžÎ¤'îy{Ť©ź‹?5öW–Ül+ł®vĄMň˛ńx… Ž|˙“o‡ЎöŃl)łějM(9_Whﭭ뎹ݞă^Żwfmm­4u€†í’7o°é·™aĐNxbő‚Áˇ™t:=ü 6K{ŞśIEND®B`‚gammaray-2.3.0/resources/classes/checkbox.png000066400000000000000000000014611255003167400212620ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ĂIDATHÇÍŐÝKSqÇńKş4˝i˘^ht“şň˘‰Ă9oÔÍ!Ń»Í=4c“ćæmę6&ŰEíytÓuPt]”âŤř§|úüŽç”[¦SĽa˛ßﵳĂ÷wTPý‹T˙-Ě×–aAv‹]űóUÇÔLöĆڬ¸;0€çÍÍzĹÚ%K†ŐÁ`N§33355==ŤÎÎN¤L&ŤŽâ;Żń)Ł•.N†5}ł·‡Lć5˛Ů,rąň¬PČŁX,˘T*˘\.Ik˘Ń(ĆÇÇ%ôxb?ľcł'đ{vSÄUtee/WW‰DD°ľ¶†ŤŤuÄc1$q<ź›Ăđđpú–=9A?˛Ç¬EµÎf3g µ˘_u°Ć Xü|.-.ÂfłÁh4Âëń Źaî|”·Xő‚ÝcÍěú°@MÜ<ßŰ‹-ťCCCđxÜ硢$e·%TLŮi8źĎÁ69)ˇÇV+ŰŰçƶ¶6¤WŁwzzŞîK÷–čé9–ŕBˇ€ÁÁAě:ěčŔAk+öµZ|Öëqd6W ýýýššRŕGě.»QqňXŚ•Űí†ÁđŰüH MM8hiÁ·*Ôn·ĂĺšU`ëΙp‰pŚSŕvą ăýýÄ+߯ŻÇ.ËUˇbý~ż[Y÷_ár©Ä KăeµXhlÄW.)+h_źtęšN§±°T`Ëąđ^ąŚÍͶ¶6‡12b‚S>QzŢg»]ASś ,BˇĺÚ`q\şłłŤd2ÉS†•Óa0ŕp8¤_’Nĺ‘/ üňĐĹđŘŘâ<^Ż>źO:⤉÷>ß3©@Ŕń° -/! a>¸nPýö«df]©†ĹsXÇôň"Ë%2ËűÄ~M5¬–Ü:ů›»/Q—ĽOěWWĂWý˘•×käýu üŢ 6NMĹŢIEND®B`‚gammaray-2.3.0/resources/classes/columnview.png000066400000000000000000000010061255003167400216570ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<IDAT8ŤĹ•żjÂPĹ?mšP´…‚RĹĹwȢ¸»|ťÝ}€>‚K_ÂĹ?¸‰‹oŕ ‚‹‹T!ţILnď±7!ęŐ6 ŇGĽGňËń3|ĆctĹ„¸ąăÂQäŔ  ­VËj·Ű4ŹÉ¶íP4\—N§©\.S˝^Ď!{ŞŐjl00ţa$w»]V*•0[ŤăhZ(¨ŮlŇ|>÷ZärÇźd×rd•J…¦Ó)ŽŻxy.‹Ě0 V­V™_ťN‡M&v.YŽk—Ë%Ëd2hüîýP‡Ăábnűý^:sYžJĄHQďě-Ëşěv;é Żĺ~ĆMđv»•®ĺR°iš‘Á~ĆŻŤä˙? d˛§âVţ§ĆČÇ ”_€ĂîWš¦ť€?K„ďŤăĂîŞßď}.h>ź§őzí}€€Ăát]§d2IŞŞnĽŮl¨×ëQ6›ĄĹbalŹFŁĆjµú $”ĐĐŮlöÉŹ–<ę˝pżqc úYüa„™Ü_*€ ń>ŚÍfşŤIŔý޶…ďŁo}ě€őµH,IEND®B`‚gammaray-2.3.0/resources/classes/combobox.png000066400000000000000000000015251255003167400213050ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dtEXtSoftwarewww.inkscape.org›î<çIDAT8ËĄUMOQ=Ó™v mŇŇ©-* 5LÜ@bbŇ‚văźŔ„°ä7â‚ŕ’#‚ FtăFŁ&JBâB±`K[kÎçó˝ůbĘMĂL^ďžwŢą÷M…t:˝7::Á9B R©T_ …»,2™Lź ¨ŐjçĹĆŕŕŕmÇ8ŽĂćć&JĄŇ০¦8¸ÓdFdmm ˘(šq(Âěě,666ZÖ „Ź`đ˙{¨Ş¶~}}ů|LÂŐŐU¨ <0ĐŻçrÓ|ŁŃ8»0ô•eKKŹP.•±¸¸ÉÉIŚŤŤann®mŽ IŇď™™{ ĆÄ_iĂ0ĚQ­V°łł•gĎ)sóóóČfł(‹íĎnźPćÇă=ČĺîŕĂűʍ×ëŘß/cyů)’IÉÍáůů'điP]סiĆÇ'_¸ďţć ݶ/_Ľ*ű€j&¦mvך‰:łşéK‰$Ť5ş‘îÚH$â8ôo}Ů“7„»Ä“’™čÖ ś“ŰÂŢĽ;ĐŔÍëýHDExëÔ"Ĺ!Cňr¦Łľ>.~ĆQSATäL2-Ŕl§`0„^ţ;¸˝Şµ€xšŤśh'ÝöĂz0RPŢĆX`IIÂô­a·`^ëI×}ľ¦ó„9Ř×n  ¸»‹…•R©ž6,‰]Lvܵlđć|”Ökâ ‡X7â—Â0ĄÓ†F®u¤ńŃĎOPµeě•Ď¶Ž‹Ĺq5Z@ŕWµ SçÄö‰ÉŽY‘¶!G‚ôĘ«­Ĺc ¬ůYĆČĄx[m GsC·{Ú{1(0µ2˝ć¤ăúź:żSŃ{±ŻĄNßČÓq°ńý]s˛ź1«0[‹HÄş;ŇXŃh”­LäVĆěKĹ€SҸŃ÷ ¤ąe¶źu­ ¨%ŽĚ×­9 tŔŃT›ž^˘ŔŰŰ_ßćó˛ôźÁp cÎÚŔ;<ßgΰ掏Ź044üĐţ )kP~´/ÇÔIEND®B`‚gammaray-2.3.0/resources/classes/commandlinkbutton.png000066400000000000000000000022701255003167400232230ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYsbbË<tEXtSoftwarewww.inkscape.org›î<5IDAT8Ť••L”eÇá}î€;ƉŔcQcÁQăť[mͱYr”sµ5JX˝IwCĆ_‹ĐW´0¦k*ćşUgÍ˙$SŃN“ttp"Č_“?RŤVk}{~/ď1.ęŮ~{·»çýĽĎóüľßďăŔkµR†7/Ay®ţާ?ŇŇŇT&“iŁŃh¬HJJjMLLś2 ÓńńńqqqŐz˝ŢăűżŔÉÉÉzíÎxůqä=„݇ ťöCÍç~(Ř·Żä‡"u}$˘ŁŁű#""Ś´‹Ó„””KęłĆ?vŐ†âôµ\*Ă­»6ŚĎtbě^'\ă6tő–ářŮd[«Źü3<<Ľšż«ň&hćÖ'đQK. ś˛cpŇŽ ;‡ŰŃÇŽ›ăv¸ĆěčµŁíŞ˘ĂZ<ůTBBBę9ś-ÓöiĄuÍ´ô¤ăƨ„ëĂľ’pí¶„‹7$\¸.áĘM Ž> ßöJ¸ě”p˛-’G†Ţ×étÜDz¸QÝ´ýŹĎ3śýa3.¸DśďŃéŃÔ%bňŢnŹöŔÖhEë-Í—EŘÚ7aw˝€—¶i<ÂÁA `}EĐ# ¶.=šşÍhüÎŚ33N4fbö×Đsâ†,|ÚnĆ©¶ °Ĺˇ°N€ĺ €Ř„5Đjµĺ˛,•c¨ î´ľťˇ®U…cç"ńI‡ ç ĽQ*`{I$Ć~Ľ%C‡z•.ÝĐmĹ’RU`Ś}#ź1©‚Jyß4Żjęt9°%'Ű«–Bł‹„E0‚pDVůQřP ÷„’řó«üĐÓ{ ]ŽŻ±)'€h9ôé 2tśC7.čŠRŠĄđCź%P·řßŘCÍáÝ_ş9O€źF¸ĎUĽtK˛‚šH)EBŢ_ uëÔÝýˇašxĹ.ÉŠEpĄ y5(m_Y)Aź[1ÝÁĄ yźlJŽ"ń“NIRÔ}ĄQăĘöcC=Ţ Ę˝DBŢ'›’ŁHü¤S’”Ň}j”nŐdĄŐóRóZ«Ţ¤<×*ż3Oďţ÷c˙y‡×QfIEND®B`‚gammaray-2.3.0/resources/classes/dateedit.png000066400000000000000000000012401255003167400212520ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<IDAT8Ťµ’OK[AĹsgć©i0­.lˇ …„¸.ýv‰Ët#ý.ę˘ëBÝřJ˛h–B»ë*´ËRˇ"őĄ …JŤĄ¶úňŢí"y&)⌆;ÜąsćĚáUĄ‹‹‹o2™Ě4@ŁŃx»°°đ3pŃśśqg:—Ë‘Ëĺ¦Ď"˝Ěś0ŻGOeżäY2L˝^ď9ëĆysúdßUĹ”Főů§1¬ďíńóč+½áaŽO`EÓúśŞi̇í-v‰Uą“brě.‘*/ľĽBçöŤ T¶›|ýµEʤ2ž! ţ€Źű»ÎâÄiĚI3¤BF|Čź0¤žđîŰ'î§' ÔŽ q`-"‚‹ł‚·ď,ÎXšQ@¬1Í8ÂE‚•ÖÚilţO źŔČ’ H7˙rě…Ag,81i{¨Ĺ 1QÄ( ÇÂÄhUĘĺ˛ö m®v*LKĘňňň9éşłłł§\ "=‡—©“Ź:5ŮwsUĄR©h±Xě‹âJĄB±X47¦¸ÇcčřÜ]k;YjKk@Úýő÷˝5Á•=.ÍOő_1d™[Zëé÷Eq~|ŇüůńŤ«Ą˘Z­jˇPčK*ŞŐ*…BáćRał˛˛çóůľ(®ŐjĚĚĚ|ňJ˘ć:hsy¤Ť1¬®®^›NS‘6€Ć€ŰŔ-  eŃU Ŕ đ8ľ˙© UYĺ‰úßIEND®B`‚gammaray-2.3.0/resources/classes/datetimeedit.png000066400000000000000000000021541255003167400221360ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<éIDAT8Ť­”OlTEÇ?3óŢnw[wĄ%B›Z(H\@Ť j­"‘•‹Ę˝ŔÁ I ńHBL ˇ˝Ń¤  <ÔP -˙Ą-úϰmß.íŰ·ó捇mK!–ßd2ůÍüć›Ďüň›ÖZ–ęřń㿥Óéťžçý~řđá6ʨRž,sfg&“!“Éě,gú"y€řĄnű‡’ąpáÂS{KőĽ<»/+„µqşÎ~ßň%RnML0=7‡’’úTŠ­MÍ()‘˘t9k-ĆFô 1žËY˲d‚ő+Vb¬ĺčÝSŘĎłÂ@[†˝Aîç‡Hş1’i—„Ăş3ôelj9 G*ŚŤ(†‘ÔÔş_k<]äüĂkšAŰ'ĄX0Ž)…”G*%q•ÂuqÇ%¦@d#ÂČŕ‰’ĄqĎ|Ön>‚Ú„%]ĄIĹ 5aŔ•T9‚G ¤ŻˇY@ ‹‘ zˇĐÖŇŮŮi˙/Í{Íw…(ˇtuu=§»ŔXÁHˇ–PĄÁM”µŹcÇŐţęŮÓöGÚÓ ŤrÝo¤ýč_Ő˛ń§Î1žÓt¬ËóÖ›o” 1ˇ!đ}Ś1D‘aCćuöouĎ…::P‘8H4bŹŤkWډ(fýÂbE†mVa‚ŔŽŠÄW†±< ‘d§Q čPŁŤ”ŠP‡Ĺ€©é,ľďS_Q ͦŠÄB†c"BcCŤ–Ţ+˝ŚOŚEFč˘FĹăB¨+§dž±ÇU$kŞIĄR(ĺ ”ĂćM›ůîŕל<ůą\žT:M}C=#3’ 4—*ż˝q ĂžŕŇ­‰Ň?˘“ŢŁ×(&4ím$ Ą¸<8ĹĐt„1¦_˘»»;Ú˝{wŮ—ç‡pěĎéę?vÔňÚÚŐ(©ŠAĽ*rł>=qťéÜ,ąÇłµŕ./P>«ŞWďóŐĎW8tf†ďŢa{k ţ\)55/qńćGÎ<ŕź±ű[áčOfP{öěŮlYÇ%:?Xä×^ëľL¦!I¦!Ž’ëcE®=Ě#ô źµ&Řľ&Ć®]»ęęe@r>ĺĚŲŐMjÓߊXuNĽhÎůQsőô ;3ň70 Ś˙Ô‰>Čŕk‘şIEND®B`‚gammaray-2.3.0/resources/classes/dial.png000066400000000000000000000017221255003167400204050ustar00rootroot00000000000000‰PNG  IHDRójś ČPLTE˙˙˙ pl}EWf9&*{ŹRz‰\17&/3":E#\Ž^w‰OXi6DO-29%}‹\h}:,3+1at4^r3/4!l~Eq€N08*0l…6&"+DW`p;u‰Lu‰N¨ÔD6C+6ŞŐG˙˙˙CTCVGZz›2~ť:Ť˛9•­`–ż>źČAˇÂW§ÔD1>% ŞŐK¬×O±ŮZ˛ŐhłŮ`¶×n¶Űg·Üh7E”­^”ş;_w&•Ľ<–˝‚>Ż w‚ é®ŕO­¸Đ4Ę41f¦M2wƤ*ŠxVĂÇa¸÷bôođŻ·Íţňb®Ş¸ÎTeĂ+NmµÝ:Ąfu9ůaĹ6o˝Vʉ–Ąß¬ŘM÷ĐzŇs˛_¦rĆ‹Žéî_ű¶ę9^QCĹHdÁy­yt˝6¤Î“cÎĹ7Y˛şęYţ°=µÎ¬×u‡DÉíÍĐš;—7'纡őĹ `ÜB2ś,Ô¶nŐÝ‹#"âŰőÓWŮŤ3s몏¦zl…Šc´ę ˝iK‚ ˝;c$ĽüŰ<÷„Č€  Z!Q’•¬TÉöł>[nĂëuß’ĽäyS_×TpÓ=Úł1—t6 Í|+čjLż«tńK¦ĺÜ© ±Ű'±Aß_ź@ąe‘TˇÖ(Šxȧ żî-Ť€ŽŁ0H¨ĚoF‰ŕ•$ËiŃý<ě¬.ĺś—Ő"ź~Đì»ujIEND®B`‚gammaray-2.3.0/resources/classes/dialogbuttonbox.png000066400000000000000000000017531255003167400227040ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dtEXtSoftwarewww.inkscape.org›î<}IDAT8OŤ•ŰKQÇżgťjwu71µ´Ô5°‚.DRF‰‰] ę!čFőPDőŇTP˝D/Ý ¬„HË®ZV«VFµnąkä^\wvfNçĚěL3›Zż=sÎśó™ßů~g‡{ľVTT¸.J‘rQÓ8MyN-ăĎź·‰ÂňĺĺéÇŹs+Š’\HŤ–ßj}šěSđy<´{>¦cZPÔŐŐEŃ'ZˇÖđG{đ]ô"“Pä\hyÉAc3c€|?‹Áô. ÄľˇÚuÔ”±(Ërň`űôŐŔD2»Tş1‡l‚KČ1KĘ[.ťm$ˇ/řF_Ŕ/ľ…;8s3+G…šç(h`«ŕp0)GüS/¶Cä䀲g†Ţđá^ŕ}„mĐ|ŹsV솎`«×ČHKCŕ^l;w@IfMnŁ8+ á@?úfÍ)*´š—ëô 6Fç@Ú}·Nł±®ř°úvât"2e2Bź{‘öދйó*TjoGF?ác™Ł°Ŕ0ĎĆř–ćfŻ„Ç˝Cń0ŰAůÔȲO3tµ/Y &7~uvBĽx ±ÖVWŻ#pů2|ŃČšj‹yĆÉOśČuLG®ý <çŁ4oă_5jßµ]^HŹCË©2»Nm6Ř·oÇ/ŻÔçC‚۶‚ş\Ć<‰›Č5Ö¤°ϱJi°ąĂý$Řr™-nk3€’$A–dó‘¶ž$˝NScčÍDnÜTˇŇڵMĎJ×”Ô¬Y»†9ÉÖČšę3JáćŤ6ß›ˇr”:Δ,]Zv٤¤d…Âżĺ#iý@šÇ(ÔźQúü‚ď7ÄľďkľyIEND®B`‚gammaray-2.3.0/resources/classes/dockwidget.png000066400000000000000000000011761255003167400216230ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<űIDAT8ŤŐ•żnÓP‡żë?ąöµ;$HH,lĄHí” ¨bŕxˇ´+bB¬Ż@§<Rg¤ŇŠ![ťX*ѨŘqrmr/Cb+vHT!eŕHWÖ±ÎýÎO?ź{-¬µl"śŤPˇ”Údqzzş°§µ®˝xőń>—Çűě]Ü)űěş®¸ßď׿ůü°Út×Ř;şŕő“ďë—Đ««ŻXki·Ű¸®K’¤h­ IÇc¸ą˛˝ýËă}NNľ­—a-(áş.yžŁµĆq˘( MGµú&Ç™L&,®Ň3Ďs ĂcLŮÚŠB µ&Ďs<Ď`÷đś&gĄâ8žAFŁ c RJ|ßÇC’¤1«Z»¤Xt»ÝÚÇ  ‡?)Š‚ŰŰ_!čtÚ!H’­s” QJŃnß ×ëŐ=.Šb…Ƕ˛ ŽŁą9Z縮C†,^MŽS‹«ô8Ë2¦Ó)R¶RÎĄ5›˛,`çŕŚ&ÇËóĽÖ)ś?Çă BĘÇ4a­% |ß§(~3Of~ A“ł¤xńpDQTm*ÇM)5o”Tu_Ţ=]VĽĘăVË'ä_Çmf“ˇŐňWz,:ťNm*ĽřđOGúÇűçë­( ËŘ=<çńËOUľspVËËÚ&GH)7s;Žłđ÷Ďű˙°M®–Ű7IEND®B`‚gammaray-2.3.0/resources/classes/doublespinbox.png000066400000000000000000000013551255003167400223530ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<jIDAT8Ťµ•±J3A…żI‚h0ű>@ !6‚•h%ľŤ‚!*(¤$(°×ưJٶZdĹNAÁX˛¨ ş{ďüÍźeăî&6.,w†ť=÷Ü3çÎk-ń¦Tµ)"UEUşăAóŘصÖÖÎÎή ŞÚśťť­”ËĺDć~ýüÖn·+§§§M`2 "•rąĚđđpô ‘ĎçÉĺrcPUÂ0äëë‹ĎĎO>>>xçííŤN§C§ÓabbU­äţ3îÉüłÔ0 ‘Dô}źíím|ß'‚čźHă8p–~?clmmáş.žçŃl6Ł„ăîä· ŞĘîî.———řľĎŐŐŤF0 Ó˙TD¨×ëěěěô8%ÜŁ±ŞňúúĘńńqôää„ýý}žźź3+KHѶÖŇjµ¸ąąI0]XX`ii‰ŁŁŁĚĘŚ»YD„ĺĺeÇI°r‡R©„µ6S®LŤ»‹¬µ©¬...™™IµÖ¦kKcőôôÄăă#sss™š©±ŞŇh4¸»»Ł^Ż#"ŚŤŤ!"¬­­áy{{{mI×xss“Z­-zyyAUiµZ™Lă–ËÔ¸źwăńđđóóó¨cççç©V«éŔqťűŞ*ŐjĎóxxx`||ś•••ě–ţ-¨`ŚaccééiÖ××1Ƥۭ{¶ĆĎظC¬µ=cUedd„ŐŐŐľ-í¶ŰmJĄŽă0::J±X¤X,öśĎ…B|>Ź1¦Ç÷AđýýÍýý="âk-‹‹‹Sa6Uµ2h×\Q.P»˝˝˝6u™ţŰęądbŹ[ÉIEND®B`‚gammaray-2.3.0/resources/classes/editform.png000066400000000000000000000005351255003167400213060ustar00rootroot00000000000000‰PNG  IHDRשÍĘPLTE˙˙˙@X€@X€/A^Đí˙Żá˙gz´ă˙äö˙—Ř˙”×˙Čí˙Íě˙\wr}Ôń˙Éî˙Üő˙YvÖň˙Zvdy˛Üí®ÚífyÄáíä÷˙P\aĽŢíĘî˙Íäíćö˙Ůň˙o|č÷˙IZaq}Óćííú˙V^a úŮĽtRNSĚ#/x ¤%ÓYů„IDATx^µÎ·QCQ<łŹÍ™śsú˙¤qaQ ´ÓśâăŃŔ‹ "0©ŞŃĐ—ĺF4Šb'–Ms“Ďçc#ú=»ňÓÜm×í†Y’,`DĂ9ËÖp˘a“¦;8ůÓÜgž†S]_`DĂ5Žďp˘áѶ/80÷뽯Ą Ż,ßĹIEND®B`‚gammaray-2.3.0/resources/classes/editgrid.png000066400000000000000000000005351255003167400212700ustar00rootroot00000000000000‰PNG  IHDRשÍĘPLTE˙˙˙@X€/A^@X€\wgzr}”×˙—Ř˙Żá˙´ă˙Čí˙Íě˙Đí˙Ôń˙äö˙ZvÉî˙®ÚíIZa˛ÜídyĽŢíÄáífyP\aĘî˙Íäío|q}ÓćíV^aÖň˙Ůň˙Üő˙Yvä÷˙ćö˙č÷˙íú˙5ągstRNS #/x¤ĚCČ>ą„IDATx^­Î·QCQŢĚâÍ™śsú˙DräŠÓśâăŃ‹ Rp­Ş)‚Â0ɲLaŘćyWćq<+źçcSř=»ĺ÷Ü{Ű.†sQ,` ĂĄ,×p…a•$¸đ÷ąŻ®Ű!( ŹşŢÆgÓŕ Ă1MOpaČÜŻ÷ăIᜣv6IEND®B`‚gammaray-2.3.0/resources/classes/edithlayout.png000066400000000000000000000007071255003167400220310ustar00rootroot00000000000000‰PNG  IHDRŕw=řgAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<YIDATH‰µ–żNĂ0‡żs’©}¶ľJy†ň,Ll”Ť F$–ŠW`ŞÄĐ@*1 ńGˇK;0CRbÇvU9ÔR$ç>ťď~ľsbQUv9ĚNWňőd˙đě8hńÉýíéy*@UQU†ŁńěyĄúPVĎÝS©ĂŃxôR™Ş6 Ę}Vóéőĺڼ׽8Ȥ™×Łß…9Ś@fšů07ŔÚ N&,«í!– h€y rÓ8µY!q–GŻ ¶ ‰ĚSPřĹęÄâ[(d sd@©A*s*Qv–Ć*d„ ľźWä˘îCŻS¬,Cmşť‚z/%e&Ö"óók°©×  u[ťëČ{5¨3ElźĐb˝žČ|±NIdN€ŻĹ77WŐ÷üíu :3;ŔäčřÂz°ř?Ë ±o"ŇŁúőkÓxWŐU2Űőµĺ+l«ÚËŚłôIEND®B`‚gammaray-2.3.0/resources/classes/edithlayoutsplit.png000066400000000000000000000015341255003167400231040ustar00rootroot00000000000000‰PNG  IHDRשÍʡPLTE˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ŚŚŚ˙˙˙@X€yyyššš/A^˙˙˙›››®®®@X€E\‚I`†j}›gggfffŤ“žŽ•ꛎ¬śŁ­ ,,,Éë˙,,-,-,-,---,444;;;???]wr}”×˙—Ř˙šÚ˙žŰ˙˘Ü˙¨ß˙˛ľÇłÂËÂč˙Ćé˙Čí˙Íě˙Đí˙şĺ˙o|;;:{„Š~‘š’š“š$$$ť V^aťŰ˙žĄ¨žÚ˙Yv˘»ÉZv¤Ý˙¦Ţ˙\w­ŕ˙®Úí±˝Ĺ-,,_w´ĂͶä˙şŔĂaxľć˙ľç˙ÁĘĎbz…e{…Ćę˙Çé˙k{l}…Éî˙Ęî˙Ěě˙Ěď˙m{Îď˙Ďď˙n|Đđ˙Ňđ˙ÓćíÔń˙×ň˙Ůó˙Űó˙Üó˙Üő˙Ýô˙ßő˙âő˙äö˙ĺö˙†“šq}p~…ćö˙ç÷˙č÷˙U8~Ş.tRNS ##$+/3GMOU_rxxxzžŁ¤¦ľÁÁÁĚÍÎÓŐŐŕěďđđđđˇkm.ąxIDATx^­Î7Ă0 DQ” śĺśsş˙ýlcPí Upô[ŕ>BFĘŔ÷hŘȰ®ŔśI†M lečö fëx‘d˛€ĚxîóÍ˝¶`«ą·ě4w™ţe?rŇ,™>÷óÍ}A®ąď(4÷\‚™W®Óőź ÍAşIEND®B`‚gammaray-2.3.0/resources/classes/editvlayoutsplit.png000066400000000000000000000013441255003167400231210ustar00rootroot00000000000000‰PNG  IHDRשÍĘMPLTE˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ŚŚŚ˙˙˙@X€“““/A^˙˙˙«««@X€E\‚I`†j}›gggfffŹ– šˇ«äö˙"""===˛»Á'''_z…u€…zšŚ•š–Ř˙™Ů˙ž¦Ş¨Ţ˙Şß˙±ÄĐşżÂÉí˙Ęî˙Îě˙Ńí˙Öđ˙Ůđ˙656ĺö˙éř˙666'('q}r},,-x~-,,-,-”×˙111—Ř˙™»Đ555556565655®Úí ˛Üí999Čí˙Éî˙???ÍäíÍě˙IZaĐí˙V^aÓćíYvZvÜő˙\wćö˙č÷˙o|íú˙Ôáb+tRNS ##$+/3GMOU_rxxxzžŁ¤¦ľÁÁĚÍÎÓŐŐŕěďđđű6oFIDATx^ťĐUSĂ@ŕ@I!…”ŇPÚ’… mĽî.¨»»Ë˙d÷&eňĆ÷tvîěś™ĂüG@tŔA|ą°TkU+‹n8\m\qŻô$rp¨íůRůş\Ę“ř,ňp8{ĹR™‚®ë…L ç;8XĺHJś á× ínŽ÷úcíýöAďč0ć÷ňZăÄ4uQ‰m­Bś‰éBG‚,R„˘´U«wÝYA袂č2 #R ®ŠéJB@:PNÚE)Ô´ĆÄ©ť¤“čL23ďÍűş×çĄ3“11Hű‡;çr~÷đ?ç<­···200á!$Ą P(LMLLĽ`¦ÓéŽL&eY<¬&'s/ &   ö<¤a é: Ń?€z Ü ¨,,Ëçq€ŮC‡ Ě7¤«]˙_@_^¦zęóŮ,—R)–OśŕwŕÖÚëenŰľÍëßźŠ¸žűŤAÉ÷]ćĆ/ˇ}=Âb˝ÎŤˇ!Ž;F>ź'qć ŻĆăĚĚĚ´ŔÓ¬¤’};¤"´KAW±Z.łpţ<žm3ŢÓĂ›°˛˛˘ţ‹‡ĐËÜb„ÔiŔçżř’X©Ě/¦IćÝw0Mß÷Bhڦ4ÄVŕ° µ ~Ĺf_LóŮá× „Ô=c.—[Ú.‹”Ę%jçÖm*W®P›ĽĆöj•Ўsä™§Y)® ¤ :‰GŞßě ŕ_çncD @k6¬|o‘ëŁy¶ZæÍőÇH÷÷Ń›Jˇ:Ve3Ěş®ŕ›Z1˘Xµ: u¤öóüsýË1Ťrpd„îîn”h€¦›xľŹŹÚÁęĄx,Îwď´{˝ş†35…ÜčK‘Ö|–˙Ľ§HTt=ʍi¨~ĐK BHťťětęę.Ąj•ďľÇp¦cQŽžüP=ŢhŞňWhš†ç{„ţl¬xqq‘ŽÄ#ŕţŐj,]»N(drř©˝*2Ś4ďĄR ×óń=ąŃ H„/±-€Ú7çXW»şxűýpë>›I‰ďű¸® ë­5łt…€üťĽzDT-ěěeîj»Ţ:BŐ*#k­Ąáź¨*§9ĂŽă˛Ícő˘m[Ģ1$’zX-u‡Ëűöqrđĺű‹ŇZoˇüU^+E B°‹Ü¬âµ›łtö%±ç¨ý|•l4Ę{ź~B×cÝlµöĺŐżX*.o^ńÍłg)}{Žů7†x|lś¬$Oźˇ;pę.[HMďą ÜVqhÜyü(?ýp+ÜŞń'vńÚDZ{÷“ŘN!µľRČĆ˝1rÍ\­Zöí¶ÍÓÇ’Éä+š¦‰őß ”EęŢ:ĘgTŤśňŐŁ={ö~><<üŔßJusܲ˝uËIEND®B`‚gammaray-2.3.0/resources/classes/frame.png000066400000000000000000000013211255003167400205610ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<NIDAT8ŤŐ•ÍnÓ@…ż1q‚“J%Í&?RbÓ Ľ˘OŔŰ€ŘXŁľ<V¬XUvęĐź (JRÔü9Í 77qŇv]p%/ÎśągŽç^_+c ÷Ö˝¨ęé«Ă;-kc0ưşIJ),ĄnÍËü8xţO\.âŮ믉0ŔË÷_Đ:ńĄ”Âq˘®cL&wđ0ťN™Ďç|z·żt  µáÍţ˲ŘŰ{BˇP¸^×1Ž6x€Vë'Ýî%>;˛–*ž1†zÝ]Kj‰(°Áw:şÝîĆu¤„kµĹbQđůy›^Ż/¸R©¤ř‹‹ßśśś Îdl g2*•˛ý~źv»-xg§HµZ<Oh6›‚Ç!›Ím głYY‡DQKpˇÇu]Áóůś ĐZ`Ű6ľď±Ú}"ĽXŚă0lJR6kăy–•l5Ćq_ç)<Ż‘2–^: ™Íf iYřľŹm۲'ŠZ\^»înŞ7 GQ‹ńx,¸ŃxŚă,[¨ÝţEŻ×\.—)•J‚†RÂq˘V« î÷űÄń «§•J%Ęĺe‡ŚF#ŽŹ#ůŇňů<őz}_ŤŤé¶µµ…ëî¦^/ ĂT1}YĚż>~SÂą\Ďk3­5aŘ”WTJĄŠ©µ&Âż™J) Xß–÷8ťNąşŇ€#gľwÖxłÂ/[N„?ľ}±~+·zmLňhÁ\ˇJBaYɰżiŕ«˙îź÷¦ D'-;bIEND®B`‚gammaray-2.3.0/resources/classes/graphicsview.png000066400000000000000000000022361255003167400221700ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dtEXtSoftwarewww.inkscape.org›î<0IDAT8ŤµŐkLSgÇqMöÂ7˲,qY˛™ěŞ›nŮ&›Óev#ÎÄ[Ü A)”r)ôJA:[.ceĘĹŇ–‚íiÁZ.[ˇ@„2ĹEś`€RVˇ2iKíoO»­AĹ,kňMú˘çsž<ůçßUVý­čG±±±ë eaFFFÓ†Ůlö‹rye‘´´cćG]&öB&Ó‚ĽäµG†ăăă×Ë媲üüľ™}L¶|đŇŇ X…Ű‚NXś””´Q&Ł”ąąý7÷îwŕ…םŘtĎo›DŔÎiäKt° Dů`S[1âââjVH†Ďmpaí+.Ľ8ŚÓ&çć`Ó.¶ěv"R0…†‚áôřľň,D"Ń,9őę‡ĂňkŚq;Řo ¦qxWÖ‚Ýţ.ÂU||ĚC°ŕ6˘Ĺă`Ž ©x2M‹÷:Ţ|(¬¦ôÂŘÓ;} çÂK5†"ˇý}|-W"řđ©ř˘Ŕ=ÇÜ8î˘É†fvOSÍ#˝ş,LFh÷”¬–Odd€™Ş&űŞË±çř4Á€¨r F ”¶;ˇ6^F+őć$±—ťŠĽýÂîü$´…BČÜŠČbÇßĺB\5ŻřŤ€kÁ mUDąUý‹{űîľ°˛±˝?B °‹‘ž•ž¤Î‡%ÖÉ @ p›!Ű (Ť* Ű™%‹á;¤·–ŔjMőÁd±ô.pŞ'!<îÇxgČiĎ‚6``ě†ÖvM")Z {3-y<ŢÓĹťn?&ć~~łG/yPŇ>Aë?|J_‹é™ywÁ;RuóŕŐÔÎÎÎoÁ3ţ7Ôušň3]·Úq$˙\±Ž˘HkÄĚŤ›•¨q¤ő:†®ŮŃŰŰ ťĆěě,tuFDËńećOčéB¦0çśŐjćóůŤ~¸©Ĺh¶ÓÉđv±*•GŔ¤Â>ÚJ] ť‚‰±«Đjµ–«@ť¬Çüü<á‡q˛ĄE%RÄTFk5ÁxÂkT𔑦>řWEŚyř˝Űąą[P*•)”č3[@Q¶2ř*Ëď'Šs×§g‘%.ô^ cÉâp8Oö´•aśćâşN§©\.Ě–ßP*•á=‚]ęMÓŘĽ_‰ř‚frbĂŇa겠Łăg|Ć®÷ZÝÝÝîš˝şúZ»´Lę–H$Ľ§ŃŐÓžą?o“{íCXš —Í#šš‚ Ź}ľŮb2ĎŃ2$Jšqkn6›Ím±X†Čb+¸wˇżMzĘű˝¶¶ös&_|ńCVX‡dx'B‚])'™ˇ'[ŠmáąŘsÂ?!uXEEĹ1˛ý’ÉŻyŕ"!“ö[둟ҾۣƜQoÜéÝ@©s˙$±ś …IWĆ‹—9ísb1që)˘Âą ,ŕqi“†ĹĚp®xaBş‚+Ô0)ę(łO•°‚5;”‡°źo¬cŤĆ˛Ţi ŕp€Â` u䍶ŮEćlĎâ»|˛9îŹř?”!Ó_ńśÁ"Ł^? ŮmH€dłřqgXN›n $Ăä–XQb—Ô±kźjY;b^šUŞT0¨ Xđ¤Ě”dßĘ`P[°ŕńźäš‘˝ ŞIEND®B`‚gammaray-2.3.0/resources/classes/groupboxcollapsible.png000066400000000000000000000012761255003167400235570ustar00rootroot00000000000000‰PNG  IHDRójś 2PLTE˙˙˙===XXX555333}}}RRRşşş»»»ąąą&&&>>>DDDččč‘‘‘§§§ÍÍÍŘŘض¶¶EEEóóó÷÷÷®®®ďďďIIIŐŐŐťťťžžžÜÜÜYYY´´´ĐĐĐ×××’’’ŃŃŃäääłłłXXXăăăęęęÔÔÔáááőőőffféééřřřâââíííŞŞŞŰŰŰŁŁŁĂĂĂŻŻŻŕŕŕŮŮŮąąąÝÝÝŹŹŹAAA¸¸¸eeeOOOţţţ¬¬¬………ôôôBBBúúúĚĚĚüüüŇŇŇűűűÚÚÚŚŚŚ™™™RRR­eó€$tRNS &M K:G 3%gŘ=ČÎ"Ä=ZÄŚ3ÖL4IDATx^•ĐĹn1@ŃçasĘŕA3C™™ţ˙ę‰SEí¦ę‘źm]ye ŇĎ!ŠăĄ4LIe]×[-ť¸Ś ‰Ć °ĐrżőćĂŮÇ \\ÚŐgůýcż’Ę ĚíäfąÖĐr×{)řĂçńFoŞö9ÔĆŻoE8ăŃTŰOT»:đ¶JX…€‘ó Z´=‘ék…»ń‹#26űVÓ4m;oۦi5;ťĚBÄ8˛¨2=Ž­,B¤rZšž‘ńW#ÎJ\Ř݉+«wë7·1P4Utc|Ź ry-+°"3Š*˛„ËR˘Ş0°ş&'3a†p*śIĘ0ĺRđKhRCłx.€PśÔ8ň‘Źýń~ţ Ŕż|-®5ĹgIEND®B`‚gammaray-2.3.0/resources/classes/hscrollbar.png000066400000000000000000000006301255003167400216240ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<*IDATHÇí”1KĂ`†A°Ř.ť»Iő?ŘPĹ:ąŮAq­   ‚ *A\\âä榛N. NţŽ×÷•ű’ VhMiŕîr÷p—6ŹÄ˙AĚgŚŚ“™$eR€˛÷—ÜgˤKPodT%~ŠăI’üyč{%3§/˘(BçۆĄMC{˰şkXŰĎP¬ĽęTŻľŕđÉgSq†XŇőCCç̰wm8¸ÉP¬|N”Ę=nZHćwĄM¤ćŁ[Ăé˝áü!C±ňyń7ĎBωWv Ű—†ă;ĂĹŁáę9C±ňżLĽŘsÇýLüĂŽż&~)ř*şaÇş»÷‚îřś„«¨úÝ5ČiůŽúĄĺýŤpÇ.Ż‘)R'ÓP÷ţZřň†ňŻřOëUŇ‹#IEND®B`‚gammaray-2.3.0/resources/classes/hslider.png000066400000000000000000000013311255003167400211220ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<kIDATHÇ˝•ßkRaÇ_–Ëu3*‚.Ä »ËAEk]t.†Î`-¨Ô„rŽ0BÂF…!TBơ5lÉZޤ‚Aٍ±Č ¶«UŐżđíyÎyw`â…?Şäxž÷ăűľçű> â_ ţ›.a&Ú +Ń!?Űĺ÷¦†Ĺ<(%Ż× EQŕńx`·Ű—éY€č$,őČ«Ĺć`0řnęý9Ě®ú1ł˘`şâÂUđĂÂ!ĺćFſߏٕAĽŞ¸Q\tâŃĽŔŤ MĚě%vq]Łb+/˙uEÁłrÔO©˘ŔČ]C|„°q]Łâż\TPřěÄĂŹ7'†ď⣄ťëoeń‹˛‚ßřŠ3c?P†ç˘!>Ftq]]bşÚMÄOŃŧU]ě1ÄýÄb'ËkŔŃÜ"]šôš¨EěůĽ.>ő@ŕ;‰{‡ q=Ü"¶ zD"dłYM<9§ŕ‰OŢ×ŇĎëâń8Ňé4TUE>źß@ˇP@©TŇBˇ˘Ń(b±Ř‰rą’ÉäcŞíYźń6ů+},~ňVPÖH|0h,sTžŔ~ů"«ńű×gÜ&7ś÷Ą›ĹăoÜ+9q}BĎđĐeCĚŇ^ů»jŔQÜ­ąjĄblFA¦čÄč8eř¶Ŕ`¬‰TT·ŰŤĚ”Ţ.¤Î^Ą˝Ť´~@¬‡cnč’.ôSĚĽ”Ç5éR+GÚ"÷qµ*›kśśVšY¶EnŹű8%rů}ňľé¶i’łî”3łÉ=µÉűćýßükú`…šéE8#IEND®B`‚gammaray-2.3.0/resources/classes/hsplit.png000066400000000000000000000002441255003167400207750ustar00rootroot00000000000000‰PNG  IHDRą‡mđ PLTE˙˙˙˙˙˙~ďŹOtRNS@ćŘfIIDAT[c`@€Ĺ”ˇ9# ´j„ž Q •Uď"¸V­ĘZµ¨*Â4:@—‡é™ aćĂěŮsĚ}0÷‚§v©ŠwIEND®B`‚gammaray-2.3.0/resources/classes/label.png000066400000000000000000000016711255003167400205560ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<KIDATHǵ”mHSaÇ—™XÍ ‡2—‰S°QŤŚË$§k•a~ɲŇé˛ô‹} Z¤DQi‘ˇ)ˇ&jˇ‰ B/Qhó-(**{[ęÜ–ÓjŰżól÷Ú6ď¬>tŕÇ.wżťťsž# úü>Dsrrr ŐjˇÓéĽ`ĎU*ärůžŕŕŕůônŔżł5 ÚJwĂq˙$Nqčáč,FwI*{©źÄÉôůG9‹,ľ8^´ágËA7 »0U­†T*u(Šg±±±{Ĺbń’Ůä"NÄä “’’0u§öˇf´–Á䍴i¦j3aş{]z5(kc@@@6}g1×oĆÜ!„‰'š÷ă[ÝNX+SSµ C-çńća,U›ę¤zwËd˛MţĘ2CliČůćŚ]SÁTᦿé zzz0<üĆÁ{0uś@“>‹5s\"‘äqňą~ĹJĄ#U™řZˇÁ§ňŤ0^Mˇ±‹‡“““0żęĆh}>ÚŹ%łě{ĂĂĂg4ÔKĚę]ś…áËÉ.z›ÎNKů`rëř(>?iħş|\)Ü€çÄφňS±–5ŹXI8ë1PU„X­Vř†Ýn‡Ůl†ńĺS|ĽU;‡ăAÍ|Η…O{-÷`9QQľ ˝ %ř11át:©,6|xzçRfŹ‹‹{L5ßăšNĽ…GH Ńdë¸x–w}pŇß –9cjěúJqĄ@Ád&BĘ‹ă 7—‘D"QFŘ]ÖÂ6:ŚŮâő“»8Ľ= 1!LvśPxŽ“‹9—y«V-G×őŁřö占ôYG Ô‘X%f’ D&±Ćw¨e\Isr«91ŇV˛¦·ý^ŇŢŽjä§Ę tKˉ\b+±ÂWÁ¶'ç3_OÔëŇ"ŃY^Śďf—´§˝y*V-›–ćqٲAXę+Ž÷8óňhb;QKXOąŞ!iף…BË#‚ßĎ>r–y%ńŁĆqĺlR~Ž…Ä™ł˛d°†rńˇ’z-zrŹĚů†®ăJĂně6®¦^Rżbň”G»ĆÉ=ëJWŁ|¤-ö‘łećş]î›*¸ěČě´€'G«IEND®B`‚gammaray-2.3.0/resources/classes/lcdnumber.png000066400000000000000000000010531255003167400214440ustar00rootroot00000000000000‰PNG  IHDRójś ŢPLTE‡‡‡***‰‰‰˙˙˙DÁÁÁđđđčččěěěăăăÇÇÇßßßgggÄÄÄĐĐĐXXXŮŮŮĚĚĚóóósssŐŐŐĽĽĽĺĺĺąąą–––úúúöööżżż´´´řřř­­­±±±üüüŞŞŞĘĘʦ¦¦ÖÖÖííí˘˘˘ÓÓÓéééźźźśśśşşşÜÜÜ™™™ááፍŤYYYŢŢŢýýý÷÷÷čŮtRNS&M % :K "GgÄČÎŘZŚźíl¤äIDATx^UĐeo1 €a·9ĆŇ6çřĘ33ď˙˙ˇĹr¤kËŽô~ $;ĂM»m>ÂáűŻ)os}bş•N~{ńgšĘ8»=]iHO&] úí*Ç<§Ő÷Lö@ĺĽÄ˛¤Ő÷€óCEA«ďçç «ŠVßs·M _ĺŠóç‚ vÉůgź vĂy1#¨†Ýqľ_TĂ9?Ő"ÖX×/śgSÓ+e{ľĚ okú´ţ8Ţöő=‰#đcišě:„śŘíuÜŘI*‚Č‚Ž"…˝$ô|»ß±}/LţKp6ĹĐĽ;ÓIEND®B`‚gammaray-2.3.0/resources/classes/line.png000066400000000000000000000004371255003167400204250ustar00rootroot00000000000000‰PNG  IHDRn˝¤°gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<±IDAT(ϵ“± 0EŹ`0up°ĄC  ĹEJA×Ň˙˙štŚŘT(g=<î}yÁ±Č$š"€F!HĽśžc#K©—Ë-€ĹP Ęňé®+ŕ°”H/gŃ5ÔTdsą˘¦gĐ/eI‰ĄĄ Đ.cČŹÝ  dVwwZĎÜaP^ÎŁ_\Čg“1tLĽLËÉ,8şÇÚűýÔM¬ŕ„EĎdvČ»¶±ëD7}«/:-ţ‡O\IEND®B`‚gammaray-2.3.0/resources/classes/lineedit.png000066400000000000000000000006251255003167400212720ustar00rootroot00000000000000‰PNG  IHDRn˝¤°gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<'IDAT(Ďĺ’=KĂPF)ýM† ť:…d˙€] Öî‚«ˇ˘?@Aˇ›“““‹“˘SAČ!NviihAy\nK Iu—Ăs9.Ľ—ńwřeJT°qp q°©P‚Ňéů`ÖWXȱvS†4°ˇ2-ô˝‘‰łCěľľô™ &OBě±N¨ąR3Cş˛Ą§Jő Ä>>¸ˇ>„¦šj*LÖý^pCM2˙3ÎŘŘśwBôLů](Q˘D¬űm¶ü&)R$­^^Ţ#Ýd˱Fą`r˝*;‡zŐóu)DęŰ/ęŞ3‰-¨2úebNhÓ„2m:téĺŇĄC›,Şx4iáäâÓ˘‰GE™őÂ%u¨SŁŚő8íŔç«ěIEND®B`‚gammaray-2.3.0/resources/classes/listbox.png000066400000000000000000000014351255003167400211610ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMA±Ź üatEXtSoftwarewww.inkscape.org›î<ŻIDAT8ËĄTmOA~z-±´…«HŔ„¶~‰Iđż˙1ţ~>$G[#´áťB{×»ug¶{˝m1Ůt3ł×Ýgźťyfbů|^,..â˙‡€ĘÖë looó×Äüü<Ö׿Ę?Eo«ô ŕIľďűčt:hŢ4 ČŁßGˇďT|ţô%\'b±;—W—8óś<ŕ4ů$€AŔ"@hó‹;@ĎD"‘'Á`đ±eYIŕPěPÉב±!%KE%ß8ĚÂĽŽ{żřÇZ^^–$MNN*Ť H¬‹kC\C\Dť­J}Jéę»V=‹z~‡L–\`Űö ™cvvV---ި¨pj™_“3R$N". Ît›’_’"†€Z`?ô€ýˇP(˝°° ŐŐU---I’ܨˇIŇhfTÄŐčöŰ›˘‰5 PČ@BˇPÚu]ÍĎĎknnN’”H$t”ýtŁÔäS˝ůţZŤĹ=D šc@ŘŁ8‡ÓSSSš™™Ńôô´ŹÇôbvĐn`ń™şüľ^†ËEٰ˝ˇx\^^ţĘu]e2஫••őöö čÇŘ)dŕ•@ ‹qęđh0XčýÇ–eĄc±:::ÔŢŢ®®®.UWW čűmŁĽ8Tç€óŔ)óŃ GqP \îŤŐz€K^Ă[F}‰qBŘ„·±›¨łmű™ßďnYÖ ĐśNěS .‚ć>ĎŁŘç8Îđ6IGw?d˛¤é_a›}ś= 9(Î\ŔY’ 8k@r˙9 »u…ń{3pÇL´ŕĐ 8ßřĽ 8bĆA•ąÚ5ŘŔ}&@6Pl:(ě_4ňŹxÉů^IEND®B`‚gammaray-2.3.0/resources/classes/mdiarea.png000066400000000000000000000012031255003167400210700ustar00rootroot00000000000000‰PNG  IHDRójś ˙PLTE˙˙˙lllDDDdddQQQ~~~–––PPP[[[ŇŇŇZZZ...´Ů†°×€·ÚŠ¶Ú‰ňňňďďďôôô÷÷÷±×óóóřřřööö˛Ř^^^ŻÖ~ůůůWWWűűű///ŃŃŃţţţççç˙˙˙s¦˙ëëëŮŮŮńńńłŘ„îîîúúúđđđőőőµŮ‡äääýýýŕŕŕÜÜÜ·ÚŚŰŰŰÔÔÔăăăŘŘŘÎÎÎ+++żŢ—ÄÄÄÍÍ͹ێ“““üüü,,,íííŻÖ}ßßßŞŞŞťÍ`xď©utRNS M& G:Kšőńó%"đ‘đ˛ŕF‘–IDATx^•‘Őn!F™—ő2îëîuw}˙g)ĐÝfnzŃĂBľś|ţ‰®JŠ,Iúţ^ B̆üĐ­–M \ O‡lŕý–Żş¤V˝ ÔI#xázžm/ňś@Á)âd¦Çv;.Ń€ŚłŢj•FŃs7vś'búÜÝ„ş‹<ŽŰnżp7L°ÇR§ýnłN#ôŮ#!fŹ:i¶Iü9žLź‹ń5·çF[NxÉG”…‰ż=Ó9ăWž3w˝^Âť}Éí+–opgßĐXîÎBß§éô·űöÎJőóáqŔ Ýn?W4 •ë„ô†.şżV  š˘ˇYĄ–f@?2k͆X Ń¬™|Ú71O3M'L„ŠIEND®B`‚gammaray-2.3.0/resources/classes/plaintextedit.png000066400000000000000000000014471255003167400223560ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<¤IDAT8Ťµ•;H+A†żM‚Hvc!¶VÁ&­‹±K_`g!ŘX(Řk-’ÂÚŠŤ‚…Ú-6±HZX(6Z±2ł &;3·Ú˝;îFoăÂ2gÎţ9ç?Ź1”RüĆ—X__ĎI)óB¬”)%B<ů§}@.)ĄVö÷÷ )e~ll,›ÉdB7Ń׳b±ÝŢŢÎbBl&“ˇ»»Ű˙»şşÇăÄb1 Ă@J‰ëş|~~Ňl6©×ë|||P«Ő¨V«T«U‘Rf}*¤”ÚÍťBýşeĄ”/Äľ{ĆÍf“ůůůHĐ©©)FFFŘŮŮaxxŮŮY?"!Äżäy› €mŰ”ËeŢŢŢHĄRÚŮŃŃBŇé4ľ÷®ëF{ ńěě ˲8<<ěľišhG`ϨŐjQ«Őĺää¤#ß–eiş °—€Bˇ@.—czzš——žźź#“g𦦠yěÝâťźź3>>N:ťĆ4M"+ÂŁ"čqG*\×ĺéé‰JĄÂÝÝ\\\Dňě8ަ‹öh¸ľľĆ˛,lŰƶmúűűyçćć&Äłă8š.TnAŹŹŹŹY[[Ł··×8==eooŹŤŤ Ť’z˝îË^{GrÜh4x||Ô@… qyyIŁŃyümňĽÍÂÂ÷÷÷\]]ůĆŻŻŻT*Çauu!‹‹‹ĚḚ̌´´Äää$ËËË!Ž5*vwwi·ŰšW}}}lmmişÍÍM_ž•b¨Ąż2? %ĄTçŞđš$8”Rţ”ŁÖ(ŕR±X$•JŃÓÓeY$“I’ɤ6ź‰ńxĂ0´ˇŐn·iµZÜŢŢ"„(J)ćććr®ë楔Ůožť˙y˘JŔJą\.żőţGľ¦Ů]'óIEND®B`‚gammaray-2.3.0/resources/classes/progress.png000066400000000000000000000010571255003167400213410ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ÁIDATHÇí”?‹Ô@‡źI&{wsr.ËÁÁÁ V[ÚĹÖ"řdń+ŘXXŘn-~ń[Č–Ö‚…°`ônVÉ&G&yg,’p§w(ěąÝ˝0 /ĽóüćĎďĺścᱥ¸_/†j‡čvľŠ¨5ŕO§Ó*Ë2Ddcb’$Ěçs€`­ťełŮŚM»PD(Š‚ÉdŇżjŔśs<~~›ţMŚŕÍłOĽ~űÂΞżâĂÇ÷řĽ&G8Y~A)¨¤$ý–w:{ŔJ˙y§ýîěßÇµŻŁčc u]}aڎ2^éňišuĐżAĄç ÷p8Ý&·Mťö{g‹xĘ˙»ÝluŮĚVŔÖ­Ť¨łg÷+ ;j Ňě@ů  Á6eJ‡§ÎůU]ú úüËöB8Ľu—ľŽă˛ĘycŞRătőťá`1 «ĺĎ‚ ‡Ôr98IŠ˘ŕĹ“w¤i Ŕb±ŕŢŃŁ¦Şjňڱ9äą§‹Q6G÷Ľ ť7Ö˙±›źuŰ‚íŘkí˛iś+ŕTµ×ĂÎW×-|˝µO蛥¶e—)11IEND®B`‚gammaray-2.3.0/resources/classes/pushbutton.png000066400000000000000000000006301255003167400217040ustar00rootroot00000000000000‰PNG  IHDRn˝¤°gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<*IDAT(Ď•’±nÂ0EO’' R™™2ô+*őúý vćî,,HR2u`A‚‚ŔvÜ!.…„ö-¶®ŽŹ®l ţűk6܆ ełc1[Ž“ A6| »TÍtđ\cÂF¶á¦n@ź!HĐŘJř Ф.x=0!<0ŕ ŔÇ“ü¤~lnŕ6k ÍÚ%ë"¬Q@‡•VpI”Ű_Áąů§Ś:Ŕ—K ćóďą5şÄ7’«Î="´"zDEłr­ćŕÎ/‰şo.ź¬ţsĎ揰ݡ+áIţćV°‹ŮtШŔŹ|BŚĆf9z«ŃŻěóÁž“`3ˇEÁ/ůtš=[RÁ˛á@ťď.l1śHIĹfž"áH€W [ ó Ĺ[†«0\ôIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/000077500000000000000000000000001255003167400205275ustar00rootroot00000000000000gammaray-2.3.0/resources/classes/qtquick2/README000066400000000000000000000000351255003167400214050ustar00rootroot00000000000000Images taken from QtCreator. gammaray-2.3.0/resources/classes/qtquick2/border-image-icon16.png000066400000000000000000000006521255003167400246720ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<LIDATxÚ¤S=΂@}ĘW‰5…t$D N`g°đž{Î@h¸1Ć+@bABěmĽ!ĘĎ~Ě~¸*šř˝dČđvćÍĚNŽă€1&}aCĘ@Ćg°ĆŠĆĘív[µä@UU6ŤúłCQÜČÄ}lŰîMľÝn/ aţ \.á`±X`żß ÉËĺ»Ýîu-Îç3˛,Ăl6Ăńxçó9Ň4…,ËĐ4 ÂX–ĹN§6› ź·®ëÂ0 îS‘ác@žçĐuť·o-×;Í=ťNą@UU¸^Ż0M“ź%IŇqëőŠ˘t÷Ń ŢŇjµBY–<8Žă®RËůľßŤ P…ş®ůüQ=µúŠ(q<#ަçyB`ËQĚ“U¦}O&NŇŚ÷möqÝ%Iz»şwhšR+€˙ŕW€«AămRŻťIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/flickable-icon16.png000066400000000000000000000005721255003167400242520ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<IDATxÚ”R=ŽFPý/ …¨Ń¨5•-(4– U° •Ni *űđł[1Ë•—7|ßdć/qî9÷Ń4MĹ×°mŰľďT„ >‰@şu]÷UUQ`Çq|«ţ::ž¤źĎó|“"a˛,ó4`Y¨ëş~Ž žçńąË˛dą}ßçŐ÷žť Ăđ¦*ŕ]–vr_BČZ‡ť<§gôřˇ(JE|÷J’DUŐ˦ëşëşq›¦ůË™űľOÓ´iŠ{̲, Ă<ϡn×uŽăkµm˛Bń˘(@vÜ*H’4MÓu—łQf`c°Đa€0ě©‹=_~$$۶Ą8Żc¶ŰB‘'đ{żţoµÖÂŽČ%IEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/flipable-icon16.png000066400000000000000000000007221255003167400241110ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<tIDATxÚŚR1Ž‚P\ŕ Q”ؙȖ6k•Đx;ŹbMOoí 8‚&Ú[hŔbZY¨K®~gy»HĐMv Â˙™yŢĽ'ÔëuI’ŢţŰíĆ9g˘(öűýżH`€w˝^y۶nĂ0|ÉţJ^ö’ĺHŽă”JĄb±(ËrˇPx®’ŕőN§ł^Ż=Ď;ťNĺrąR©¨ŞšöÉžMż'čv»‡ĂałŮřľżZ­ Ăx!;ŽăËĺBGxűHŕşnŢuv>źa)‚ Ľč!ͨQĄleJb1kQ‚ĎH _ů/8AäËĺr<·Z-PŹÇă`0h6›$ 1?z€{ś‹J‡C$»ßďc˝^ŻV«M&°`Jš¦aťŇáĎfłív‹Xu]§ZŐjŻAÁn·c´Ui‹0zóůĽÝn›¦ ±eYŘĽö“ů#6j4 Z!ěČt:ŤFř›ü|×…źě(xąp wý Ó‚$őIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/focusscope-icon16.png000066400000000000000000000005301255003167400245010ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<úIDATxÚ”RË ‚@˝F[®\Ф}€QD/č,˘UäĘUDôG˘źŕsň ]Im*\ĽwĆsćśQMA¶mhK?PU•e)ź5öQí4X–%<ĎSABá]FDZ6Ć€ŤzřHβŚOlĹĆlíŇ4mťÚŤŚŢŐfÓ©,&Ż—KÚ¬V =ĎJ÷Ç Ăk×ŰM®™¦)ź'ŽŁvŔŞHĘ<ś/efĆńtR t?Ő`‹ůü'‘/±'đOîŻ`Ŕ-'I" }wî Č_Y×uáşîßů0 )ĎsM:(ŠbąCŃřj|´Ë÷)ŔOŰ^7IEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/gridview-icon16.png000066400000000000000000000004731255003167400241560ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<ÝIDATxÚŚRË … ÔĘđl‚ˇ›  OŕÁx˛Ź\­„c ¶ŕuÍľhśĂ‚Ă̸lă8^ˇ”Ú÷ý8Žó<ˇ Ň4}‘‚N3mŰކq‡a0Ą”Ňu]»®3IĆT˘żł,ĂMY–˲`pžçHEb6tÓ4é64a¶mł®ńh¨ëzžgKQU•ß$ dĂLÜ[ZřáM[ę'ü˙ Ą4 Ý÷˝¬Ď9Ǧi´Č%of{[rI˘g÷Ő _‹Â5¸$Á ď˝dE<Úŕ3.ň9^›oĽĚIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/image-icon16.png000066400000000000000000000010131255003167400234070ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<­IDATxÚ¤“IŠAE NŤâĆ DĹ[xOâ ŻQ×đ"‚( .D7 ŠsM]?Š´işÁ2©úńăeT%:ťŽćűľńFę­V fŁŃĐ|ŕuřAÚA:ívŰUµR©ä'‰ż«|ŽăŔ¶m†x<Žh4Šëő*iRÔl6˛\•Ńív{š¦ ˲B×użŹÇc ‡CdłYT«U¤Óixž'şőzŤËĺ‚€\hte ˛ßďc±X \. v·ŰCve˛řt:‰6‹… sµZa6›!—ËI1gĂNÓéTVâ‹Eˇáž3ŠŹz˝R©”ěď÷»ś™ćÓDÓ´pňÁĘ<ˇEÄbčş.x4Ą »06›ŤčřNÍńźăx<"™L~¨ A[.—Ň˝V«‰ź“Áŕ9Ŕý~+‚ĂŞ×ë"äçŁx»Ýb4É™9…Ďf&ĎĚóťĎgAVY©T0™LdŻűKĺW&"…Ż‚:vĺ\BÁ[ĹMpA<Ľ4ŔâS€î-gµŢő"vIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/item-icon16.png000066400000000000000000000004701255003167400232710ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<ÚIDATxÚ¤“Q †«óFŹľq¤=,;—X–]Â)â9Ś˘R čtŕš4ˇŔWĘ_Î9LÓt»ŕ±vpŔűt]w‡ĂÍĂ0€Rjqmo)ĺsIP…ŇY– m[#PUBĚzY– DÉ:ń ĆSűľ!PJÍzÓ4foK]áqa;NÎŕíćměT`ßĹňť+ěSöˇ¨v]×?a;v`«B`'žl÷9X4M˝áťŘ6|4ľđNlŰmů yžżtfć3Á?6 0Ę’ěáŢ€IEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/listview-icon16.png000066400000000000000000000005121255003167400241760ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<ěIDATxÚśRK 0MÔł¸tăN‘^ÂĄtŐUdˇuď9ŠčÎc(^A˘¦}µ&6a’yoŢ|¸”’yž÷čűţÂ4†8!›¦‰Î­iš+LJëş2Žc%x6Žăę-ĎsÖ¶-wŕ€±ëş/ Ţ‘Iöţ`É•eÉÂ0śď=ó}U҇€Ř†AŔŢ=ѵDŻ Ş*mv­ÔĽ >T@Î9I÷,SŔžEˇź˘H­€jZ5‹BňL,r¶›f¤« u]ĎŔ}´H+ŚnđË©gÖ’ŕźf&۶SÎą4<)°/­ĆZh(ĺĺIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/mouse-area-icon16.png000066400000000000000000000006521255003167400243730ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<LIDATxÚ„R±Ž‚@=pAÁˇ@*‚­Ť-‰źë˙!$‚¨Ü»[ŹŔzS Ăä˝Ů÷f—1 ăămÜď÷Űíöx<š¦A&hí÷ű7PŕÚÎápř"xž‡\EŠ˘˘ĐőzĹĽżSضz˝^ŹGđ«ŞD÷M§S۶Q€ó?a<§iĘqÜn·[,®ëfYöŽŔóüů|†t5MsłŮśN§(Š^FŁFV?1›Í¶Ű-6áű~wQOZ„<Ď«N°,kYÖd2‰ă¸%ú©ëę˲„$ÚAá8:—ËĄ{ą„ŽÇá€0żI’Ŕ7¦`oş®CmO\"3 C ÚůřŃ4- Cô»¦ }ôg>źĂ"D«ŞŠµ˘ł\.á¤GčľY–q’$ˇ’~­•P=mPô ”łZ­^˝‚Ář`$ ޱôÍOEIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/pathview-icon16.png000066400000000000000000000005001255003167400241540ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<âIDATxÚ¤RA ô)†Ł?0ý„GÓSO}MZᆪń˝küĄN‰ Ąť„vvvX޵&iš>„˛Ľ“R’yžÍşő}Ą¸ŕśë<Ď˝ÉJ)2M“«ëš Ă@cŔ8Žă&qTE×y@۶›‡‹:oK[ł…Ŕ©`1ó˝/†:e»Äk¶sQ|Uý^U¶‚u ϦŮM>e™ŐÂß|Žz>4Ń Š‘D€`ÎO 0Ş®ş®ŰÄc$IŰŚk(¬9đřĆŘú90EQTRJuŕ*‘ű`tő·ü”ţaIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/rect-icon16.png000066400000000000000000000003751255003167400232740ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<źIDATxÚ¤‘Ç ! EM¸n”C­tE{"{ńFLZř’…„őźCÄĽWŞ‘k”HŻTJ}˙9J)c„”Ôb—Ľ¤O­ő}ąj˘x’1$U°ÖőŢßVhÖQó ¶źNÔyyďTÝśs0« 03{ `B„±™ĺµâ°¨eŔO€ř†Â.śŮĚIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/text-edit-icon16.png000066400000000000000000000005261255003167400242440ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<řIDATxÚ”RK‚0µ…S`=[îA4ˇBc\É!dç`kKM¸_ś¤Ĺ*~fŃN›÷^gŢ”yžç8Îâ‡Çq—sEŃPß÷Ă#pLÓÔĹVUŐ´ë:$Ó{>'\×u۶ԗY–˝'ŕu I8 CÂaEŽÄ%X.7ë5ĺ¨dĘ_ qŠcBâ˘TQMÓȇç$Áęű>clĘ7„˛,Q´Ő˘RĘ*Řô@ö}ť†!ŔÁ·4 -2Č[ĹčŇ÷»ŮőDĐň[))‘3ăwÉřëíFçĂńh!hzüŐřWôt‚LŐŔ\äyÎđ˝˙Ä]€őĹ”PĚÍNFIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/text-icon16.png000066400000000000000000000004531255003167400233200ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<ÍIDATxÚ”RA TäěKě'ü…©©ń!Ťhl<óĆŹPŢ=˘ÝÔf‹T-ť Ě ă®~†AxĐZ+Ą(!$I’’”R˝[Ć…Ąëş-ę4MPçtËXaQmÁ)M±o‹w)K[Đ÷ý˝i8çŕ}Î2čÄL:DŃ1ŽW^¸Ő5$†jłoʶ˝Vn‰cÇŐÜ&‚ďč{°wAűźaGűw—`ěh_ä9ŢÍ5Nŕ#0żŐş^ŹäŇ„ż·÷ž ¤czâˇáŰIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/text-input-icon16.png000066400000000000000000000005141255003167400244530ustar00rootroot00000000000000‰PNG  IHDRó˙atEXtSoftwareAdobe ImageReadyqÉe<îIDATxÚśR[ 0Ü?˝€ŢEJń‚ýě…,´ŠźžBJéeĽ‚ĎÔ•&¬Ť5i†$3;»Ç÷ýĚuÝ3 „€ľďaš&µf\çy"I’]ň0 0ŽŁv^U8¨Ô4 ”e ¶˘h‰ČuĐ"MÓŐ#ĽěşÎX–ó®eÉ…ĚL“(ÔE۶@Ď÷pę@şŔ l ‹)pŠcŹa÷şţJĽćą.€x<ź›{ŠC¬h%üÍU§{+[Q¨ćḰźcŰXJ@˘›$™Č«@˰źW?‘ Řd¦€1–qÎĹ˙YŮK€Ψżcv%ĂIEND®B`‚gammaray-2.3.0/resources/classes/qtquick2/webview-icon16.png000066400000000000000000000010071255003167400240000ustar00rootroot00000000000000‰PNG  IHDR‘h6tEXtSoftwareAdobe ImageReadyqÉe<©IDATxÚŚ’KŻÁP…o«Ţ„"$nH3"éńOý12AB"1ń BÄ[Ńűµ»·¦ö =gźµ×ŢkťŁäóyźĎ÷óEĽßo˲4UU[­–—Ő4;C‚¸ßďŻ×Ër˘Ýnk, ľô §ÓiłŮśĎgŽCˇ®ëŃhTj\Fůöűýóůśo6›­Őj4ą^ŻťNgżß36©±[+Š÷rąLĄRőzýńxü:ŤŚ[@ęp8Ún·Ýn7‰°}>źét–rą‡És g˝^g2Í Ă0Ţ4M¦UpŻV+1ÓÖŔÁńx„‰ŘĹŃ1° L TĎPX …2&“ BM'PR©T0 Ó>.Á‹Ĺ°©a8V«U „ y—XAÜď÷ˇ„©ŮlBDó?č™Ëĺ>¤âńřívŤF¬i’H$@z<s!0˛vGÂA(ąŻŮl†ÄR©Ä<Łd:ťBÄ—-24‰ŔĐb±¸Űíz˝¦‘§-PZ†ÔMťHŠ2@ÉdŇ{|d.—‹g‘ý,äť| §°!yY­@ůIEND®B`‚gammaray-2.3.0/resources/classes/radiobutton.png000066400000000000000000000011121255003167400220170ustar00rootroot00000000000000‰PNG  IHDRn˝¤°gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ÜIDAT(ĎÍŇMHÓÇńßřËŘ ˛NnŤ6)F1ÚV,’ Q, 2B(ŁĂ(ő`auČl d‡5"J‚ş ę’¶KD‡Áv)iJ/dEwľ,ţßĆ˙”:ĆsýđđĽü„ţ˝ô_bŮdČ.§\rÉ)» ŮVÁ2N§ŽvVÖš>ł˝Ň]J Č#‡Ś°šzsŰçG™â5e2Llˇ{R>ąŐdÁ2ŽçNÖ^đť/|ćsĽcŠžZW^­r/wŻĎ:ŠĎ?çyĎ[f(3M‰Ű„;ÓňÉ![‡ #|ĺ%Î%Âó”{ô˛»¬<2ŘľŁň€9f8W_˘Ź<·csUqyeo`g‹Yâ /‰ÔńFrÜ ĂS ůĺl`W‹ůŚW ×qwç*SIäú o­Üdš'ô×ńA˛Ś1ȆŞ;;JýxÄ= r€Ë\c}Äf­cŘ÷„˛Üç.dąÎ8W8ËQüKáŚuACž=“µ.1ĘE.0Ě)ű)*i=ťMůvĺŰ»8Aš!ޱ—uK[ŠęTÔň$Cnµ¶§·•ŐfłŮ\_ ĎnĘ(©čď^’Üň)¤¸J*©„â ­¤_ÝňČ+ż Č/ďŞý{řl8»q¶ĚbIEND®B`‚gammaray-2.3.0/resources/classes/scrollarea.png000066400000000000000000000010441255003167400216200ustar00rootroot00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<ĆIDAT8ŤÍ•MKQ†ýţD›@÷-ŰDD1’$8`î ]…´Š’)÷.f!´+ÜŘ&páÇFg#¸Üh"žîąyeš/jf“đpĎ/ď\f΀˘(wÉdr‹ĹP–eŚFŁ|5CýßQĆ ¤R©aŁŃŔů|ΙÍfÄfšÍć …˛€ďLĽ”t:ťb&“ÁP(dA’$ŰľŞŞKa6›]Ö‹Ô›@·9™Lřć\.‡ů|5MĂR©äŠ“”‰–ň…X*Ćă1“´\.c­VĂV«ĺŠ“T`‡yâŃhÄĹ””¤żůŹÂČB|ŔĹÁ€‹é)Í_Äň9ŕá%ŕ¶ Vqżß÷,>»ĽxÜ?5‰©čőzžĹ×O€7đä–ÄÝn׳řöđáđčĘFÜétřóęE¬ĽćŢŹS6GˇëşçÄŽâH$ÂeÔřWbÇ3ö+v|*üŠß<żb‡Yá_ě0ÝľĹív›oL§Ó|ĄMf¨oĆe‡!Ź‹E¬T*X­V±^Żó '0_±ű‚0©Îçq"‘PŮËń(jq-z˘vIOř„[a•±ĆŘ`l1v»ěąA>â NRÖ†®ŮIEND®B`‚gammaray-2.3.0/resources/classes/spacer.png000066400000000000000000000012561255003167400207530ustar00rootroot00000000000000‰PNG  IHDRójś DPLTE˙˙˙“¤­ŻÇÔ ĂŘâ«ÂТ¶Á·ÇĐp–Ş fu|f‡@o†SvŚO{“+LZ 9c{>k„-Pd4ZnAT\JJJ444LLL---AAA %ČŰä ???ŁŁŁµÎÚ~~~¤·p’¤YYYĆŘâ333“¬şĎŢć’’’`ڤłłłĂÔÝrrrMMMMˇ}ُjŠŮćî[‡žAex|||mmm ĄĄĄEEEV{Źxxx>k`x‡CsŚŞŞŞ666N}–1IV:j„XXX–·Č3^taaagggźźźŠŠŠuuuSSSUUUŤˇŞ×ä쑯ż¦Đ;Â.tRNS  MD"3W?(:Ünöuţţůů\9töź7ťŕüíýŮ~â=ůřřş{>F›Ů,öëIDATx^ĹеnÄ@Eáńر×^ 33žĺ0333ăű÷ůG)J‘:·űNyŐ?,ći×Ő^ě·•÷žËâ;ž­ÖJçVĆT2N˘Ś#ĺf.'Ů^%Îç-,ŹÄr2‡'TĄZ`6Ťq™äç5Ą˘¨c“Ďö`ëžJľ¨gLlňŇMLM“bóś:ćĹ&ż‚‚X®,l‘T66ľ€ ím ‚ř bđŃdĎŢćK?Ń47v7Ůť3gÎě.Bŕ/ž ‡Ă/"Ň8ç2Ŕ9‡Ý˙4vőu!Ä÷l6ű i…BA–$é)ň»Ś˙­V+y:ťjţ€s.K’„H$âĽápÁ`@Ś1,ËÂőzĹĺrÁétÂńxÄápŔ~żÇ~żG6›ÉřĎř.ňcŞ–esţÔ†N§Ă0`š¦łĆŃŘ ěĄßckš&Z­t]Çn·¦iN@‡±=đ JDč÷űX,0 ËĺÁ–e˝fě^¸Ůl Ş*Ňé4ĆăńSŔ^݇n·{ç7đťĆî…çóívB·Y¸űORŘŔn\.‡T*!„/P»¨wRŘQ^ijBxküj˛;‹w’x{<2öbď6ŔËâŮ“'“ TUĹz˝F©Tň­ó[Ť‰Őj•JĹ·#™?iě—Őh4Â|>wvl±X„˘(ŻýŠ ( v»¶Ű-2™ jµš÷–ö Ę9c Ífů|ŤFŚ1oWجÝ’í ŰzîoŃhőzýí–ÖW«‰’É$âń8b±b±ŘÝů … Á»s‘iš¸ÝnŘl6ŕśëŔ„(—Ë_–eiD$Şú‡+Jđ˝^ŻŘ_]¦żh7Ę9'a÷†IEND®B`‚gammaray-2.3.0/resources/classes/tabbar.png000066400000000000000000000011571255003167400207310ustar00rootroot00000000000000‰PNG  IHDRójś 2PLTE˙˙˙%%%} hЎĂpŽjŚpŹZxˇÂ$$$“şr‘—ľ&&&…ŞgMfkޤĹq•yśsq•c,,,ĄÄ(€©‚¬„݆±´ж‹¸Ť»Ź˝{Ł~¦-;###§u›wžy żĄe†­ušJcKdOhPiQkRmTnUpVqWsXuYvZwIa‰Ż‹˛Ťµ…°mh‰—˝˘–Ľ˝4átRNS &M "D 30:(Q)\^®!ĐIDATÍÁ!OĂ@ŕ÷ýîk»F¶0ABCzěW#Đ84‚AB&H ,×–]ďZLMĂ nĎě fN:(۱MQ˝O˝.ż {'o$đĺEĘQ”Śo1}ułEČSťÝˇQ#‘»¨lQ{™/ ëeľ,,•Ě“lmŢ-zĘDxmĆ—OYąX5«Ó É{Čśçä†{ésí6 ą"_Î8aďńć ŹńÇg«GIřÁŔČxĄth˝SšÎwđ4 ¶l%ŠřĄ6H“I IEND®B`‚gammaray-2.3.0/resources/classes/table.png000066400000000000000000000007431255003167400205650ustar00rootroot00000000000000‰PNG  IHDRn˝¤°gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<uIDAT(Á?K”ŕç˝űá!$·(­ĺ&NN7„7D EźÁ©ŻŃgpŠâŚ”]$˘?§95Tx‹xŢq˝ďď}{žĐzůĽŢ÷&® OĎö LC»Ţ}Ú»¶u€g8Ů|°ŕŘUhŹ{÷$čZ— %ٰě6´'Ţj@ÇŠwŕTŤ_°¤ žHpĐŘÁWíP@€”¨ˇĄx¤«»:Ţ8w €OčZ·‚Ž;Xł `Ľň|Ŕ68ô?• ś[S€T!JpiŐ{đ]…߀€‡fŕ3ú ő1”J%H%*@Ŕ‘9€Ź`(ńĐ7ß°Ň~RHPK$ 4×* @-ÍM Ö„fxz˛ą(#đÇČĚ.T2äŮŢ‹Ŕ>€×páČŤyHÇ–- -P«Ü›†4uĺVG[injM]”&fÚ h4RĘ˙ř‘7üjIEND®B`‚gammaray-2.3.0/resources/classes/tabwidget.png000066400000000000000000000010741255003167400214460ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ÎIDATHÇŐ•˝nÔ@€żďér Ö‘D"Ýą;ž€J¤t !% ĽH Ţ"EZZ¨¤ťR8ŕŕ;˙-…׾5 qG FÍxĽűy<ł‹µ–›ĺ†ä˙‹Ó0Îú« (ťm÷¨·×ë´6@0ťN‹<Ďń™¦)łŮŚÉd‚µADz÷˘(ZY„@n“ç9ŹŹŻ¨ę¨ÂĎyĚÉ HžĽ¦‘íŰČ`@śŐđ|źw——ËW‹cö7~ °ÖRŐ ®ć1Ş _?7«ľ}ůD¦0Ú…ÁVüp ŔywŕÓe9Ć@aşšşLE{çÜg/ŹÇ«Ý‰"žz—išBSŠ= 3Ýńđ ˘°ÂĂg¶† ŚIP čl¸őAŁó"ćŐ@Ň}h»)ÉËď”Öjµ mŚĆ˙¦K~ęu·Y\çóâ"ýoŁ‹¬m“r’E/ăM ¸ŞeóÚ®ý­PkĽ&Tµî!ŮŞ«SĂ´‡{žÇ||ë5ŃeŃÖO[ß‹‰¸L’‹Ő鶤˙pb>ÎŤ+ö]§»Ŕhh$@&®#ŕ–łfpéŕéźýßJ÷cřĎŞ/ÔŔˇIEND®B`‚gammaray-2.3.0/resources/classes/textedit.png000066400000000000000000000014671255003167400213340ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<´IDAT8Ťµ•AKAÇ›¤©ÝD­<Š·zŇ §‚^ĽDAĽ íAĐ_@¤Ąć ‚Eą~©Jˇő’(ÍEž#ŐŚI%îÎLe·»ŮD{q`73oţóŢ˙˝yŁ)ĄxX^^”R&…1)%RJ„Xň}s‡śSJ-d2™˝€”2922‹D"ž›ďň¨q/›ÍĆ666’Ŕ+€"‰Dhkkł{0Äď÷ăóůĐ4 )%¦iRŻ×ąąąˇZ­r}}MĄRˇ\.S.—@Jł©Rşnnĺjă蔕R¶ ŕknhÔX‰QŁ˙€˘1Ń ŃŤ?‰ú 1ţH„ř#&†ى`"JLđGKZl]lËŹµ-twďÝ{ď̶¬¨Ő7Oň}8çĚ|ćäĚ™ńśsü¦˙-±ĺÉú’ Z¶é@_}A“ŢśÍř}alŹś‰’/L*_?3˙Éţ]›Íbű˝Ĺ*Úýíú¶¬˙aw{n}6ă35Q XŐ–ĺâ|al9vŞ<6ÚŰö>xĹŘ‚=đ¶ď>üHgľé©\“Żżů•®ěë–{,k´ĚT5G‹Â/a+×_¶šrdÍälôř»<ăŔ- ľýŮovôtäž›śŤ˘clíűűÉ·µQü˝Čô‰iú7őSšźgřČŤTIšşčĚ711]ŢůÁĂW=˙đÍOZż˘53\Ž­ŢĐ0Ć–M«čďżś†† ű÷ďçđ·‡Ůąc'ĆŽű™ŹŽňCe-ąŚoNĎĹ÷=vő€:wQZó^¦Aé%qÍW288€ďkÄZÄZśÂJ‘šŻ<Ź5kÖrëµ—Ńl&É4(­5ďmyň€®Ao Őw´pŠWÇôőő!"X¬X¬ł¤6%1iÝ·b±t®ědűU--ś"Tčmu°12čścmnŽK×ő ]«Lç'Ž$1T« N\MNŔŃݵŠőůçĆ0đ'ŘşR,tä :Ł ĂJ*â'¤IB\Ťk±…¸sB…XÖ,o  ĆÚAXx ‰ułĺ”ĺí a%b*ž˘Łă"|ŕ{ ĺűTĘş»Vc¬Ĺ‰`E°Ö0==ŤsŽîłŁ)"îĎŠSk‰SA)(W*TĘđ<ÜBŹÓ4á§źÇ9ôÍ!~ĆXs‚çAea} 5q*¤¶6ď @ś÷˝8M–°˛ł“Ţu˝(ĄPĘG)…ďűěxhCwŢÉ »_b|b˘žď]×KOo…q5Vl­IRĂé(CF5Ř9¨ňń•ʶnÝĘ=woç•—_ĺĉ“őĽµ–Âś¤kd¤Ţc5â8|z [~›¤ýÂv´Żń”â÷ů"gŁľŻ0Ö°éĘŤDŇ–ĎŁ”ʎ8s†Ż #OąŃzĹămĄ=JĚDaÎňŮxŔÔäžR(ĄhĘdÉfiij!ĐľďsÝ5×ŇÜÜ‚RŠ0Šxçŕ<żÎ”‰ń¶Ňž:Říş#IŇô~ĎĆÉÇ>G‹LMN‚Ö\+]íݸš]3ůV,mG)EF|ţÝ4ďGx6N’4˝ßíş#9ďĺÁń×nů2Mâ·“j™gj^?0Ă‘±©”k3mŤÁ‹ňišňŰÔI^ÜWŕŃ}gIŞeŇ$~űřk·|ąř·é=ˇňwőľé!ŰĄˇŮßĐŃ =šµ+YÓžÁ÷5ż~*&|6Vedr•”¬C˝;»gü>çžEÁçlÉĐ[7©4Ýë<Ýęü€ “%Ó ®†¤qgSŕYk±Îb¦ Fâń8S““ä66ć"‘Čű­­­g@EDL`SŘĐ6Đh4ĘúúۡVĚÎÎ’JĄ(‹łŐjő{,ްR©P*•Ć?>€1†••śs¨˘Š‘ÉdŔ9X\\Ä÷Ľŕż "íłĆŇéĹüÓ°ÖâśĂÔë¨ęYĆă ’Éi˛Ů,ů|ždrЦs ‚Ş ˘XD…bq;źĘ>@4emmm¨óóóĚÍÍQ(X]}ÍyVü3+î­ThqŠ ‚ĺסa;óxB:}źĄĄxž‡JçV @łŮŕöť»=Sµ––;ĺ¤ţő@µ żW®MĂNö —6.133s ęP۶ l/lŚ" (m˙Ć®Ŕő>{…|~őĺ"VôĎ€¨9vRéS"ËDĽ“žł‚N›űĽ¸9Bq»@Ô‹X¬Ôh´j´\çvŞ ¨o_ípĹmĄÝ ‚Â`E… •Öő?üÉ˝ÝIEND®B`‚gammaray-2.3.0/resources/classes/toolbutton.png000066400000000000000000000022171255003167400217050ustar00rootroot00000000000000‰PNG  IHDRÄ´l;VIDATx^•UMH\WţŢ›űŢĽńwĆ˙ š1 q4F­mGMÓLL\‚Zh.şh1]u'¸qÓ••lJ (jZ¤BŞMb’Öt%Fcˇâ¨tüç§ç\Ţ[ ŐE>8Ľ7ď^ľóťsľ{G ôööÖ†ńC8nÚŮŮÁűbss sKKKßX ŘcbŃßß˙[0lŞ®®F*•ÂIŕ5EQ¬=iďCCCčééaŇ.а`bVZUU…X,†d2y")ÖSôž4‰U¨Ş‹"ÔRxX1۸üx<ŽŁŁŁI÷÷÷111ľľ>tu}ŽŽŽ”––B×uaŁőȡ0X¦L$2ŽĂňň2¦¦¦°ľľŽ»w‡1;;\şÔ‚ š‘™™!…™ĐX¬EĚ-`âcŐr%ŃčZZÚŕ÷W˘¸řž=ű÷ďŹČµĆĆFJĹPUŐF\Š€ ĘČq1Ł˝˝ĂĂ#˛äúúÔÖ~€ŐŐŚŹŹĂëőŇ|Á°„Ş0Aj9{ZĐ0Í„ 8ťą¸ző <a~~Ž•ŃŔj$ĹÜÜ<¶·# pĎ…Ş KqzŹ™lqq†á@yy,ˇąą™¬ő#}/‡Űí–±˛˛—Ëi¶BŘ„H¦3!—ľµµEš%Őq´¶¶˘¤¤6› š&ŕóůŘfô[!uvęmĚśA Ó&ă´Ă“réÜ7šŮęKŚŤŤáŐ«?ńî]„H±¶¶ !22 IL !ŘÝ5‰ Ô&%­Ç–—ŃŮů©;¶¶Ď099‰×Ż˙Ć‹/1=ý+nÝúŠJwËŢź?_‡˝˝}˛âż&±¦kš!ţ× ~vwwăŢ˝aÜĽů Mżv»ť|ű=·o+‡¶±–„Á`#Uy€‡öę٤Y·[jĺóâĹOńöí ?ž•ß*Üąó“<çÎŐŇĄł%]`ťŘ¦¦OČ‚šÄFžÓéʱ[D>ł˛2QWWŹŃŃéŐ††Źé[4M—ęd†Ž˛˛SÔăô:#77Ç+„îéŠăRB#•©vffOž<âdŇv§OWźŻó©ż5đxÜÔŠ#đK"/Ďí&â\•™ř>eľµřöRHe••܏щР»„ĘߦDż ĺýTÍš|꺆k×®SRűÚ dÁÄ|I‡BˇŹŘŁĽŃşą ľĽŢŮŠ‚/"‘m<ţ;í]Jx†îڧL*+8{6pHOqĹ "HÁcŻĹű’ŕňĺ+dÁŻSTÍ›Hdëµb†‰Yu…ÇŚóęS Ľ®çź¬OZ4Ť~Ú3é¸{˛łsňóó=ŚŚââ"Í0ŚíD"ůYî)“&(ö(Âü4+°1ˇőo‹Ĺ>˙|TéČs;-eÓś†aw‘BŞŠ˘DÇ?äŚ7Ľ Á$©ŚăˇŐh.—K÷űýYMَ©qŞh‡Úý€!ąY„.%IEND®B`‚gammaray-2.3.0/resources/classes/vline.png000066400000000000000000000004721255003167400206120ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMA±Ź üańIDAT8Oí”± 0†•FZ;¸tp(t,E*Tp“‚ŕűżDz‘˙ĘŐfčŇmÁ˙î>pČÁNH¬"b " ‰ n™mĆl(Ĺ …$Ä$ #ö¸eV€ łJеhäćŕACśqˬłZŠÝŻX1`Á‰8Šo É2㼀ë~bKGUUÜ|!L]×Rpődś—p˝&†áIě2Ń÷˙Ĺ_-~xŇb`~Ň qÇŮBě}ŇĹy ‰y ŤăhÓ4ĺĚpÖ¶­{—ĘóÜÝoÄ}ßsóĽ6§i˛MÓp–qćäbgx×ćŰýŹźé^Ńśó{IEND®B`‚gammaray-2.3.0/resources/classes/vscrollbar.png000066400000000000000000000006371255003167400216510ustar00rootroot00000000000000‰PNG  IHDRÄ´l; pHYs  šśtIMEŐ .A«=‡bKGD˙˙˙ ˝§“,IDAT8Ëc````b â > Ä˙±ŕ#@R˙˙˙BXˇ†ŞńýĺË—˙żrĺ Ďś9Ήĺo€Ôk0'˱5ČeȆ‚řȆC]ÎI¬ÁÜ@¬ Ä0a†Â0Ěp(ź›Xy€X}`c c$qb ćb5 öE lj0/ŮG—0üŹŻ`ÓÁY ˙=ٍcpń$†˙ĺÓŔtZ#ÄpŞÜş‚áç:0 2ärŞÜż•á˙´˝ `şf.Ă˙¤j*a·Ű=ëóůdYVN …BŠD"oZ[[łáŰŠ7°Ň|őŹ{54miř•ĄGŻ-=~gilÖŇÓ9K“ź-=K[z>oé墥™ĺ&Ťż=§p8ĽŘłÁ@9pĐŮ+črőOxtgĘŁ5-iMKúˇ%ýĚRę“GOŇŐz±čÓĚJH@@@A6ŘTu€B1t>ş‡ŃµQÔŘ‹NôŁ“wŃ©{čtťB÷ߣä41ďŃôňş-€#ě\Ŕ1@¶őŞc·PÇm´Ş´ľ*­oFߍnڎÄz0‡&˝ňűýś›UĽzč8 FQS5_B‡#čH+:Ú†jbČ×üP¬wýâëŁëÖą\®/+Îö8,¶ú}Â=ÎîŠý@­±ĄÁwAuvvf @˝‰©59nðoÖÇĺĆPÔá––őőőeŔUŔ>SarŠ Ă–Ëä•HC{{»’Éd\–ÓämńV™Ęęăń¸FFF2ŕ˘í>B˙Á‚»şş”JĄv śu˙ŕŕ ¦¦¦2`çvÁ…Ŕ^ŕ`OOĎCłAn…;¶š€js–äşš~ü\…š#¦IEND®B`‚gammaray-2.3.0/resources/classes/vspacer.png000066400000000000000000000012451255003167400211370ustar00rootroot00000000000000‰PNG  IHDRójś DPLTE˙˙˙SvŚ ĂŘâf‡AT\ŻÇÔ9c{ O{“ ·ÇĐ4Znp–Ş«ÂĐfu|>k„˘¶Á-Pd“¤­+LZ@o†JJJ---444LLLAAA`ڤjŠŮćîźźźp’¤–·ČĄĄĄ ŞŞŞłłłUUUČŰä3^tXXXuuu×äěSSSN}–YYYŤˇŞaaagggmmmV{Ź}ُ“¬şrrr`x‡‘ŻżµÎÚxxx~~~ ŁŁŁ[‡žĆŘ⊊ŠĂÔÝCsŚMMM’’’:j„ĎŢćAex|||>kMˇ %6661IV333???EEE¤·hTŚ.tRNS MD"3W:(?íźţŕş{öât~ýuůřö=ţ>ťů7ůnř\9ÜFŮü_Şl—âIDATx^­E{@Ea†@\ëîŢCĽîîîîö˙÷Í aö=Ëł¸÷˝« )t!Ť VĹĐMr¶K~Áp´4ì¬>—®ď—'gććóŇŃ"dQ¸[ßÜŢŮ=<=»Č‰šö#Ľ‹‡$3¤&0ĄWŞăĺ2 łÜ ;•ŐăM<Ę@Ô9Đ!05]O$¦ů ˇk‘˘—š!ÚBë~mѶѰĄčŽN>ööÝŻ»ŽŽOč‰ű5˝ś÷A˙ŠĽ…ˇaFq„óÎ(căŻo({ŢłŮĎ/Űţţ˙˝.Vřoď_Ež2°bŹ\6IEND®B`‚gammaray-2.3.0/resources/classes/widget.png000066400000000000000000000013141255003167400207540ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<IIDAT8ŤŐ•ÍNŰ@…żqpP$ĽIb ›8‹˘vÇŞK*ú@íô™*í t¨¤ŤP*Ű©láéÂe’Á¤ę˘,:’%ź{|ŹŻîß)%ĎqŚgQÄËwźţr!%RJÖ?€CŤ~[_>Ľţ'Q>śWď?—§§ɲÓ49<|išäyÎŮŮŮF^JÉůůWâ8ćää-°–ă'Ă0đĽr*Š‚ 6ň——WÄq¬E­OJ‰ë:´Z-eŹÇ$IŞđc~6›q{{[I‡&lŰ6ťNGá››)óy¤pŻ×Óř»»\]Mn·ŰUá˝˝˝^WQ1ťNYçűýžÂËĺOFŁ‘ÂŤF×uŞÂŽł2&IBŽnµšŹďűE”Ĺ=jµZUŘ0Ę×,Ë‚‘rŞ×M<ĎSĽ”ß÷ɲ (űŮóÔëuÖŹ–ă2’€<_uŔp8Ô: ÇÄq˘°ăěkĹ|R8 Ç,—K…Ť†ÂÓé7ćóąÂÝn˲4ľ"<™LX,аí>»»» / ®ŻŻîtÚŘv_á(Š4^ ˙>SF˲čvW’¦)!â÷nh6›¸®»‘ݤ`ggÇŮW8Ďs‚ ĐŠ9®ŠůŔ?^żšđöö6ž7P.Çy¤ĆYˇł( |_÷Šp­VĂó<¶¶Ô^" C’¤ě)%®VĚ0 IÓTńë˘TŽŹß<Î GGVĹö·üĆE_HY>…D")S( FąěźZřâż»ó~Ô ű‚P IEND®B`‚gammaray-2.3.0/resources/classes/widgetstack.png000066400000000000000000000014741255003167400220110ustar00rootroot00000000000000‰PNG  IHDRÄ´l;gAMAÖŘÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ÎIDAT8Ť­•KKUQÇkź“Ż^h)B_ j 8í 4"âM˘Y(GAŽš• Ç•ˇi"JĽć5ŤŢtŐęÜ®Ż{»ÁŮű<ĐÔA ›»Îążő_kŻ{—h­PĆ…ÍM‘ńPk­7zIz{{Oݬ¬\^\\ě¬V«›=ĎŁX,Ž—JĄ>ŕ°ř&YśŐ$rkµÚĄv¶×}f-¨ ĘHP Dc ´®±wě]GéőŔ°`ŕˇĺŠHDną\îj=ü™o Cřá/$T*…*J a'G …BiłjÜjµĘZPÁĄ 3Đä4ĘmŃęŻäÚTk†Răhś«†\ČzúُżŐ­ĺ˘bĐţňu&fáŁ> -ťqĐi8´ąŘďUŻú\ÄÎ…ÄĎž EcÚaŔ=ÍßUĂśűúš;â`čŰv§ŠM©ÇÎëß>Ł’wě0.ÍÓŕó “»ł`×…|?_ßwĄöxˇ”âqü„ćOX±¤e˝Q  ŕÎY•N¤ŕtxü Ä`Ǩxs/Ul!cQ®* -9˛ŕ0V¤=~:ĺć6™Ç|6É{Ą`Ďó¨ĺ~Éef&AÂü5Ž2еżľSSSĎ›Çgşę›ťöqÝ)1tć%śŘC}Vq”iĹôôôÝék´‡Ř†u¶Ŕ©vđs­ ň!\JRąZë~ůě) Ďşů€WŘ2A¨!´’«ł¬Be`\óč °Ëó<‚ĆZŞdó#X˛•ż˝jĂsŔ#ŕŹ˙ÖŠĹâÄĄăŤ*{żŰj“Ţ7*° x@YĚ 8 \$ţ#ŮŽÍʇŔáŮQČÓë!”§§źd—–›™hDD„źo¨ŻŻ÷@I¤ R0)„´™FÚęÓó˙á@dŹç =ć¶“˘H»IŃ®ń6×C|ž¸\n˙ ÔDž%$%“ö’vą´ę,Áä^ż1P ŮŔ!ť ±I±¤ČőbËत¤SqqqŞđđđ˛ń2)ÎősýĆýY•…·°ÇúIEND®B`‚gammaray-2.3.0/resources/gammaray.qrc000066400000000000000000000135461255003167400176450ustar00rootroot00000000000000 authors GammaRay-512x512.png GammaRay-256x256.png GammaRay-128x128.png GammaRay-48x48.png GammaRay-32x32.png GammaRay-16x16.png kdabproducts.png kdablogo160.png splashscreen.png kdab-gammaray-logo.png classes/datetimeedit.png classes/textedit.png classes/calendarwidget.png classes/progress.png classes/scrollarea.png classes/lineedit.png classes/dockwidget.png classes/vscrollbar.png classes/combobox.png classes/commandlinkbutton.png classes/wizard.png classes/widget.png classes/spinbox.png classes/hscrollbar.png classes/checkbox.png classes/tabwidget.png classes/dateedit.png classes/label.png classes/listbox.png classes/columnview.png classes/dial.png classes/frame.png classes/tabbar.png classes/hslider.png classes/groupbox.png classes/graphicsview.png classes/mdiarea.png classes/fontcombobox.png classes/dialogbuttonbox.png classes/toolbox.png classes/timeedit.png classes/plaintextedit.png classes/vslider.png classes/doublespinbox.png classes/lcdnumber.png classes/toolbutton.png classes/table.png classes/widgetstack.png classes/radiobutton.png classes/pushbutton.png classes/listview.png classes/edithlayoutsplit.png classes/edithlayout.png classes/editgrid.png classes/editvlayoutsplit.png classes/editvlayout.png classes/editform.png classes/qtquick2/border-image-icon16.png classes/qtquick2/flickable-icon16.png classes/qtquick2/flipable-icon16.png classes/qtquick2/focusscope-icon16.png classes/qtquick2/gridview-icon16.png classes/qtquick2/image-icon16.png classes/qtquick2/item-icon16.png classes/qtquick2/listview-icon16.png classes/qtquick2/mouse-area-icon16.png classes/qtquick2/pathview-icon16.png classes/qtquick2/rect-icon16.png classes/qtquick2/text-edit-icon16.png classes/qtquick2/text-icon16.png classes/qtquick2/text-input-icon16.png classes/qtquick2/webview-icon16.png gammaray-2.3.0/resources/kdab-gammaray-logo.png000066400000000000000000000211571255003167400214760ustar00rootroot00000000000000‰PNG  IHDR––<qâsBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î< IDATxśíťYŻWvßkď]Ug¸gŠH©Ĺ¦ÔR»-Ë ÝqçÁ ’‡JúäřEŇ‹żAA#Ž»ŰŰ#‰í–§Ő†C´ÓV«‘’¨Y.ď=cUí)»ęśKФHI‡ŇmŐź(Ţsϸϩ˙]kí˙ŽÄéĐáÓ†ú¬Đá±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬±:¬ćł^@‡{†\˝zUŚYí)«ëšcÇŽE ~’ç‘?Ńă;¬ňúëŻë,Ë2´6„t|ę1FQĹh˝÷öŻţęŻüłĎ>ű±ž«#Öç/ľř˘=zÔôűý5DÖÉą=Ż>1ŰD Äc¬lđŁAQLOž<é?ÖSuÄúüâĺ—_6Ću­ő­u_”’ŰKnwůvä‹qéߚۅ¸xTŚ‚ŹÁďc \·ÖΞ|ňÉpż<éb¬Ď).^Ľ¨Ť1Ů !ô-!ÜtiÉ#˛ ”ě!”Đb/1bŚé~1"!€Ň8„"Á;‘ŕ%€WJůW_}µä>c®ŽXźC\ĽxQęş.€-çÜ0źÄł,ɵ¸&ý_UÄŃşżÁ((‰(W3°SL‘)3¬ŁµÓZ{ŔräęőůĚf3BŘ1®×ÖfÓéTjçŇYŤ{K¶Ä6s‘ö2Íýbz\ó3=,g3üµkĚ×r#P*˘mĹA7fëĐĂ#‡ •e1Ćňg?űŮřüůó÷ouÄzŔxăŤ7ÔńăÇMÁ|82ĆpŕŔâęŐ«›ŢűbwwW˝ňęE¶gs˘¤(Ć-č%‚(µ Ö‚wŽŮdŚ«kBđ‰PBDçU…Sš:jBđřrΑaź_zę ŰXW}ĄzŔp4Í€ŽXźSČp8Ěťs‡Ś1ë$ú&ryď‡ęĆŤąµVĎćsŢ˝r•‰(˛µ5D(AD!J­ĐĆ MŽŇ­5bJ´1Ě'S®ţčo¸öÎŰÔeEŢ{bđ‹ËŢ9fłŐtÂé‡NpěäqÎ8G/Fäu]«^xçž{îžŢhG¬‹/Ş#GŽ Dd p‡Ě‡R Y ÄH62e´łŻkomá¬m__‰ňŢß—šŃëâđáĂF)µôĽ÷ć6žHVko°®Śf¸µÉÁă‘÷zÉeůD:R6(Ą0F#*BĄ5EżĎ‰GżÄ;_e÷ÚőäcX’Ö{ęŞd2QÎfč[ÖÓBT]×÷ő^;b=@h­UڱpΙŁş±śs rµA”€'‘ËątQňૠ„™Ľň^ż‘’Ś!BŔZËl:a>ťâ˝G›,IŤTî[{íőQ×µ4äR€ş“„¬Jl~6Âe xďđÖĽ'8‡wŽ#AD#Ál"EXé‘ŕSĚË+xśµĚ§S&ٶ®™šŕ_–»ÇŔÇH#uÄzđP{Ž;bi­ŇöŢăę:]߉1•‰Äŕń1Yš#˘ôâňb7بďŢŞŞb2S×PŤĄ’&~kÖ Däľ«`:b=8Ȥ®Ń(B’NË„JŚMš%RWŢZZĹÖaëšÁ;Kڤ ŃGśsÉZ…H ˘ôŇúíY1¬łL'Şş&’\¬(ŤRŃ*‘+ifcD){UŽŹ@G¬„^xÇőH@ xED…ŕ­„Î;bđäF8ĽŢ'S˛@c ÄPJJ¨«çlşM„ŕ­E©äA‡ĎóDĚĆr…¨­c:™0›ĎÓ}Uc”J‡¨É‹ŐąÂĎ+ž~ó»?@iT^ĹŕUđ–L [ë=śłĚç3ęşćřÁ5ţé7žáءÍFMqRđžBҰDŇď1ŕÔÂőµiC"ŕ| ,Kfł9>h¤ ˇ‘9´F´^$©cŚ*ƨ¬µ÷ő~;b=@\~ď:J#Á‚UÁ[ząÂů ‰ë·eŚŐŃ!ĹV®9ÁqOB:Y= ÄdVBhâ0ż$ÚřŞ®kfó.řĆő% '€VIlUĆ ˘ZWř!÷^ĐëÁBB@BŚŞ9°Ö±˝;!xËú GF%É Y™D0ďu]Ň ÄQZidź´-ĄŐMşsHÖ¬Ş*&“ UU%Ň6Áz‹¨qŹ×k÷Fnč\áç_>ó—‚Äŕ%KŚ!ą9Ł"O‘ĄÓŇZ¬#¶¶Te™,PzeEA6XÇ{‡«kDtŃĂů¤°‹ba±jk™Îf”UE$E—‚w”nRF rIŚńviÍ»˘#ÖB|î9~đň«ŕÄ•4:Ö^Iظ@g±ĺ$íţÚj…F-Ź!$‘”fwXWX›$|]QW5ÁYt–ĄŘ,Ş˛d>źáC@”BˇÓFT *¤ú,Ą5JëD°FÓę\á>ŔSg"„ BŚ" RĂ-Ö`6ťńúëŻ1µ–Vsp.É ˘Yž5i¨Ş9ĺÖ&ţřCpcóŢűDkŮ[ęś§®-IĘşVs í*6*˝Ňeąh C(­ő}˝×}K¬ţđ‡OYkĎĆďď? ϲ썧ź~úĺ˝W“N™iíÎí›~FŇ —FHžQ%•]˛"Gb Ž`˝#”%Ęy´NÄc˘ â0˝>Ť-TŢCDé ‘Ö]¦]a¦YŻ×ÄoËŕ˝®ë_üëÂ… _í÷űŹ=ýôÓźőRîőĘ+Żś»pá‚<óĚ3»çzáĘ{[JB»#ŚŤrđ>P—%µ­Ń*•Ĺô‡kč^7˝ŽÝŢFj‹69ŕđ®&‡sç,¶.©« [U(­A˝jŇ?m?ěőľ8®ĐZűČ3Ď<#ăńxń}Ţ`Śá+_ů ?řÁn"Ö­‚cK¨#Öyjk÷$ˇI©ZşŐ¨B` 4Ô5q6KâćF–‚yg“ŞŻMŁ´;¬­q®FŤkň‡KbĄĺ(’rßîFŰŕýľß˙'řě>3„rHÍ•÷ëű?M(íÝ)‡l,NT‹¶Ě¤]k–P‹ü[kˇRÁ] ®Öú›¬Mŧ etJ·®®('ŁD ©ç3ĆŢ5»Ćôg˝~ěËRYW i;vÚ¦ Ůs{›/L1–bůÇpĎŘ—Äjüţ˘ೀÁ:ÇďüÇ˙ÉżűíÁîôfeúvÝ1 ®0ĆsçÚú(@ŁŰŇ—°¨6€ĺÎMkMďÓń(íâ´&8G|ٰ{L–cŠJRţ/íúRÝV»mw…J5·“‚wu“ň.Ţß_{á~%ÖJ:ďB:¶¶|ëĎ~Ę—Ď?Źw&÷­ÄRJIë^jë(KKlN¬1c41¸Ć=˛T"HÁ|»ŰÓZčő×Sţ1ĄxBLU .”1Éú´Ô­$…]±taŃ’…kŚĺÇęĽŢŻÄZX¬Ýp+J°¶ć÷ţ×Oy⩯ńÓźżFüPÁGX¬•÷NÍË9u1Ú`Ä2“Ň3ËËćçRâş•˘¨…ţ¤´¦.k¬s©6~ďm*éSŇć[Ć(•Úľ”Üô<ŇÔ^ÄUL’Ă}ˇ#Ö}@)ÁŮšßű“źńĺÇżJžç˧{#–*„ l]©čćč¶TEI:ąK´|ŽpµĹ9źĽO$˛“ý>:W„¦:TöĘ4îÍ4—˝Áhł´XJc@‰ZÔËk˝ĚŇ$ˇů"¤t> b)śłüç?ůç˙%ňřjU—¦e˝ľąą>ô “gięc*ŢK–Ş%T© ľ•ŢE„,Ë)˛˘H ! LFŃë“őzͰ kÉŠ‚ÜLžă‚çÚÎ.Ű;»dÚĐďő8>čsBiň"gsë µwüôç?gŘëQE“ö‰đEJBŻĆ ßţ‹78óčäEŠ©FăßxĽŔ5ťÂĶ˘łY‹ş»ěcäo~ňĘůăQľ>čăÇËÉcGČłÔĘ®TęP%h­‰d™–;CQ‚É2˛Ľ@›˙ô%Ő¶Ö†ôCL–ĄŘÉd›1«*®íŽ ň<ĺĹó<ăŔÖµ ú˝ś3'Np`8$“HfLSY‘’ĐÎą_|‹EÚ©,¶Éź-‘ďüĹ›śyäqŠ<#†ŔîdÂ7ÎeřşZ’Ş­8X>ô¶–łµ>ßżđ×kµsś>q‚É,ÍH)0šŕĽ âó<ĂÚ*ő6e3‹äsłN‚Ćű°ĐśDZ§”Pf±ň,CkŤV:©éJáCŔzŹőžąuĄ)úCâ(R—er·™YTŤ„€ň,ëgÎśQ"âďĹKěKb5~˙f˝çă?J„ďüĹ›<üČyň"#ÄČh2ĺ×ÎexW±č^`Yޞ|ÝŰÇXí˘#7FcŚ1XçO¦\ŰŢf^Η÷˝%řźN'¸¦Âł˝ÍÜi*JETę3 ‰Ä8·(±ˇ™"ťG”˘śÍ"˝ĽŔ7¤ÔŢ7Ť mŻá,µŽ zjD`YD©ĽwúŕĆűíďřČ"¸}K¬OŁdFŚđż/sęěyň<'„Čh<ĺ×ÎiB=ov|KŇÄ({R,JoYËŢŕŰ4ÂŁsŽ7Ţ|›\)Š˘h$ Y¬EhžŰ\5[´ŢKPUÄÉ!U´F‰ Ú‚·xĄ N©EBYëtz­µ µâˇC‘ĆÚ%beyFQdJć©ůbh4FĄ¬‚÷NŤ§óÍŃÜ>.GL1ÜÉ~öÇ|ńúoýÖcw­ŁŮŻÄ’OJ*ŐÄ7đ—oqęěyzEŠ;ćó9żůTŽňŃdéőHĆ ¬Ý2ľÚì=C®oBK.c’RQLf%×GSŠĽNȢš*–¦#YRţ.‹Ł’Đąą6äÔÖ8ĐT5´V.‰ť˘i$LlÖĂbäQŚsMčç„p¸yZXĂDŔ$U‰‚O=~6‰Xky˙ÚŐěʍɧWęŃ^ßćë×Jxl wxăě_b-Z§>Ž+T"(‰ü—˙ó'>Gžg©Ý\„·ß~‹ßyém¶¶¦“"iС5Í?űőGš×kw…aa±n·+l­ ZĄŠ˛¶Lf%µóMúF5A|óS$J´(ýgOž$ËsŠ^qSL˙-ň‹ëblóMÍ}•,Z9’ V‹Ú2Ť•K ˝W}‚QÔM»Řh2ĺŐ×.©˘čm?vôě°č}páÂ…ů3Ď®+ś—ły™ž„”«{ëęŚ —Ź>ňp2ý1Ň—)_;™ÍíM˛†_Ľ^c-b˛ywr…@š§›őúČt:ovŠ-±RU§néy/c¨ÓL‡|Qip—÷ąČ.í±H·\ż”Hn&Öň3\ZŘŘlHběŽ'ěŽÇ>p3'OSÎf\ľü:Wß»Ěwľóť;ŽçŢ—Äú¤Á{;J+xí˝ ˙ďÝČŁgĎ €őžˇšđŐ‘é-¤j^Ľ]CúIŠIîć ˝óSKUËÔAŁ“ˇUŞq7Mí”Ńšč=\ŰĹ9Gž™f·Ř~7“Üô»´;CšŠŚĹޱ}ŻvËË9¤éŢăOůʦ ÍGlŠł,çÜńS z˝xýú5wcwg:yÇ/â®°mčü¸˛Cf„źľ5ć'W Ź<ü0¨m`]ŹyęˇS5ŻuËk !îýDĺ¶ë1.šNťK•­Ýi]iŚtc!˘,Ž<Dgx46¨T¤×ÖQI đa$éV˘¤‘P–Ó••4S’›YĄŢ{˘siäQt¸q>b]š&ZŃlÚ!ÉŤam}ŁýFŚvwęŃdtcw4˝ňŢ{«»ýQď[b5?ď;Ą#"-ĽüĆ.Żeś=sš(`ëŔf6ć+Çeĺ0ZČŚfgęVŽ#Ţď ®ÍXncí †•´sC#&¶CŃA´YőŃ&’YÝśpHu ’fWů=ĉMŲ´( -Şiż×hŁÓHɲ¤˛ľmµw®9,um±¶nş¤-Ţ;D)†ý‚ëkl×ÉŚˇ,ë8Źít>ą6™L.–v|íG?úŃ]Ő÷}K¬[ç ß RÁüđŐ.ďćś}řtŞgw‘ŁĂ)Ź…ŞňŘőĘ5.˝7'+ &“ ˙ćź| ç–U 7Ć·łlK‹őÔăçąrí:“ŮŚŞŞ©ĽGkSí FY´Î0ĆaśAId<ť‘ĚdDI_űćhŘÔŠ˛Ť”a˛ü+­0MC«É J+v·o0ÚÝÁÖλfb`˛L•µ8—ܽ֊^Qppk‹‡Žp|k‹č|Üąq#ŽĆ“j^–”Őě'ŁŃäŇŻż>ŤńÁďWbÉýĆX"B¦á?˝Á{Ó‚łźJRC¶Ż_ĺŇűůÉĆ:ăy`Z ?|‚§żv­3._~˝±2q9|áÚî\ŹŐ˙úź˙KŢz÷^żüoľý6Ű;»Ě«:Y Wcë Ąt"—6řP“gBUW ĹŢ!Í7$µ:ą9¤JInP›4r÷Ć ĆŁ]ęşĆyG­5YfPZčk[››ÜÜbPHńę•ëq:ťŘ˛®F¶®Ţ™—ĺĎÇőä­«ýlôă˙ř#ăŹýJ¬ű–”Dţű_żĎőŞĎcŹśŔű¸Pť:ÄÚĆ:ÁšŚŕʵ«ěěîRŐďS3DŚ–é|LYÍSCC$ÍogŮŐÜęç1Ň 9nôôFA7M…B5źSW1ŚR˝››;|هŇ+I+›ÎbU–lßŘ µ­ęŕý$DĄ˛ĺĺş,ß,o\˝Ě_ţŢ÷îéß×Äş‹UÚČ?úúŁô{šy]3šEŢމ\™hÖEŢ[Ü·ö‘ůlÎé‘›Âß;{‚Ńîhˇ!Ĺ6x_„…Y{•÷+×®^Ű õőüŕÁćČáĂrţÜ9¬µRŰšÉdÂőím®oß`wĽËx2mĹHćeEU×Xç“”»p»{¤ĆE*ISnň<Ő¸çYŽ Ń*U’ú˝Z y‘Ţ(¨ćW®\ ăŃvĽ/&ĹŐöçŞwËŇߨvŢ›˝ôŇKîŁÜß^ě[bÝŻ+TD¦“]¦“ô»řĘ‘‚Żťęóćöś+ăHí„~yä <ôHқʲf§L‰Ţ¤PďéΡ ŕ—zËÇoĽö—8¶±¶ydcccs8ôaľľ±‘ő{=- Ę˛d>źSŐu]c­•¶ëŮ9GYUI ·6U6ŁąŰ·Żd©Ţ‡ŕ±ÖQ[‡«}¬ëë,¶,ą˛łçeL–ŮőőM+JŞé|6­˝˝á˝˝b«ę}Ův~>öŁQůâ‹/úű!T‹}K¬˝ß7óQRŹfj\H¤đ!0ťW0/9`§NöPJa­c:+ąľťô ­$ĺńš‰Š$kŃ–µ¤uÜ9WxéŤw^>:ź˝6ĚŻŻőűůćúćÁ›kÖë[õµµ^^ ˛1&×J´ÎłB;T^‚÷ҤᄆÖâ¬kä—š/ĽĂYʵ–élNYU±®m°Öz[Ű`mí­łÎçĽ÷µ÷nćŁK©v˘ó×ërĽ]×ĺD‰™NŻľS–eé.\¸>ˇZěWbÉ˝Ľg0 j'üřň„w®Í)m 7±­‚ÇOݱ54Ô60ž¤xFFjP\{.ľ3ćꮥňžµÂđř‰‚3Ú*‡´ž;®“#řźţíüŮgź-˙n<śçďéäÉ|}ĽŐ+tݧĹô•6kýµÁzžgCD z z@CĐ!ĺ­ç˝8ëć·ç|tŢἋŢűP×.XgťłÎZo«]tś…ŕgu5ź”łrŚňÓLJÉ(qÓęÚ›oÔEQř_|1~2íĹ~%Ö"xżősHdRĚęČŤ©ĺ'oŽxg'pâřť8Ń>¤JÎ˙zá 9–'OyřčcŰcË[WgĽö~ :çŘŃ#:1DkŤµ–\z‹Ă‡›žBi…Íx[rí‰Ű  @őěłĎN^{í5Éó\;Ţś8{Ö ô0Ď´h‰!s6šč˝©˝5Ζ¦®ťĄ´11ŠŠ*â­Ç{ëĘëk˝·ÎoďutâµËzÚ†BYçk§çÎ~đúUWUoűS§N…˙ńµß<˙<ź™öb_+„°p…{!F+ţŰ__ăƆkŽ9ĂŻ<Ľľg#Éč:L]×\ľvŤ^Ţ!„Č`ĐăŕÖaÎ?±™4¤Hš ĎrÎź˘‘ĚCš‰MŮĚm×y;E~™ Nđ"âžţy~üŁËŐ«WŹÇ˛»»+Î99tčL&Y;}Z/ qŚF#*kăŰď˝Çóyȶ·cŻ×‹EQÄ^ŻÇŁŹ>ź|ňÉřüóĎßúú ÷řUĽ÷‹}I,Yď ĺ˝QÔ˙đű°uä$?vtˇ1•ÖcëŠÍ sđ>Gň˘O–ĺś8q‚“'O¤çiä`<ŻČĹrhAĂ´‚ÝRłÖď5•ž±)»YşĹZß]pËÉľŁőř¨qŤwł<÷ú]Îźö%±Ľ÷ęÖŻ·ŐůŁď_ˇč ë[‡(mŔÖ5‡5Ožô=Ue±ZÖŕIDATÖˇ•đô©Śg\ކíYN–e´Ű÷ŕJNś>č+ϬŞ ĎsD.]©ąĽŁ1ů˛ŽřŰX¬Vyżß‹wĂ*\ÖŞ°/‰Őţĺîýśť‹ü«ř%‚äÔˇFb`hjFÓ9Óńś&ËŞ€ń,‰†O0čGĘŕńAȵGGËîxÂtä™íůČ鼆9Ú3ś|ť(ţî‰#̧»Zc»¶O§=m˙a_ °UUm‹Đ‘7:v÷N˘ŮŁyí%äÎhĘŤÝÉM×í%`[MŢ^PŐ–÷ŻlÓ~«íí*9•RTU…TźÖ›ŢOŘ—ÄšÍf˙÷ŇĄKżţČ#ŹPps™îŢŁmR¸Űő-ö|1ч~¶.mŻđykŤÓ^rZkąté;;;ÓÄ„źÍxçĎűŽX"’o}ó›ßýë_ßÜÜÜĽŻ ‡OÜ6vó¸D„ŃhÄK/˝4ţÝßýÝëŔ|˘Ţg¸'ˇńó„fđţ)ŕ°dźíŠîO"ÓŔë1Ćű‰·Ď±ď‹ŕ=4ó»^VŚVő€ý˘ąAاÄęđůÇJ'ăuřâ˘#V‡• #V‡• #V‡• #V‡• #V‡• #V‡• #V‡• #V‡• #V‡• #V‡•ŕ˙©(ű*Ö~0ŃIEND®B`‚gammaray-2.3.0/resources/kdablogo160.png000066400000000000000000000445431255003167400200600ustar00rootroot00000000000000‰PNG  IHDR  ‹Ďg-sRGB®ÎébKGD˙˙˙ ˝§“ pHYsnşnşÖޱtIMEŰ :®/Ë IDATxÚí˝Y$Çy&řą{ś™Y•™U™YUÝŤ8 ’â5ą#RÔH;c¶fkÜÝŮ•öAk6łf|ÖŰšDrVłŇjů0;& (Q˘†”ÍhÄ 5"ŔűA˘qŁŃ軫şŞëČ3÷}LOOwŹČ*h¤v ]Gdd„Çď˙ńýß˙˙Ŕ­×­×­×­×­×­×­×­×­×­×­×­×­×­×ĎĘ‹T9č©§žÂ;Ţń\şti#Š˘ŹrÎ?’$É]j·–đgűE)E«ŐqÎĎŹFŁ?w]÷Îś9s˝™ ŕ“O>‰wľóťxá… ˙¤Ńh`}}ív„[OŕÖ 0ŹqńâEôű}ÔëőOÝwß}˙´ťc ŕ“O>‰V«µrtttÖqśŰîľűnřľŹ$I¦)8ç·VţÖ ”R0Ćŕ8&“ ^yĺ$Irqeeĺýýý#›’2Í÷ôÓO_p]÷Ě›Ţô&’$ ’$ÉŢhĐ~Bąż? !¦ď“ŹŃý]w>Óßmź-˙Ţô^ůü¦k«ňUţţzť»ęgT]ògSvnů˝ŽăŔq<űěł"I’K>řŕí6MhŐ€Ď?˙üĂišţ“7żů͢I’€2w3'vB_Çsýgqš˙ »ŢżŤc žçáŮgźcěS÷ß˙?]Z^¸pac{{űÚ<ĆŇ4˝µ˛·^•^…&LÓgĎžEŻ×ŰĽýöŰŻëŽuL'‰˘čŁőzA`8wţߍ šŃż Mf;§É ‘Ź—M_Ős÷~L.Đëu˙qŁV«ˇ^Ż#Š˘Źřm­˙h:çü#˝^oęóÉhú޶#Şo[xŰ{Š/ůç*×$/XUˇ]ö>uBeúLÎyĺő9î}«ď/>·ę{LçĐý=Š"ôz=pÎ?b `Lăř®V«…8Ž­l§Ę‹Ł:®ęnłÝT•Ĺ-|ҲE3 €Í™×]Ç2Čt¦ďMľîLšp™Ď7i^ŰgÉkŁ®˝ş)Ň4E.Cw™®Ď±¬gŤRŠ4MŤx XU+÷łŞ<ĽŞÂ˛Śđ-Łí—±&UďĂvťBPJŔ(ç)•7lŮymçáśR XtŮ YĆtžÄ‰5iľăšŞ&cYósŇ{?îć]§#ačă˙âŰs—ŞęůŹűů: r,¬â˙ĽŢ‘â|:óZfrmצľ÷¸çQŻń¤÷yŇcĘ…ĎĂżô üÁżů‚Ŕ_ęüÇý|Ő4ÇĎ©Ň[XÚy/BÂŔĂ_|é)|ćó_Co} T :ţ¦źC•s;ÇŮ©'ɨčqwŘIĎaCůË2ÇɸŘ [v¤ĘšęÖ‚‚ đđůŻţńč÷qzł‹+7njČ“<ËŞAÔŇX=™RXËâJ¶ăL¸—-(:ÉŐEĄjÄlúą V§~†)«d:·îţuĄ5ßĂż˙ĘŹń×ßx·ťŢ€ë¸čŹ-2a»Ý5W‘‰ŞĎ¸˛ Ö €úűâçâ_Ű.‘Í€-ĘŇ/ź_Š´¬ď·ĺ;uŕ°ú9şëÓÝC™ Şç×ýŽ‚4M§÷eÂ,Ős =˙öKOŕËß}·ťŮÂĘĘ `ďp.ŇěOhŐĺ2mxÝĘď}ÝLp\ ŰńeY“âű˛L€m—eđ5^n7ę6“ #´]‹é~MBXőüę}ÉÇŃJŃÝ3%őšŹ?{ä |íĎá¶3[謯Ă$q /@ÜşŢÓóĺźU¶V¦Múşŕ* Ž*¬ k2UZÝĎ:MĽěő—iÔ20ľLĂ›®Swr@¸(őĐÇçţúGřúăĎáöÓ[ču»X]]…ÆĂ!ę@€[Ý$ősm÷¤űý˛ľ`% ¨3E&ú’íA”9ҦăM&˝Ę.+ޫ۽ęď«:ĺË`Up¶*>ł „&¨ţô ?Äwž|·ťŢB·ÓC»ÝB-¬AŽI4Ąś‹ˇ.{Ž:Ą ®źÎý¨-męŇ2X–MÉçUŹ_ű“M{YÚp>[@J•üô2ŕřë{Lď@=ôń'_řľóä 8sz ˝Nëëm¬4Ś1ä'Y LĎĆDtPŹ—}ĐŞŘßŇQp•”’ÍŹ«â˙™nÚćš ]PaňGĺť,›ś*δí÷&íb{¸¶HT÷ţĚězřăżü>ľ˙“s8sz3Ó|ë-4 řľBÓLřČňC˝v†¨Ţ«ĽžÇ2Áeôqnä8)([D­‹Ŕ–ńŃ–Ý­¶ Qöůęߪ:l?SBP <|ęóßĂgĎăĚ©Mt;]´×ŰXm4Ł@*BëęTY[@¶Lţ¸˛ ®ŞNUD•E-»PÓÎ×iťÉ>®Ů+sĘm]Y4X%X{-„ŻQ÷ń©Ď?†'ΞÇéS›čv:hݵ±Zo p=â€pA efř8ě™erĆečÁRsĆXĄőoJ«e˝Š—W«^ëqď§t¨…úóďŕÇĎ_Âm§6Ńéő°ÖĘĚnx Ô-î“«×Á+G˙Ëź.N¨’Â- Bl\ľ*‘Ú2BV5ÂÔůŹşŤ`âýéȜ˚eťć_fMŞ Ý ^óńĐźO?§Oo˘Óëb­ÝFceeNř¦xLÁ_–Çh»O› :eŁ Ł2eiš2đ˛,dĂŮĘRfş+²´[Uľ,)uEÔëţŕß~g_ąŚÓ§·2łŰ^C˝Ń€ë»s23KŠ €Ńo.ŹË¬•mmL´~Ő52eŞ*ံÔUFX¤ÉäM‘¬*ř”RkV—ú1Ąu°Š-*UÓ{ęűÔűQ…O~ż.]©~–-UG)Шůř—öM<ţNźÚBŻ×A»ŐBŁQGŕ» ”BŠűÍNrł/h–×Y÷{SćIÖÎqYÎŢČ ů±4 )-¤>(ˇ3P"Çürá#ćg+ݵĽ6¦kŇ)!UËýŤdB^Ź"$™¨ jN›@ŞZĆdtř”Í´č>_u7Şř†ştUU‡Ţv/ŮĂę‡ńąoâĺ‹;8˝ąÎzkk-ÔĂxž$| ‡$|ŤP€SÉŻ[6]¨ŰŕŻKR)sę«2ŞMTʼn·%ËuÄU3– ߲YŹ*ąbÓz<·űÉĎ~/_ÜĆ©Í tz=´×Z¨×Wŕ…>ĄYŽ)Ę2÷U /3ů«TwbK0T `TsýşŔ0Ë,ř2Ńź.ÍŁ{ż-'\0­l—ÝKŐÔ^U¤Ű”4źüĚWńÚŐ=śÚĘqľVŤĆ*<ĎŁté岰Ń2d_ó¨ěţéë!TU0?›iRý °]––[FSÚękmPK™ŕÚ>_-U5űŰőŔĂ˙ó™ŻáÂŐ›8µµ…Ť^ívćóyž ć°c ßq0Ę*›­Š°Ë\8VMšŤ%qÜĐô}™–\F ÷oÇ©v+„ŻxřýĎ| —·pjkťn­VőF®ë9™‰>‰đ•YňPUáś(·l]­NK¨L › ˝ŮSˇô˛Á@U_ď8BlJł˘ß˙“ŻÎ ßZł…z˝×őŔX.|¤8¬_á3ü¬•uL%“%*[Ç2Ľsé(Řć˙TMZ›˘©˛ťUĄĄ đ>I˛ĽŚ/W…[ö»‚Ď÷{źţ*®íőł€ŁłŽvł…úĘ \Ď•(U™0UŇňY,EŔY*N}żéy~W&„Ëp+™`] TµEŔ¦‚÷΀«°‰É_´Ń…l`¸úÓçذGumL÷Wř|˙×}7npz«‡^§Vs ő•úśđ§bnÁ܉ň66€żěů,‹”FÁ*ŰĦfu»ŞĚT«@§Ime¦żéľŻú^Ó{Ôkµ5Ú4A<˛Ů­ţů}{‡#lmm Óé˘Ůnˇ^Ď…Ďa ‚XH˛v!äŮ…@>ĚF.#›Ň“¶LÓŇP§őä4ŤšVŇ]Śî÷˛IÖe;Ô´ť-á­K}©i&›ŮVŹ5i]őšĘŞâcfŔ1P }üó?üöŽ&ŘÚč˘ŰYG«ŮDŁ^ë;`„f~€@ľîą&ă3ÝF0ő qńE 8źŇňËLf©Ř¦%«šáJą`5Íd󳪦ƊcuBbJŰ™4–ηҥ™L×c+PץU ur!Śľ‡ßůĂG±ßʱµŮEw˝V»Ťz˝Ç÷ňsçĚb¤>"ŔŽ4ĺůÚĚz4 śŚ ç=äŻěśĺţ˛îŘ4ľ-µyâ(XM2Űü']…›îÂuä€*|2]‚܆5ę¨÷¦Ĺ«roe8aYPÂ(Eŕąřť‡ĹţQŚ­ŤŤLřšmÔ:<ÇÍĚn‘^€ŕ‚ ¤QŠx’ ß  M"¤IšŮŘ<ň%|Aň¦†¸ ý^¶(U3(¦şŃśs¤iŞR Ćj.e[ń˝|śüwő8–$˙MNŰ{Ôăt×`úÜâXÝ÷&IwNůó(%đ]†öđŁ8eÂ×é¬eÂרà =PFć$‘®)ĺ˘G‡ńżôs¸yx„ńxś?#>}Ď,%Lçv! :ľˇÚŰO·ÉäµĐÝżú÷ĺ‚U3UÖ­ĘĆš(Ó–&ŤÎá7ĺŹĺkÔ4şs™îIw ¦u1á‘ňç1Jú>ńđŁčŹ“Lóu×ŃnŻĺDî«EŐ˛…íť=é>đLëÍ ťŞĹĽ šµ|´ŮLőĐUž÷±˘ŕ˛ĺËpĆŞÖ˙VĺÝéj2t×l25şHşJjN÷*ńó%đ<żýĐŁH9ĹćĆ&Ö;ÎWkÔáćÂ'›]ˇqˇ?bĹOń«ď޶Ň\y^—č5űˇ¨CÝš2ĆđÎeŕ”eDKłalZƄוág¶ămź\¸¤{ŹŤQ]5˛LVŮ” Ź=ôEÁ°±±őn­Őjµ™ć+„ŹKÂÇsÍ7‰# ÇX 8~ĺ][¸ľł;Ągëp2‡·L‘c .(BRń™,C@.µqě ¤Ŕsl}đl9bťĐ,Ó,h™»JPQőś¦9kŁ«d”Âu>ţĐ#ÔĹÖFťÎš«MÔµ™Ů%’¶FA«âŕ©@Gč÷ÇhŐ>üÎ \ßŮ®›@Nk­Öś+()"ŔS1MĹ•ů°ş{,+ɨŇĘx)¬35U.ľL–UďU´­éQU*–nĂUé–E)s~ű_?0[]¬wÖĐ\mˇÖ¨ĂóĄ’đń©9"űŁxŚŁţ­:LJßŃĂőí˝©vTÓc$ʰçő›Mć2HË;Yé„ÍĆé´UK[šr1¸ĆšňľU…Đ6GmŮU+ÔĘře›‚±,űń‡s\lôşX_ë µÚD­žG» łh—g6tęó%qa0c­.đKoßŔµí ”iŻĄxÓ~ ˛ĚÍ ‚łh—+r)D‘YŞ(˝ę(W5“r˘(¸LŐ–u'µ1%TŻ ĘL{ϰ ŠŃmÓÂŞ€ő dÎ{č‹pÜÝ^kë4W›ë™Ď©zm*#Óh—#J&8ŚĐ­|đÁޜٵĺĄy‘.Su dŐ”pšk\Űř-“ů-k ľä)[ÇŔeÚśU­«`~6á2WĆĽ©ÚŤ« n8>†Źý«Gŕú6{YcČV«™N&|sśJĚ ß$š ?ˇ»BđÁ·u§G”KäK p ňѢ´¶ŁĚ’éŕšă`´Ö(xŞęKUË«ř†¶Ş8›9ÖQý«4L_¦\ţJ (cřřĂ_„ëŘěmb}­f«ŤP#|ęýÉ·ąJ𡻸¦źÉwťÍˇXţeŻąÖÁQeŚ'ŁpixŁKiŔ˘ç‡ă8Ąš¤Ę¨xťđčŘĐ6ígę­brMć˘LËŮŮŮŮsüŘżú"‚ †^Ż‹ÎÚV›«S¨dQřŠk—…ok•ŕý¬ăęő‚Äî*Čž‹ňd?)1\Ţ`H‡WIDż?± Öůc¶îU˛6ҢmWŮňÇËNă´ŐĄT‰v!€ß~řK¨‡5ô6z謭cµŐD­VĂ’·Ä…˘ůĆQńŻż„z­ŽŢFkíu¬®6†5¸ĚÉÚâBÓ}źiÄ1‰3Íw¦Eńóo΄Źh:Q•A]iĘ3ÁJĺ›ćZJż z™üxŐ U[˛XP%•VeŘîČöe`Žăj:›ßY´ÓÍęĂçśQ€âă=ŠZ˝13»«M„őZµ0:ÍíÎVöÔÓ8ľţ·Ż;xď}M\ŰŮÍ…hąůżÓ€B 4H,Ě›;MÓŇ6,Ë$&d"óŇAH•á46xD}Ź®~˘ěłM粑H«śS×8Gn«¦^§ë0€8řŘCŹ˘¶ŇŔćFťn««­™đ9zá#‚#‰“™đufÂK©ĄŤšĄüf˙.ű’ëzÔ5Ń‘P«¶[łuö?Q*ÎV-VěS-@ŐůËdTŞřIËl×ÉE”püłO=ŠŐĆ*6ş]¬w:X]]E3Í'Č”o73I‘ŰíŹqW×Á»ď]ĹŐíĐ语«‹"ĺ5ŕšôś%ćČL·ŕ(Ü2ٲ•ÁTUŠíuĺe> -{(ŞéÔ1N䆊etśă42Ą†ĘĚí˛­…çŻpE’ |âS_Ćęę*z›]´×:XY]E†p<pčt%‹d')ž _ż?Â]]ďşgW·wAµÖÔě[#ÉâáĺŹ\ę‡Ęsá,~#¤|0…˝#BY,`2ŦFĄş¬•sÁI>Ţ˝°ĺşÔŠ,I’XťyS^×”k´±RlůČeóĆ‹š5ű{”p|üá/Łąş‚Ťnkíu4WWP CxŽ*2č¬9d¦úHĘ‘đŃ$ÂáŃ÷ô\ĽëžU\ŰŮÍ#dűĚaµ°K.š;!łľD §hÉÚx­äâ¨2‡Ę0AY‹™ę¬ŐBĄׄČB!HŢ•›:üÎQ©´«*IŐ4 ZhšFřÄĂ_F«ŐÄF§‹őµőÜěÖŕ8N^ ^@ ŇFI’bE8ěpß©o»ł«×oLŁ]Ű:™€yíĆ+°€y _üąj}o™2°Ťę-Şă %v,¬–ÚŃe[KڞĽ¬ZúY¦«E\t+2ź/N>öđ—Ńj6±Ńía}=Zjy GĆF! Ň ÎΧăÉ7¸o+Ŕ[ď¨ăúöî”|PĆ$Yjl—ě’T @¸ĺcsaL.Í×/ĚoYT]Şm-+Ę|˝*ä[te«°/kůkŤ`ň Ć0ŽRüźôU¬·Účv;hŻ­aeµ ż‚: ">ĚF! s’`4ăćţŢrG o˝łí{SAYfÚ¸mÂč‚vÇ VC›) Fů}ŐĚ“í™če§ŮWę #O‘\X®:D]TµĚ˛ŚŘh*Ϭ2”zşŚb” _§ŐD·×É5ß*ü0„븠”L[¤Í\‘<Ú‹ ‡#ÜŘ?ÄwÖń¶;W3ł›çŤMnÎW’ë3¬×®Ő––¨Ěš”›JYMÓŘM.”ŤUsâş`•űgÂËÚŞé2Uć§UáęÚmňÇ&¦ ĄŁIŠßůŁŻˇłÖD·×C{}-÷ůB0悝č‰Ô‰>wîÓ4Ĺh2ĆŢÁ!Ţ~Wo˝Ł…ë;» 9ű9{`Y+¶4-¤@ѧEíV—Î -jH3F+ 7ŐĆ:*Sel$Ýł>¶ .3UЉŞ2U©QĐadU˘e“Ă dŐkI‚ßýô7ĐYo˘Űéa˝˝†Ő•U„^ ڱ™ćyóÉéâ)G%'xóÁŰNű űh6üiÄ[•Öý ¤ŕ‚š ;’|¶4č'S˙mN[IÝPg)çoľ\“CR‰|P%ÓT–9‘ .úÂČlŚ˘ŞćŞ˛lŽŻ)p°5ŞęŁ2FѧřÝ?ţ:şëk™Ď×^ĂJ«…ŔÁ\6 8 ű6?î «ŻHEŠ$‰ńÄąC<ňřk8::Âx)„Q‘•Q’ě=)T,™›‘•9RΑ¦ Ň$Á$ćřĹwß_˙‡ď@óŦL:e§RçŽ(íhĄł6$»B‹AĎÄláHö?Ćxž‡vsµŔC’&ó“±Č"Ô#4ŮLř&“ýŃᆵ‡ôţű1ÇĘ&“˛.JŔAôVw¶°&U‡ĽŽş±)ň-łNKiŔÂtg! Đá>¶~qj»/“‰¬2ÚA‡ů•QÉäsşĂŃ(ĆďýÉ7ĐY_ÇF·‹özV˝*šŻJŽŮqaB ‚ Dš&łFáEş‚.šÇb?·ÂsÍEö‡ř?>đ¶3¸r}*Qµ•‰!±<ÔéąÔb¦ŕM7·O¶vşg§ŘÇŽ‚UM˘k(YUPl7T6¶Ş,ň55•”óÔ$Ďí #üţgľ‰Ţz'Źv3¨E>XG!B xv/Ěq×uň0·Ë ˛B I’ĽýÚżňŢ tjî’ Śâf‚Oţ›oŁ×]G§ÓE«˝Žzs%‡ZŘôa )Ř(3g„’éŘe  Mó‚ôGĂďĽ§Ž»{¶wöć˛'Úbů4ť«¶Ě( tîÚąŠgćđĽW´Ň#g™’VŁ{ž'Ž‚uČw:^•צóĚs4˛`„ŕćŃźüě·±ąŃAw˝‹µÎ:VWV!ćLű|Ë&¬”϶D/d-Ą,ĺy}HÖŠăťo¨á Ű;EżĚ}™˛”ńf#=« ý«üĚŞ¬.3¦ł‚'ž˘›¬.6u°‘tHz•îŁj bËMOĎź›ÝÝţźüÓoasł‹îÚ:Zkm4ęőlÜ)c™;/Pš\xĘb±áwĄ|lĂđ4Ĺxá¨?»îŞáöu;»{s¤u=ć ľ\ł Ů›ĹѰdÁm1=ż2!3Š 4á~şążeÓL»Ä6E\gâM "żŹRF)vÇřż?ó lőÖŃn5Q_YEp›áxi.H¦…Čň©9´’ő\¦sT’"2&”N;ŮWu¸‹ô™"#ŞÂww gÚ ×oě'µ/şFÂč&«rAŤs™mS/U7Ç6}ŕÄjtÂb Ám~ś.QąěFĘ@MŸ´ÝÇďýÉ×Đn7A.┣?Š1Žű3™d‰ŕ™f˙ňü!ç÷ťŚ9|őš ĎqÁŚRp«ÓZ !Ňś®ut4»ď­áTŘŮÝ3Â:Má€3ÔOĆeśq€& Ä*Z{v“ę.»5‡Ľ¶ś°IŰŮ´ š ®˘Ůl™]€ŕöŤüńÇţ1z[gfʧó\:#V&ůA’5âĎďâÜnԟЬą¸AőLyÉą&iŠ(Šqx4Â{ßXĂć*°ł»?MŰ™r¬‹đ–ě @ę 3dŽł0#PčĚĄ kUĄ†™6|¬(Řq+&gâ·Ů´Y•đ_Ĺńt~† Áçđă›GŘŢ=;'¤ęd¦y&Ď3Š4ÍF+p.ňFă Oťëăą ôşkor3l⢗KE8ŚńľűęŘhěܸ Bhţ9ÜŘ c! F#lŚBěÚU­C‘Ź+˛!¦y¶ć'2Á¦QTel őAWaĄëŠŻ3ĺeQÔČM¦”Bd˘¶- IDAT¦©%éŇqŠ®ˇˇďâ»Ď\Ç÷Ď^Ĺ©­Ť\KP#ô˘ľIáđhŚźżż†őZŠÝ›‡ #ĆtŁ%ŚţŐ’1ČěşH%¶ü{u˝Ląů˛ôě‚|•™`SS=…̤–ń8µ®n‡ë ¨Q·­žAgVL׬^Ź:ĐFîRřľńÔ%|ĺ/ˇąŇ@- ŕű>Ç™ůłd†·©ś˝"Ú=8ăîŻc-L°·w0G °Ť?Đ Ă!’yçÚśŻŽ‘•eMÔd‚©†FÍvČß›©Ďş ’©TRĆvÖ‘T!¨ŇřÚ”cÔ‘LmjžZj/Ěś@ş°!˛.÷ľţÄE|ýńWpúÔV6^ˇ±Š ¨ÁőĽ ĽÖjăY µI4Áá`‚_xSí ÁÍýĂ…`Ŕ6śŃt߳ʷy#k"#TM‘UmHUe^đ±Ë2 Žc+đ+ –n·č4ź©ąĄĽűŠ†Ůş¤SřĂÚS˘Ş]yß|âś>µ™ŤŐjµŃ¨‡đ]Ěu$ š/_š•qC|ŕÍ«h8v÷„Hvü“$Y€¨ÔŮvsëZÜŹ( Q´cPq&‘ŮyŞÍ±Ť°0Y%µzR.é]ÚËČ”…¨ ż,Cß·Ě&UŻŁ™|B›iŁąćűęŹ.â[OžĂéÓ[č¬gšŻ^kŔ<0Ę0×Vc®ü–#ćŮ…ĂÁ˙--4č»űÓŤlJm-Ó)BHćW,DáҸVeŚ\Ób{>Uš·›:ť©VńŘ&Xţ’ě»ŘR2:gWw&3¨ŞqSÚ6.Bgzu›$3»™đť:˝™M0o­ˇ^«Á =ę@dťľ3č-/çȦĹôÖUxbýŁÜŃe™¸’¦ŢÚĆ&A–”O¸Hµ„ʞişN¦ôiU(¦’4͇µ¶.ů6•/k×*<4?±lđŤşřÇđĄ^ÄwžÎ…ŻŰE»% ߬ëé|†CľýŃzkďc˙ŕP+@UşőWŮ@©°µD0ç‰Ćgnś­†Ů†Z,%€ËDJ¦ĆE¦‹ÖŃću=FlđKYűX]őĽĘx _~ü"ľű“ó8ł•kľ•\řĽŚ8ą÷”ŹXŕYd™M1—…oŚ>°‡a˙°Ż (t„ZSµ¬Qµ T t fSŇźĹ$긩»ľaMMÄ6d܆ ËËÓż«4·™ô*“‹d?Đ6Öˇld«~ Ô|Ź<~ß˙Ék™đu»Xm¶Po42śŹQ¤H”¦bŽošrÄQ„ŁÁzë*~„ĂAé •Ę^µ7‹vS+_˛‡Ŕ•c_¤ĂŮŠËuÉ€*ĘĄ*«r›őŞ­cM­tŽ´Î«ÓĆM¦ÉqŮȱňőŐŹ<~ß˙Ék8• _łŮÂJ#×|Ě1O0/f|D1ŽFüŇŰWAÓ# K óm€Ľ)ZW5xü,ű"ŚX1>Ů 2A[efZGóZZĘŘVp^…ˇ,Sűu*ŰÖ~BőótpOŮ&Ů_,€ěŔcř뼆.ź _8Á/?¸ 1ÚÇá`¸PˇöW\ěźÎź$É·’różt.8M!µ’ATżÚôlMh‚môëR8  ”–uÓTë~ĺ›PëJmÂ*źç8 ĚĺëUIE]„ďR|ńŻáńg/â¶­-¬w×ŃlµPŻ7ŕ{(3ĚR“„oĹ'ř® íă¨?Đň&Ő5)Ót´¤…Űôď$·µeUJ’j’¦˛ZâP6»Dǰ±iAZU•šü®"» vÔ—oFÝѶŕB×$\=ÖT´.çt Ó)ëPŠšĎđĹᅥ={§7·°ŢYGłŮFŁÖ@ŕýŮ\·¸"o“‘Dąđýr.|ýţŔHđ4Őł<ÝeŚé™12Č'Ď“ńů3.Uš?Ý1ln„NNtÝU—âŞ_&a0©kÝNÓ˛Ş`› [Ç~ÝńrqRŕ{řŹß}O˝p[›[X묣ŮjŁ^oŔu}iIJ–·óPKšfšo<ÁŻĽ}“ţúąŮ%BŽŻdDFH¦m0–éŞIś Š…1·>Ý\¸ŕ¤şÉłj>! ä(DYä‘·±<:ź>ŽăĘŚü»Í )ÓŽ¦˘ä˛š][:Ζj+v˘šĂµ)«%đüŐcçńÔ‹W°µą‰®$|žë9š™nĹ‚#I8˘h‚ŁÁ˙đçZSá3ů8ó>4‡Ă(\‡‚ŠË;}\ŢŕĆţű‡c F‡cüŻż|?ÎôVüG-yë¸0f zĹs±T5ś- j*ǰ•|.ť )IĘú°ĚŻI7Á4¦,€©|pş„ ôüŐ÷^ĹS/^Ĺ©Í t:=4[MŁđ©<Á4N1śŚpŘŕż{OoAřLxŁ” ¸®‡§^ŘĹŮ×vqţę>\‡Â÷\¸®F(@<ÔB A84ÓŔŰ<Ǥ¸·%1čąB+SăK[-Š)(2‘:N¬m\:ŁlŔ®lX mfŻŽ ă ŞM&| _xěU<ýâµ\ř:ąđŐá»>¨*|y’?ëZĹ‘$1†Łv÷öń‘܆ńŃ.ĂŃB”7?D€1€ŠÇÎnă‡Ď]ë0‹3[řžÇuÁ‡2p¤'1ÜţŚŃ©†R]uÝąĘA¨(†şµ×ą>şŔĂä2™Ü§cŃe´‰&^f6lDÔ*Ś“ź˛]ĺéµ/<öž~é¶¶zX[ë`µŐF-×|Ä™źă+/¦qšu=Ýľ±‡ü÷oäź _áĂ.4ŕş)~řÂľ˙Ü5žµµ&jA?ŕy><ßë¸Óŕ"MSŚGCÄ„M»8$IZ©‚Y󍹪8ˇ©§„…\ÚňŃeÁ…Ťú&›^µ“ĆŇ&¸»`2±…V*°«˛Y¦4Ť©ĐÜÖńT§dMć{ ő˝\ř6{č´łQŞőZľăg8_ц/2™˛Ć“1F!~ő­5¤ŁŚF#0Fó "›lYřvŚ2\ľ1Â/ÝŔóç÷P«ůX_]E­VCX !‚ €ëş•ź00‡ć~"€pĐův&2,ĄsUXL…ČtŔ…T‰&se{L(“<¨×YČб4 JD59Ą:śĐ6FµJřoę˘`ň÷f™˘zřÂcçńĚąmśÚěa˝ÓAł™Sł›CZ­"f\šÄřÁs‡¨űuźŃ¬)ᇇĂ{Î]?‚Ç(ęőÝ5Ôę5„A ¬ÁBľ‡ş ŚÂ)  BŔÁ!sX% ‚`ĘĂ” 1D!rż%µ”UW'űpU ’TźX®¨<6­B6ĽÇÖ WÇÓA,&ÇŢ6ĆjöąŤĐĂ|ě5“ůž¸„€:.¶÷ .ĐÄIÖ”e}=Ćŕz.No¬Ă÷}ř^€ 7·ˇÂó8®ĆrěMé9H3¶3n\¬ĐĽ" k„đ4ďţ@¬% :˘IKę„ďÄ©8eČ”ćŇEÇ6Ň€ZsŞsf« `5ôţĂwĎăŮWv°µŮĂZg­VµZľd8_®yŠ6f‹ťä3/ŠP ÇuÖBmA€µ(O98xUłL#:ŽÇqáş.|ßëůp ć9pˇ GjˇĆźÓ"sÝ÷m"Š)›ň†…Ίć…đ+Zp±­I5ŽĄŽ´ Će™R Zľy5O©:â¦TŽm Ş+2ĺĺë™÷Ť0ľçÎď`sł‡vžáČ&{Y·)d3yi#ˇ¬÷‹ë¸@iş°VCĘÓ¬H=J((Ł`c.e ”ÁaăŞs=¬UvQ-𽂵\÷ÚěŃ[^ë3…~¬jŃ@u§lłťMí•ĺ´kY–ĄŇ´Lygč*âŠß›ćJ¨„ÝßLůSu!Šë(ľ„ŕ¨ů.ţżďĽŠç^ÝFŻ×E»Ýʺ܇!§¨áČsˇ|VSK@ 1<:Ę_îXˇže”­Ąř€&źDuTuţ‰±b#a–13ü !Pó|ţ›Żŕ§/_C·ŰA˝¶߯1B¤yłpJŇ\#a6­’pA¤Yo…!ůttB#ŔDް|®áótP׼_'źKBéˇ@€s2mŃ–Ä)’8AšŠ\0µ”ZĐÄç:ˇ"ŰF¦8.gŃ”´EÖy˛˘Đ&6S}ll®…Nť cĆÔÓEÍ›¶9ÜĂ9‡ç0üáz—®ďáţ{Î`Łł†vsaŕ#a<ćL\—Âa žKAc™Ö"”dł9rÎłLčśţ;P“uÄô=’{/ßč|wÓĽËxžYÉ»FDiŠń8Ć$cĹĺ8ÓńxbNHL,Zô¨Î=•ć$kĐaâ–Éͱhu7”µÖ(K^ZUml©ŁŘŰβ–• Ç!Úë-čD7÷#ěîݵ°†Űš«x÷==ěĆřÉů>^Ůž :đ\Ë€áéýNŤ4ćü02mď[t-ÍŠ”â$ĹxŠŢQĂ[îÜŔ`0Ćîţ>~röňÔŠ0Ʀ`­N¸u%ťÓçR%řX” ŤŁXÎ0ĄaŐĆ*"bjŻW‰’oŞ|7 :ŚHPcŞá0ů &6±ěs.3ʼnR F&“ ®]ßĆĺ+W±ŇhŕťočŕoYĂ“/âě…\×…ç»đX>7„0đ‚…,f…"÷ë8˘$ĹpˇÓxĎ} ܱŃĆŐë»řÉŮćJÔ,“‰…b$µsÍď•c––#šD°4¤PXhĘÓ«]Lě#ÂQŰÍť( ÖMC’/B9LWĂ{fdŇrI’ĚiÍGţ\Ő±6egäű(ţ>ŤpîŐ pĂíÝŢóĆM.]z ăń$ź´I­uj)nn›ş”R¤śç˝­AhkgQ 2Q×Q‡ŰćË©ĹgÇŽ‚ËFq•qu]RM9ÎŞµ±¶ŢҦ>…&S­°€ă¸ŘÝ»‰»{pŤzwujüďĺ2k_׎1îăâĹ1†ĂáÔĽ2ÍśőšuĄr±w9é4a˛§68|šC–…D& hb* ´nö_Í˙ŘQ°­RÍ”ăŐ©ń˛Ý­šSSŔcboË&×ưVSPş©á…¤iŠĂŁ#JŇů¬Q|®úĺő“}>ť ŁúMjK9R“iPŤ)*.`$•ĘŻŽ63ůжä鹨AÔ‚•-‹€ä†‘ę.UwwYT¬3…şŘ6=ÓTR…˛‰Nşl-ˇUi Y8؎æś>Ças©úąĹ{u´¶"·nk‹¦jNY8Ň4ét<Č|Ěé÷|>Ĺ}Ń­áD׫JIƱů€ŞlZ45#˘gźÜ´P—QgUKĘÇPić)ˇdZ÷ŕPÎ Îźąů¶¬yäŠ=YŰ>_ÇÓS5©i ăĽźJ@sü’,«á8i*±fxńůŮń„0ÂćŤ,Ě*śűW˝^5x(®© ťT™‚*·ëÓÉÉčX*Ąş [0“?(‡ë¦ú_V8Ő4őňsŠ„S\ßc˙h„I’ŤŹ#— řž•ĐĂf;ŔZĂAś Ä©ÖËŞŘŁnü«N«ŮĘ ěóK˛%ŽĂ@)¸vŹ"\ż9Â`śâhĺV‡ŔsVkš ˝¦F˘4Ešń"NŮ4ł—jY|!“ŁÓbĹł3uÄ/ÜLPͱŁ`ťPćóęv•“3ံž"Ó± <…çdůŰó×GxţŇ.nŹpŘÁa›ŐŮfÂ>c6Ç)Ł [ťwöxŕÎ&VkF“óť©qŹ)­¶–µź\?"GčQD)ÁsđĘ•>.í Ĺ1\FłžÓ$LÎóúä|víwtBĽůެ­ř Sć ™.†8Řn˦ÎŰČ«:íZ6ÝŞ˛Ę;˘ Í^Λ˘V› Ë¦wú~x Řp1g† Ň´*u#–5 °EĹÇ6ÁYâV6¬­ŘHNŃvOś$`…YŮH,FłŞ¶sW#|÷ŮmÜ<ˇz謷˛z ?Dŕűđ˝BřĽ¬¸ś˛ĚAźÖJđ|`sĆ»‹ÓI” Ž'D&“1&ă “®îFřw—/b5tđŽ»Űxŕ mř®I”äőú®_łN ˇ—ĺŹ_ąŇÇ‹—wńâĹC8 |˝µ¸®ź_żĎË©űŽ —9yq<%ÓŃŇ$DÇÇéŃ$Ć$š ‰#¬îÄőóyuy–&·Ó W’Být5˘ş˛hëž_†».MÉ7±śMŮ u:’©u!€çd7N!@™ÁX`ű`„K;#üôü>’8E­ćŁłÖDÖ„A^ŢÂs]P×…“—7‚ Ľ|„V1<Í„P„Ň AŐ‡&“LÇăFŁ1V˘1nŽ#|ó§×1Ž8FĐiz<”PŚâýýa‡e•\ĎÁzkľçÁó3MçűĎăđ]ĚaYí!9vaŤĺ"e'Ç!… px®Ź”5ŰłĚK•W’¦ÓÇ®‚ŕ6Dɸ ű=vMŚý™Úréý¦9 „ŕ/ľ{‚'`¨Vę4ó…(…ëđ<A xAÇqóéDΆ)ŞÚJgŢ 1mĚM„€ 3Úqŕp^"LjO"D“&“1˘I„q4F’ÄHâă„c'SS>ęµ—Áu<¸ž ×őŕ><ÇĎ|TßK¨Ë@ ›[K díˇ°X AĚ ‚MU\v˙dZńgd-Ł&´C°äÚSęU÷}ŮdŐĘą`ůŔÖÖßÔ;†Aŕ`BńźžŘAčąpýzć 9NÖ'%Źd×…ďú`®Ď÷áR'ăćQhçę–ŔČÇJ8bˇ±™`L€ ®—€×jâ âÜ_ŚăI’ ĺ)D’‘ß #`„f«]×qá8—Áa.<Çc„“:őrD›/3Jáô0cJĐ!ćĂ`AŘJ*K7™É”błŤ=‘ 6őó+#‡|QŚ ě ľňôjŹ0 ÖkýN.€ĹĂbŚÁaTŇ´RřŽňÔźůHM8 ¦&x^VTĂMŻŻ€1Š…uŕú>Ň4FšÖ¦igŮÜ«`”eĄ™ˇy­ Í|:–tłz"Ď·Ä\…\‘'‹W='śĹąŠ{łD°Ě ‘ř§E˝‰nÖź©ë¬IˇŘFÉľ.&XÇŚ(h㦂5gÉ9‡Ă€k‡ľűÜj‡z­Žz˝ŽZ˝×őŕ82 Ś€L ą ßnJ˘,„E“ťü±MÇžĘÓŔĹśđA:— b®R§, ÁŕRáäÍE řô´yĹ\aN§-sÉś€uČ󩱢„H̵YŠ•¦šĚZŠ@î”JŚĄĄ¦Ů­:Đ]†“lt-]_Ąp•ů¦Ą> ęš šX%..¸xüĄÂŔC˝^C˝Ö@ب#đ‚LřŠmŞŮŮÚš žµĄŕ‚C4źţĂ‘¤y'S.¦IxĘHŢ˝€ÂaÎF¤j8ˇň"/ßB oEGJjQŮŻ’fĎMQ’şnqÁ§d€4oý– ž5AJEVô.˛IFĹuSBÁ(É3<4ď%HríJfîÄŕCJCä¦dTiTNĹ©xŻš§×µI)Č*ĂGí¬ş´ ¶í™Z®¦Ż(%`„ăÜžŹł‡k µ°†Z­Ž°Vç…pťŚę#8ʧ-(äA/iĘ‘$Y±Źŕ1Öę ë« íş‹Đcđ]ľKB1ž$¸9Hqeo‚+7Pę \8yG+Jł‡,ťiJą¤ľÜK†*p™’ ź3ÎbÚJX—…L×pJç{Ş…ó:~Ŕ±M°ĘčP…DËçˇ Žw|Ľ|}ŚZŕŔBÔ‚Ľ1d†ÝQë¤L"“‘=´$N0Çh÷v]Ü˝Ő@·`0áh0Âpxd’b4ä8˘LkPŠvâÎ{W°ÖîŕňÎĎ^â•í8KĽěR:‹P§5ÂÂÖź(ŹšĚŤ«y®Ý’ă(AGxCĎĹý÷8ł±ŽĂĂn!ŠŽ0Ť„8ĚÇ(îíÖđŽ»¨‡Î]áĄk#Ľz=F˝–]»ĂX~íąË27 s±I%J¨xjjNme+HÓ± N4'DgRmŃ"厳;!.Ţ p‚0DXk |ľ7sĐ%ßnöŕ2óÄ‘őeNҬşŚ§îŰňń–;š=‚ť{¸|é5<÷ÜQfR•®řňuďâňŐkśŁąşŠoďâCo[Ă3úřékCÜ2Ô' † J˘8×Đ´đĐ\űś¦ć)â8ĹpŁrĽ÷ž:î;ÝÂŤ˝lď\Ĺůs‡S?IÇ$€ť»ÓűYk·đž7¬ăom㉗đÓ GđçfÍXžIˇDu%%˘ăó× ß®ČRDIŠţ`„Ť&Ĺ»ŢXÇ˝§ÖquűÎżú ŽŽŽŕş!đ=O;ęAÍÓR‚R †CĽôň«x…ô6şřź~a7ŽbüäŐ!^ľ6€ď{yÁzö@JsŘB•Q%„@’¦HÓ“$ÁhC¤1î?ŕÁ»špáĘ5|ď‡/Nsě®ëj[ŇÉĚ™;xxÔÇŢÍ}8ŽŰ·6đŢűOáG/îăÉsGY'ŻŔďfyeP6»\™ šfŮb›ŻŻ›×§;FWôĄšô˛t\)ö¨`ËIDATi,Zr§…)ţţ¶Í nďuđô«‡Ĺuę‚R”8Óąk\‚Ňü†'q‚ŁÁ®á® ď|wDD¸tůľű§´,ĎóŤĄlpQ˙¦)®oßŔ•+×°ş˛‚ź»ł‡żý4ž»pW® qĺćaÂý,eX¨ÓŮÜ ĺ™öÇ G#8bŚ3†űßŘŔ \ßŮĹą—_Âh4žÖëŇTŞóoJčÂ…‹—qńŇeśÚÚÂ˙ţ+§đÓóxćü׏VVęYö…1p!đ¬)S’©¬ššÚµ©‹®ź Ü]÷DMĘepSőtÍÁ§%š‚âM·5đËďą ;#\ÚKp0ŕ¦Ŕ8ć'™żB)‡Ďj>ĐôV‚ŰÖVP۸zí^zéL&QN…w*aKjt¦ă#Ę‹J]ĂŃ/Ľt”t:ëřŔ›Úh­6°}câ`âhBĄinľF¸ˇ x.A; Řj·ŕ0`÷ć!¶w®â±óGyÁĽ3˝~Sű ]˝í-­Č&I&ňĘŐë¸zí:şÝţ‡÷÷@)Ăőýý1Ç0Ä“č†!îęŢ”ď€P{ͱîąë˘aÝś† J 8w$!^»@Ŕ”ők“ŐëÔą_şbť»VeTWĺ•:öłÚ0Rľ˘Bl2‰pńŇem»_™gXü[řFş]Ą3I¦ścq=*iBîo§«eµí`0Ä`0ÄöNŃ 1ťÍ!k µ’Ź1j$tŞë —_š´»Ú“GWÇ!oľýýąÚ–ąŮ"†Žd˛©Ô­»ŽnĹó._ęý—ˇ'•Ł`ÝnPiKZ˝ŕ˘HŰDé/Kšşµëhaň˘črĹ:Ç_ç;Ę…9ş°¶ ?¤-+đ×iµ"P®©1m<ů:dś¶JŮ…N°mM’Š52)­˛’LkY&ç|DZ1¬¶dPk]X®^ĽÜÂ_Ţ5:vŤ¬1ä÷©×¦v-v·J3/´|\’$ĆśwŮä(u#ÚXDeţ¶‰q^T«Ůo“Ó_ň˝ŮĘ\ĺó¨÷˘—©B© ”ŠçSĽňk.#€$ßńŻ•ţňĹčF‹ŞýMuę…Şř—¬iä îDÝűä)c‚Em†®öU5ýžçi5Ľ|Ş.źĂ48GçBĚZ cE ě/ĘéNąŤ›|źş{Ó‘JŐ¶(sp•ć}şéérHÓÄRÇqĐď÷ŕŐŞ&äBI8çążż˙Ŕ©S§DZVÔ]®VűŰş®« Ťt`ŢŻbZ'ŢT«!ű%ş’R5–…[ľ×uµî‚®şĎÖ×Đ4—ÍÖšMgÚM“¦Lő¦ŇXµX^†xÇ™ćuM.…N¤i:Ĺ6…p]ŰŰŰBü‡\Ö¸Ęsá+Đůö·żýÇď{ßűţYíëćBčÂr™1ŁŰÉĹ‚Á†*x¦"&ŰF§ed2e!ş¶ ¦»Nëşqf&XH}Řş‰*+ĹDy×éÖDľw“°Ş~*!®ë.řóŽă,L—Í˝ě®yž‡(Š0ńă˙řÓŽž¨6Ubů—Ŕűô§?ý/}ß˙źďĽóN ‡Ă§[·ä>)*…Ű4ÎôĐLŽ­.BT5š*$¶^‡ş˘sĂ@™|ë|ŕ˛ë+›oŞd,ë˙¬ëŁŁË÷Ş~¸‰†Żkϱ˛˛‚sçÎ!Š˘?űŤßřŤŹ"!ë*ĚuHsásźýěgżî8N÷Ě™3$Žł˛@ŮĎ*ĚH‘aĐUÉ—9áeĺ~ş¬;F.ń¬ÂČ(Ž/´¶ŤÚH·jDŞúŤşú[Dhš‰§Zš*ťÉŞłŽŐ,3bdXFË` Ě’$É{z.]ş$â8Ţţő_˙ő_Č!€q.€ÓÖÖL1ż…úBÍo}ë[ßţđ‡?üáĂĂĂZ˝^G† ŕŞüłŽM!_¤ü˝•©ŃnZ»­ÁĄ řÚšf«\DŔşBk`l*Î6sM¢Î×+ţ˛ü­N Ş>·ý«ë§>KµNî¦%·Zń}śs\Ľxqďţćoţć˙6 Ćâ\¦Pz…ČOˇ0ż~®ýV¬čXűÄ'>ńŃ{ď˝÷=®ë˘^ĎÍ^NPٰÂë|Q@ŽŠmv*jŇ®:3/ĎŞŕĘř¶ˇ|jţSţ˝šš,c «=•Mj3ˇ:đ×ÖźĹBŰÖϦ áL’Áý~q㥗^úŢoýÖoý »n¸ ŕŔHFaŔš$€ťü«Őn·o˙µ_űµż÷ŔÜ×h4VëőşcŠl­ÍÔęśéŞŻ*xŰmŻ*M ml§˛s™…Ę›i8&ý~˙ŕěŮłĎ}îsźűÎîîîkąĐíäB¸ź ŕXň…ÉôróŰĐĘ…°ť˙»  žăćQ4ËßK1?+Ź0Ć˙LŻ˙ZĄQü-~–\hÇsAJr­č8°—Ýp`  lŠç`âÄ©tÂtLšź ĚOŔĽÚ‘Ě=|SÝ(rm÷şIéß­y\Mözľ$­(40!™e!˛6±EDĺ23Ęeć(Âľ¤ő’2’d'ů‹§“äŇ}” ź/ ź#k>i!©ea…šżőú;ő"Š` I(‰$'\Šj 8’±~#]˘Ó€\#(ĹɇąŕąůSµßĎ üY} )N%Ą%›bů+–4 5ĺ YÇ’ĆÓů}·îgOušPö Éçă’ .ŐRD.*(Tů*L­¸%„?“Âg L¸ćK۶â˙Íq#.m"IEND®B`‚gammaray-2.3.0/resources/kdabproducts.png000066400000000000000000000133521255003167400205260ustar00rootroot00000000000000‰PNG  IHDRôşk|sBIT|d pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<gIDATxśí|kt\Ĺ•î÷Ő9§»Ő­–ä‡,lµŚ!Ž1‘ÍKĆFXÉ•k°esŰ&Ľ r3CnnČ’ß$̰’Ifňŕ†GŢÁ X6Ă&±x8`𠉱- ÉÖ«%ť>ŹÚ÷‡$ĐŁ[jÉâ޵îšo--­®Ş˝kWŐŮU»öŢçPD0(ĽęŞpóOôM ł˙Ź@’ůĹĺÉs9QŰvËrQ_ꔋBRÍ^ą2’Iź!­˝¦={ěT|RĘXQać·!ägg)ŰKśäˇ2ʏ!µ;«Ăěć$ý‰ře4Îv 433ŮHr^IIVKCCĆăȆ$cĄĄ!í8lI$Śhvî'(\dřř3Loż‘éösćőIm­ź’>7ň÷·eŤ«ö‘M:•Ě}~4 }bś-Úź)PGqsrŢęlĘęǡ§śLćÓˇĐs+«"˙Đ´˝¦zxy¬˛ę%hŞ«YžŽ¶¨˛ę>nĘ•)ŹŐÖöŇ>ŕ’QÍ@DŢů)űÍÜđŻ˙üçv¦˛Ć*«ä2ţ¶i{ÍŻ2h˙< KSĘřśáŞyň‘ŽTôs**˛ťžţ­ ™z˛E„ ž“€z°{ĎžŽŃ‹—_Vu’ŢżLĐcxh-@(Ą!oĂď¶=˙|«Śi;’Dii(וąC¨|×FĄ^Ť" >Ň…#íŢŰŇĐp2ż9ŮNW_- Ă=ÎÁńľřPřkĐé˙Ç÷´î@cŁ›î!=íÜË"¶ŐýPČÍąőřkO÷¦Ădi¸ył*¨«›Ýod}CQ´i2´thÓ ć<řßČ Go>$ŐĚ /࿊ng˙—çŻŮpËŃŹ>7‘¬k®)°”¬`’¸Ŕ„ H@€WF•źđ@.ń-˙Ë…ë«Ę›ŻůËj×%Xb~AťH×Kň„Pu3ý›hIÉu$OŚ^<’ K[·¦ćcÜnš ú«ť~wK¸´ôZ’-iN|báŠh^Ňż ŕ'ĵľhĺH{ŔÖ~KG‡ż coĚ$’–úÄřiîҲ;H‘1'—¸.aĐośnw·ÉPč“I+üËČcÝĄĄŹčOŐÖŹö*:ČöŁ˝*ÝśM–†fÔuĎ´ÍĐý xH™xŞ3+ě ­MŔĽPčq»K›:ŠÓˇĚ»{]Ů_péĄ˙ŕýÍAD4ăń7ó÷·]7ĆéCÔ5ü‡-߸aôŚč»Ó’–Ćň>‘ŢWćĽóĘsµô=¨OŃ1»Ą§ËGn®F×Un6iä†űč~#7â~ˇ«´ôűéćk§¤Đ§]?Ă4T=€ů [2Ą+ŠÇł ó j¬đ`óyg˙ŤlÚ”rçoŞ«ąhtIÎ_ÍľďßŕKZ±ľ°˛úÖćş­?Ż_Ků×4üU€ŹĎݬúČŃşš·Ç– 漣ŁđękSűźđ«Ô¨]vŰmgď}ŕ7…Ľ‚ N´˝đBĎčşácBqńý9ˇh›ˇ¬ŻÇJK˙ŁŹ€F(>ĺ忍öőµZIµi^IÉĆ\…bĄĄˇn[ţ^Hťmč[›˙ňBGŞÓwđ˙ßŮÚŮ 8GŠ‹7’lMłIŚ;N’DIÉŽĎzζĽďf;x—Ë–ý^öî3gÓ ’FnIÉÂxJîéŚDţ=ĹőĆĆăűłŹ˙lçljÝźć˛eO —qĐłiĺ—•<„Ń3ŢJJLAß•Tl ĚšöWv'şĆÎi’d_´¤d3Äx0Ďu‘üŹń¬®ŚwżŃˇĚ“Ŕé«7ÎG=`5Ŕo5ŐŐÜ–N™ÓADäČcŹüµ©®ćBp=*Č÷Š®ŚŽKGŢ "_ ą~2ýŽFóc[ŢhÚöčÝ÷řȻǻ—L•—{éۡĄĐ>©¦´ŮŠČ®]¶éçĽH2×µŁcÖ¤jwŤÓ`ČąÚĐßo~饴¦´üéOý‰hôemň×F0ü?bĄĄˇ)˶wŻŰşďOm®Ąî˘–żËÖ:Źä„ţ…SĹěłV† ănRßŐ9{ö3˛kWÚ{ĽÔÖú‰çźo·<çEÜžçűů.&× ¸Ę·Śß´ďŢÝ›Véş Ĺ_ĆU ĘËăńť’Bź~őĆ3‡”™Ä]’ŔÄ—ń˘+ă…ľĺ?˘T€/4ŐmýúD4-vÓöš_ đ´90ŐŹÓµ›ż¦zĹB<ާ´Ľnz&y”ŇŧÄEDÚtjšÖ)97ŚPżńĆ8n`^II(¨˝»ŕ«ďő„Ă]9ťęë“´¬źHčY$§|ôőô´)żVÜ9Ő "STÚtcɆČK2ěj7žŚ†ďw)_üăqc:eŇţL*A'˝v řdŇ˲wŻ+^˛^„‹śž±ôpLzQNżz㙾ď×cP™Źm«ůÇLč ×ÄĎSí°HŤÍu5?ʨĂ{î™Pá”Vw€k¬˙ĚÜTm´’€Â©­ő üŔé…•Őă2d đrhđ˝‰ŰNŔÉs ţO^oŻAr†oŰcÖŘ6M“Ôs ĺě•]»ĽTôcä‘®ţţ„aČ/&n‹•–OE>46şO*Ĺ3m55k$SĚ+) ů!ăËľ?ęHqýH‡Ö}űlßđżgÓ˝‰äĂâ~•Ť+°pḧ.tľúj—‘?ăó- ˙:îzR =L™‹Ć(ł¤ße毯şJ˝`–P­nŢVS3™~'±[öh_’‹F×ôŠ+‚ŞEpĽůĽĹ»@ ·Č= č“I®Żş ¶nĂ÷®đúÜ9໦:†!žvX…brîÔOh’ĘPˇÓ„ě3BˇŃa•ôT‘¦j¸nFĘü><7| Ĺ§Ş„""–'”ÝÜvB!”<3'´{2÷uń{÷ľŃ~ůĺűŇ…°¦ŠwęëĺÉŁnÎÉť˝4ńâ(—-łŇYŚ""'vîěž6/÷üĘŞŹh`€"@ľÚdĘw–ÄăĆâboĽ‹+ąZăŹlĄ°ęčă[^δO@cc¦ ţ6€€‹<;Ľ˘?]`Ý×[vÔě)\»á( ëň׬ą˝mÇŽtN «¬úóđµU ˇeŔ|EYňĂT±LÁŠ s^II^/ě{ˇQ×ÖÓ3ˇY8†Ç€cÍš]R2Ëţ±Aů‡vËąŁ›†öVŮŘÚW8)…É/+ł=Ĺé„Ôćyl¤ )a«ěü˛˛”Ě}ŰVy*°¤Źć—@Ůo…¬:ěŢ=FŮPéřř¶­Â%%aĂ0V;>«Iyčd$ňÂh“:–“c$©VĆ“őOë©3Y==Ú5łN::x:ąůőŃIÓŻ·×€qj7„˛k—Çx|ßě}-Őţlä±__§"ţ#ž/VGorwÁňĺ?›łdI{$?ßËTą'ThVT±s>án!®ÂŔ©µ3ěô¬{kçÎd¬˛ Ó™GľČęB×ř7oľ~R^í¶¶ĚNhý"#ť5ó×TĎŁâ§i®űíSVkÖPÉť…§Th!HÁ±¦şšŁëf]qmN(ŕ­'ń]ĂUk ×V˘yűÖc#úđľm+Ď4L1 ĂčwoRĘüaîҲŰIvw“ăxąZíÓJ_ ŔäîŃÓ?ULúQS©ă–Â@Ŕ˛W{ÄěÉÓ’4˛Ď˝pÉ7S%Ôś Hrhm˙Űl’ ?R`µIĄ,šÁO‰¨­łŢ~ű†A9ŇÎUF&÷i—]1ĂęIĺžĚ Čú×·ď±űsś°Ő{µµ‰YW\{yVĐűwÜT¸vCŔí™ô]˛hQ†whůč€ ţH…ÜUXTY}Ď* ‡D×FS‚´¦ÇZÎ?ű—…Żř®!ykŠ Ż K2A¦‰%3W¬¸ß÷őUĐŰ… đÁĆŰĐŕYË–˝L—ç·M.±$Ăçź (+ÉÎĐ©oČíłĹWťfJ^"â9'ONč‚ö<ŠĘšŢ"íy“rŔ‘döye3•rď)8çŇ›0,cěTÁŠŠP䓟Ě%Ů6ZAź€3Ńwů3rşš=ňűłW®ŚH»ţ:#ň׬‰ša÷wPćEaS§Ë;c•~[Wµ:ÓśŘů›nĂ5.đ*€ż‰UV}?:»ŁcÂE­»f0°˙š&~P/pÖŔ/ąV ›F˙X6X7ož’sfŕ Á×dť¶¶ęô©đ.ś|ńĹß÷îȧňc1kt˝/Ň ŃyÎ /­W5%Š‹-ˇË|ro[ţ©ťě$©óĽÜt1÷€mű3˘ŃE™Ä€IŇP*_]ěěÁĎF4•$=­’Ě<ž\\l)$ŻČK­}Ć´Y2$U~wwˇŐŐs_Á9çdŤ×VDDŢڙݷ_€ŕD›Ň¸đ˛Űnł‚FÖwąp°h5~“ŕ zç×?8Gž|¤C|ő)ݏŁp݆ŚbŘă¦@˙`đWíáÚÚăCu˘Ť@‡ˇPšęŹÔĺMÎź÷ĘţUŁů 2‰C€Ě€€«şNqH§ ‘P8l¤¸căŮ‘@Ŕ!p¶} Š‹3şK“dNNN6 q÷SÔ×OÚ ?3®úž|Ëlm Ťőč·Ř¶§×áó|ĽňĘÄ–DI‰éş¸Ŕ´ĺçŹPľÖłrmßT?PÚřúĚ+2Ęú"É<+?¬LuĄ4~‹COM[zŞhŹl0ßÍĘĘh1#źDŻśŠBď}ŕ·i[Í笼¬ ŕoěx hmő ‹Ľ“î­«˙?ő•ŻiĎ;~×uk¶‘;aę%IâśKĂĘ•›¨äŮžht·~ĆăĹ‹/Îrrřq€vV–ń‡”±áĆFWÁ{VËó˛łÇ=Ĺ`Áĺ©ßŁľ|ÄuPjký`GGŁPş=­—3źŘŚ/.¶ ú?-Ŕ{ą˝˝'¦űŽ?`%µg2˙ŽÖE3őődiş`Í5…•Ő7Ç*«îw;űľ(&śąą5mŻůš¦h^^ÁçbëŞ~[[uŰx|RˇuÇ–VĄą ŔŰŮ«Üp×dčçVV/­«úo…yĎp3‡Ď˝[[Űö~#O­ ™ýq"g 㟉uł®¸6} nŠâń¬ÂĘ Ő˛ňŐÉŚăĂ„ö<‚´R™h""}ďľ{Ňź˘ĺß;géŇ9éĚZ’ś˝revžŮ˝Z´TH@=8•Ó™$YQaćťw^n®‹« čżőěÄ=í»w§tŠDš 8ę©`9Ď=7’ęÁÚ D©‹ toŔ>ůfŞđWűÁ˝É¤u4ż5óČ‘2^|qVZ~gT„f„óúä-^˛ďë­űöM{¦X»mŰÔř™©ńÍśâŇéRi_hɢď@sČóĆ5ýÇ2 Öf®ŻÝG-…Ňę jŕř{]˝±Ę ˝Ő¨SB™Đw4Gwlm)Ľ*ľŠ†zŕ˝±µŐvÓö­cîŐýÁśÖXeŐ™ ňĎ4ĺł-Ű=0Ľ‘2Ŕ„?™H–cŹ=ňV¬˛ęIW†^ŔĂ0AĹ*«ŽŹ"ł5“Ht¸Ł©îŃ­H…éňčO–ŹVFÚ4áC‡śÎ’ÜfW$á_ç>|׬‹.zËHdi+ÔŁ}ץŤŞy%%ÁŢ~˙k Î yÉ[÷Ľ6ć]íá ăDć,©Sź»t©Ą»ěÚ ÝLí·’˝×w56ľ7Ż–††ţđÇ?ţ-«Ďůe®•}–^Ľüáü˛2'`Ű>8‰]Ľ<`$ýkA®KşÁë»Lé¸MĆŹ†Ď=r“~'ęËv—>ž_Vćç—S\j©pňz-ú2xüZď,nŮ—ůĽgşF žąrĺż9¶{!‚ňż˛JJîË_\Öi{´‰hí8’Ç?.>.÷áÝÜŇĐ0ą×']qo% Č˘ř;ĺó/B ő*€Ą€ĘˇČOD¤Ţ…±?`ŕ|ľZ‹N5‘ŻŽ×yóµGOżză*ß÷ H|ţš Cď58 o@@´x[€CyŁeÇŁýPśQY™„€üá´‚śăÉđ>k%÷QsŽő1oČp/ń$@»8`ŇţůáşşÎT|CZ{ đpHëSrŞL–OX)7ATž&Ů3zŽ÷qÉ’'f„rhĘݾϠôé¤X‡ Ë,ĐI/ÇcŔ§ř/Ŕw~ŃúÚki_ä0zz´k…;]¨"dkC}@"¦!<ęęäćlĎ;ÜÚŘŘ7‘Ů."B˛µpůňę„§?Ż"ÜâŮ~ŇqŘ}v?˘Bš|%[ĽőťűVťy6­i,Rë“›ß(\ľóş„Ç/!äoqű}í)ó04EÂn‘RŠâű Ů&76/šß)Żfžň9™5[˘ŕŇKżŃňd©%ĆżxŮľç0Ük'ýcTFŽDĽ"ŮZsO„ŢÍ- cŢ‘ŤiůbÉ"=HrAyyđť4źú°ř k?a†7oV۶eůѨrNž ˝ @}DĆq#‘ĄŰ’M.÷8äŔ§tR˝®9„O]–ślFŘĐX®k9'Ý#z©ř¦©#ćk!{Ňź\âŔ'lĄLŻ×2Ŕ®Ź•j4B!ťmYîTÖkŞk=ô (ń\:3őÓA±/ěôµq Ńödäů?Ů©«˘Ü$ođIEND®B`‚gammaray-2.3.0/resources/splashscreen.png000066400000000000000000002353271255003167400205430ustar00rootroot00000000000000‰PNG  IHDR T§q6sRGB®ÎébKGD˙˙˙ ˝§“ pHYs7]7]€F]tIMEŰ '6®Ľ IDATxÚě}w€ŐŮţsÎĚܶ+EQÔ((¨‚@T4bŤ%ź=&¶ÄřkŃXc‹!*6ôűE-Q#[0•˘±€Š Ň ŠÔe÷¶™9ďďŹ9SďÜ»·í˛ŕĽÉČîÝ;íś™÷}Îó6 ’H"‰$’H"‰$’H"‰$’H"‰$’H"‰$’H"‰$’H"‰$’H"‰¤ă kŻm;b$¨çÁ…ľnÖLÝţŰv?üÖÎz=šŤH"‰$’H"ů>€†®őďľeý<ě  NśŤd„c=­31€cKö1ţ b/¬}ëµőŰ< kgNŹf¦BIí±Ň‹?-ř<ąŰ»“ýÁXCvů’ ŃHEI$‘D˛Ů@C—ˇ?Ć÷fˇËnÇ~ĆϨ+cŚ…€1010Ŕ>``7­ysú‹ÝFŽ53¦}/&ˇÓ~C4`ŕ€ €1` Ó8Á„ÂK" şb'¶; ~@Ŕ@´€Î€€cđJvů’詏$’H"‰dł†íÜĂΰ€ ćüÎCĆb fýČcß‚čÇkfNźŰí#°ćŤ©[ĺŕw4B`gĆh%@€ŔY_"Ëč€ @t`Î.Död ű˙`Ö‰Ó˛Ë=î‘DI$‘Ô"Ľ* 0d„ ~GŔ7ڱźZ(…V0€¸ő]ëOĚŢ©8›Óí#YóĆTt?të´w?xśă&{Ś@ ›tě"O10ű díÇ=‚ňsű;d}‘1:%ąŰŃÓI$‘DIű2 ]†Ś60  Í!`0c¶a˛đqËč1ÎF  ÁŔąxäßI Á>dŔ`ôݧl]Lð8r0 Ű@’]NaBÖx$ż˛|ö^Dpefé˘;ŁG=’H"‰$’ve$Ă ˘‹XĆY«^Č rĚ–ŰÁĚ^!{Ř?`Ř…KŔ t0ĆŔXĆÔî?:jëý<®r`äxÂ÷€ľě!ddŤ“ó ěě‹0DI$‘DŇî ˇËáŘđţŰá €ő!ÇßŔvŔűŁý»…*¤u“˙rîůś30ôáăď^JCăÖDô\kÇuXÁ®kIđ`S@ą#Éθăç¸(ČX:AéÔ%zĘ#‰$’H"©ŹŐŞŚi>Ŕá23Â:€ĂX&‹qiČ8@ŕŕĚýÝ zDŔ`Ż¸Ý».ËhNűîőWŹŘâ‘Z<ζ°ß)Ld¶Ű€d1 ł #‚€HŘ{‘ü‚đ»(ôDfÉÂłŁG<’H"‰ä{oă)`ď©ÍAC—ý‡_°ŰdŠ8çž#ČĂ0îüęÄ1 Č4đŔ`ĹřyłWŘž`˛ţN ‹ľ{í•PegŃe˙áó Ô_Ň ;[‰E °gZ8ń ‚¬,U;ľAŔ4H@ÂXűM"żn˝Ţ™H"‰$’ď­P+żłJD« ˇËţĂAÝ °ďl`ŕnđ#wŽĆ á0Ŕścř/HRŰŤáf[ůÜÎkß™ąŠt} Ä} ť÷ş/>×jtŮ’l Ľ‘± ů|ůçËI$‘D†VŔyX…ŕżEÖ ËĐ ź2űâL–Á)î|ßď–°Ř ‚L«  đV<´˙&ë0çÖ˝äsą?¬ź1íÖ-if»p  "Z¨Éi»( B~RV„l&·Ń\±8ĘŻŚ$’H"‰$ĚÖ'€Á»!äçP@RÚ=1xŘxpv>l“m§KroZ$wâ]–Á:4Iá¸%¸Ścŕ¬Eˇ»‚\–"Ŕ4R4©!™dK'MÜ,3Óu¤3Ů2!%ĎOťŽËÇÜAÜFLä ^61˘. a}IăËĺńô˙ŤĂIG‡żÚŘÜ!*M¤ šżÁŔĐą±ÁŤ)StÓDľA®šŞ"¦v<Ň%§›ĐŤÚ[śwđĄ);źBţfý˦źA„Ľ®Ă4Ír…Şžźrî1™HřÓ°#‰$’ŠE±,“É<úé§Ź™ŚY…‰ŕu)xţnf~›žw-Łż§‚0X{B&śţ¬)ťĆß'ż˛y¸ A®!CT2‰»ű;•3Ćl„]1“ŕ-ňäW’,ß7ĂDîŔŔ}‹†ćtĆUţĺ?bµ›:oÓP•ÂĎçóµĎ4Eé/p­€Á}î(đ»ý3IđIűÎB˙&!“Ë!ťÉřCĹöż>ń4D„–tú–%I$H8ç»544\ńŇK/­[±bĹ1ňcEbEîŘâËŕPĐĐe˙áč2xřP€%ÜjnÓ$»l±·iÜRČä.tÖ FkŔXfSşŮ\ÎWţŘ­,íňË5BľfX$© …+řócŹ·?`€Ó˘i pĺ÷Ú;ďbĺŞoä9}5dßćÁCެ©üÇŚdp<Ŕ"ťÉ`Â˙Ť+0ňşŽĽ®Wh¸©Uʤ;Ňu›m¬ŕ× An5›"‚¦Şr…jš"t®ÚOy0«ČŞgl@6—C:›Âý•Ç µĄ0ĆËç‘Íĺ R$‘DR±n¤>}ú<łdÉ’ă< µ|/](w»aÎlt<ěL'VÁ ű-\!Ë sL† §IĎżµîÝ·V­žĂŃ}°‹W~WgÍĆÄ©Óńţ§źˇ1™ôGÚl |ćâ˛2@Ăę ńĆÜ1rĐŔv3’l ?+T¶ńX ÷?ůⱫ”‰Ü˘V `Ž‹ÂúDx\B t”M(°€¸üWżÄÎ;ěP`4I˛ ĺŹ • JŮ Ë6Ű8 żb–Á0ę2ŹŃ-† Í©0 )ŠÓ ޤB7ŚÂj¬ödŠj@ˇžH1Ă0‰D‘ł"’HŞ~—Ń~đ6¬ç;3“oąé1žZÄI–„ö)Ŕ÷´K8s·R“iu"0Ćţ°éŁŹĆä[6p®B­°–––?¦R©+çXţŐ׸ö˙ÄK3ßD*‘´ď*0/Ą3ŘsáĐýa­7¶ëŕ§3YäĘ M „ŐëÖaĐI§!™L‚ ÓQzBW’…śŕĚ—[čIŘ˙÷Ą^j±ÖÎ}Ţl [Ş‹chÝBP “ŔC—ĆĆŞÁŮ|ľ&Đ`ł qMë/ms¦vŞÝ­•"<ď„7v ,íx"‚˘0ÄTE‚şˇ—ž+ŞĆţ·-(""$ ¨ÔőI$[ЬYłf\÷îÝoń€öćĄbŘžá® ŰáÄ:|St^;ëŤ[ó-@‘5lŞ#źH$N;Ă.;î€ ľ3yťśĐ_Q(;Ŕp1ťŁ[@bň[oŁ%”ŘÖ«¶2•ŁÂÜ÷Ĥ’IŮą2Řú„_,ő°1úó­ˇJ?ťÍUÇPľu¨7`°÷Éë[/Ë@D06łkBS8ňşŽt&ÝĐýĄŰ‹Ůţ¶¬gŚ!›Í"'Ýś‘»"’HŞ“Îť;˙€Ëă  ĐETůN{©B–ađđa®ÝŻ,8Á{Ż­›5cpÓÇs6y lÄ9ß­€}÷ŔâMÄaC÷‡aŠw…'PĐ))můţ‰©DOz©ťŤ@yß3MOľ4Ůş%‡|ń0čXÉČCą†ÜoŇeđăQG†&Ů\®B·DëQ ĄľU+`°YAµvÔXĆň†Řl×F$Îf­¬VF¬IĹéۇi°ÇR7 ¤Ói4DIu‹MŰĹ^ŰÂŤođnˇ±  ˇËţĂFĂ˝ž —Bw „ĺëŢ~cS5ffŇ e6•˛ý«OŹąż>ĺÓ ç|`pŽÎś@JƸ ¶{ň•)íľr,G~î‹J%o„çľáɢ€ŹÁqÁ‰/ hÉf0aÜ=ˇđ›ZŇmÇŔŢ&Ť×\–AߊYËŐdší×?Ě–5LéL‚ŚĘć¨jŔĐNqEň>2™ ˛uȶ‰$’ď©(Đ ™…Ŕď…F}Üٰ‡µ†'5Ň.Ôd©#06TíÜ•‘ˇS1#„ćhU Üzá˙âŇÓO†nšŔŕ- %%ťP ‹ľř+żů¶]•rk’J$đ—§ź÷Ôµ`ä‰Ď¸(śL’ĐÔK—FŔçý;íĐł ?ż%ť©P׳˛}` ‚Â9:×l–Á[3Ëä íÇő3!Éf‘Íĺ ŞÜŽˇ­ 0l ‡ŚA×u4§Ó0¤K.rYDIŐ !Č45ń"/âî`Ä‚ű»úżmÝŰ3Ö×#ä ,„q¨HůßrÁŻđ“Cr«x\Ünjś; "•Hŕ©)ÓŰuőŘÚ}Lzý ¬ojrbÁţ­o·Źu˙ÉD·_ýűĹÓu+ó Î+Ă0·„T§ sCCM€ÁeęËŔ:4Ë m‰gěçÁéLŮ|^¶°gP¸[]µ",YÓĐŽcd˛Yd˛YDI$e‹Â2°–ˇ8Ó e;Őž‚NvPäş·g^˘%€}!"ÂŁ¸»í¸ŁvAţ^Śsżbăŕ˙2­ŤAi™L$p˙?& ¦©žA"YĚŇSŮRÖe€Ż€ą?=J<§ë˙§[|Š’Čj§ÝRQzeů >glŔP«K½vS5ĎĹ÷•ep 3!›ËYuP9€%¦ňĘ{—up×D1lc»cšÓi§˘hÄ:DIYL‡?¬ 0” l§B$ 1Ś aż‡!•Š€Ă¤»ţ,·Í­l+Ë™dň Ś€/ľ]Ť/ľ]ÝN A”Tä –,ĹÜO?•Ř€ąĹ«_¶k0ĚŃŻý,ð}÷ʼnGQ0V›ZZÚ0 0¨0„ĄyVĹ2Ôˇ.Ó:fĆD۲ ÖAłů<2٬ŐÝsžĘm\Zíˇ;´ ʵ Bµd2NÚq"‰$Tx ¦!ÔĆó"oc,,žÁâ©ŮíŰŽYň˝ śWs'Ś1ôčÚw\zˇëď¶Wߌ;É ŕŚ3$ăqüűÍYídJđ=ŞŠűžz©d˛`­N.řr˙ȤpďÓĹHél˙¸÷Îĺ—Îf+Ś ˛żĺ+B. u®`° ŞaÖ‰eč€o#c Yݬ;bę\>Źt6[PŹĂŞĎŔ (Uaö*ËFoŁĚZŁt6‹Ś¬&I$‘„2 Ĺ*B†*ŢúúŇó!cź®{gĆŞuoĎ(öŢÁB•ZË•óN8}vŘŢcH-ĂĘíĆYnˇDp®ŕßoÍŢěłÎdđÜÔ×ŕIŚđř_ÝZ đ¶ß`ÁAtÁpů/ťzşÁŹŔ0Ldsů*˛%Ęű–SLćNu .Ë ×'–ˇr˛ë2´EĆ„nhÉd`င1V˝[˘ębNíۨĚçĚ0 Ëe!ł,"Ö!’H| (ëAQČ4t2Â_§Ő ÄcŚoôS+ÔFUĘ÷«F[«y- ^°ŔđF5A•+ż¦RňČó“Ĺü×PĆv\+H-®d<Ű?Ú×tDŘ”N×0ŻÄ u Ë_–!®uĚrŃŚ1dóőaěy× Ă©µP´&1Mq_ÝJ—íŰÓŞŁ&k~†XsÁCNfY‘Ë"’HJě·ĎKĆ4t±•Ź·qŤŐVĎ”ĐŢëö62Ć0dĎ~Ú/§Mx«$Zć—ŔŹĹ1ůíwÚT!”:v*‘ŔĂĎ˙ËSvŰ_*¬×ŕ+˘…‚`Č\^ÇCşŮ űßćt¦Śa¦Ş¦Ł-ýč†Q—gCë =&rşYó3čvźČdsNp_±y ˛Ş>*śU7W[Hd-Ď ŕfYD-·#‰¤(łŇE©xöD—¸d0Đšułg~UĺŐ¬˙\äóş0 p‡lŕ © ¦˝7·MB1[@DřĎ›oa}Ó&xă<ŔCŘ ¤Ś–3úĂ>Ę÷ýl./Ť.+ĂTĆşřbÚ0ŘÇÖk €$˘[.ZBľ†X/Ł”ÍĺdúdësŔ9 ©Ľv˛U1¦VmÉxÉD"b"‰¤ {¦ucöĘXÖüł ő*8)GyKĆFě=;mßßmŘč‹oŕžVÚöŞgę{sÚXa…ßV<Ăřg_@LÓ@Bj= ß0_ó0VS¬Üu‡Ż+ˇÁ]ĺ¤ňWÁ: m«“ĺÖĘ20ĆÎŐ«‘Ëçť…rŽĹC\UŞźŻŞăÚ—i¨$‚Š˘@SUçy±?ʆH"){ČĂ^p5ä­Ě;8Áúú ţ †ş?ëgϬäÝćőĽ»KO= ׍ŠděćVŚůŁ W­]‡o×­ÇöŰvmłŐdŘg_ŻţoĚ™‹ĆxŇ­Ç@ž^N5Há6($ů»“J Ë5!€ßţâlôęą˝s|Ć657—PvTŐ˛ŃçÄ ‚¦jčÔjŔP/–!‹uČ70—7­î¤Őôŕ —jU]‚ůJĆ5Î×ŮZ·nűćśCSU_lXŮőH"ůŢŇ ŚŤ *†2‚Ż]^ľT±¬÷Í]׿űćŐ |^&`¨I•’łŽ> ,č†é9M"Ç´÷ç¶™bp-ÝăsÎ1ţąĐ`·řvg¦´A·˝đOS,ĂWŽö­ŠšÓQnCeŞßV¶1­íC˝XÎyÇkŤLSňFen oc&“q«`˙„Ć­Xŕj竪ŚÉÍYt Đ©D©DÂbü"pI$•0 ­ľŘ!ü.űě+¶ń˝•č2ô‡Î§ëß™ąŮď.¦iµ˙`ĽóégđvÁ#™Ĺh•›ć aÚśđó#Gµ!Óŕ (…¦¨řűż'ËÚÖZ&/–gXuă˙č~Ěéz‰¦NTF  ۤÚ0ÔŤeĆ ŁĐ˶aĘäŚ Řëú…Čéşó{Ąw¤© ĄBŻ*Â`ó6§`qWUŞ˘8@ŇŽ_đŽu"‰Ä/J• ŻаaÎŰNńö ďÍęP7ID8ăĂ0kţ'PUn%01fin­8Ţř`^›^‡k&N™ĂP˝%® ĽAŢ@ř€…Íśî٧s”Oá…—‰.żKĺć őd”Ä2Ř ÔZ˛zEĎ!›ĎCQvÜB€Ř€˘Xőj¶Ŕ˘ŇÇ§Şťę Đ Ľq A`…H"©ż¨[ŇĹ2Ćpęa‡ŕ‚±÷@UNZ"‡Ý’;ÖpCK3V­]‡¶Ű¶Í—­@SÉ8ţúěóPî&+řâĽdCuđ˙Ţ’Îŕ‰±·ą+Oư±ąĹ߸Ş`ß*ŁôŰ0tÝăµ± ÉX¬C± L2 •Ä1Tä žC2¦şa2[5Ë@Ö}rޏ¦Ŕúę—Ŕč‡H")ľp©J÷l‰7}đŔ}­TFO? fW{â!®ĹđćĽům˘4ĽaD„y‹–`ţŇĺónZq !e3üôTü ÷ÎŽ1iÉŘe‚ĂR(k `µ9`,—K!ĹQ™(\çĽCE˝ç Ăe]“]śÉµ}"$ăv¦DŤ§Ç28îEC2‘@C2 MQVÁnxöŻýs$‘DR¸řţŢ0 ¶wŕpĽ÷ŮBp(öŘń \f(p¨ Ă›óćăÔŤleć*#EQđČż^D*1ÍfŞ‹Í$8Ć]wµŁ, ÓD.źó†ÚXGA„x,†ĆdҡŘŰRůűbŞ`¶­ëU;Ë`ąĽQ˘Ř9ť󞸅×ÜHĹŐşĽüŐeK¶mŠĄ?NA…*ÓH8®x\^·„ÍÜxÇ9b"‰¤ô»ö˝`N8p8Ňą<ŔŚÜfOÄ`uľ”vĆĽůí0Ř„‰S¦·˛*k}r ĂŔ=×\ÎÝ)ivĘD×V#+ČQ†¶^ŤëFńaˇňĆ[UŐÄ2L“É…3^–Éĺ“=ęŃä+SkË”(†i7łň˛ }<CC*…D<î đô‡bL‚@!"¦!’HÚ@¶Hаý¶Űb×z»'§+§ôe2`ůŞoÉĺŰ4LxexhłPا4­»GźŢ8çNpŚË¦–t]µş·4´ Đ€ˇhĆ ŻVn5®ŞÂĆY¶€LN/éČĺóČärőë×A„DLÂYýf­*–ęţiš†T2‰T2 MÓ|lAX„ !,ć!xk5Ä‹DI$ĹEÝR/üŘĂđ÷W¦XJڏÓz‹q©pĵf/ř‡Ú·® DHE–LÄńč¤CáĽLe,ç-3k“ކD„K–á“eËkÖßgžpěţVC˝šé áigŔPq]r‚uö Ö’5B?7 ÓÓ’ˇ~€!¦ńÚ{JÔdűkc|î‡x –űó’cí ¶»ˇm ˘WI$‘DLŁLŮo_č¦a•‰e"+ru"`E–żűégmr Š˘ŕ‘I/Ye»N #… üĺ†ëEą©ĄĄf†!hÚ;†ˇl–ˇŐ{±ŇA77Ë`am0¬í‰üŘ–ÓŤ4’j_nVŃÉ«|pŐ-yF Ř ó–¬p^’]%Ad˝#Ţů¤ľ Á^á0ftbĽŘš’?V…4M·Źţ ⲏ¦––šíAđŃŮ€Á¦‹k­ţČCLŰĽŹ(ÉBé¬!ü^‰zÔ[(u^Eáku,dU•íŻ¬.×ý ©jE…¸Ľ1 ^V!Ě-Av€0+Ëä·ž*z>jŕVä`euďbu`ś:húŢBjeT*v7T(ĽE†#†ěŹŹ–,“5ä‹!K8Y•!łů<ľXývîŃ˝> A®x&NťĐÄ­cŔŕ”î´ýö¸đ§§9¨#[ŞĚÉÂMíÍ00ąZY"ÄcZ‡`ŇY¦€S˝S7ĚşÇ-Ď«rŽDL©ßĽU]“©u¤á«Ň(c*÷™ŮŐŐŽW°HŔŔÄ<@ŽJ(VV‘%˘*‡×ŔsňZ&uHăÉÚńZ¶V·•;ĐĄPQá<«4A5·ä>|Č`äňş­qŕv~"guSUĽóÉguË×&"$q<ňŻsĄę‡9ťÍâńŰnuč×–L¦,ä T·Ňc{ľÔRŃ×Ę2đÍÜúş00Ŕél®îq ˇ€!®8 R7źĆ-1iżS1MCC*…d"UQÜÎ7U4î""«­ĽÍ.„”‡fŽ~t˰[WĘ^lcĄ7Ů9×Ţcŕ5o!§Bµ+řĚk°7÷ÖŢekŰx­«üyŞv޶hа÷n»Xu lĄB°Ę5ÚîIńÎ]´¸n+B!®řó/…t@t ŐÖ^/ʼn‡ŹÂýÁCS™q ĺÖ„¤`ičö|©łVᨭ\t\–‹Ţ¬€!§[Ź dëXoˇřyĹ XhÜ‘†mĚE±Ş4¦RĹbÎTŢC 6řÝ.čÄ<Ý˝÷3ĆjPÜló¶źNÚ"—č]a‡uKżö€w,@ÖŞCv™$bŽ•ţ`á’şE'2đň$W?äEö’QXßÎëyŚżé¬tK§Ň‚˝3 ĎÖµS/‰˘è­L˛Âymťë “7 ·]uWÍT8G2Îë jÖkĚç~ФűÁËÔú>Ů)ĚÂË2Ŕđčf9eśQŞWŐńŕk;ŕĐ–¦C•碅•1Ľ:»Ĺ†Cî‹Ů >•>6P`Ň|[>Ď/®Űů…ăźS¦YA[ÂT„pc˛äsäŕçĹ"BŕćK.DcC y]G6ź·ŽUä1dĽ›0Ř —Ókn}Źož¦T^Ŕ׍ş•~.0´ĂP±Ę˝ŚqÄ4ŐWtÉ;ßő¸w!&Ź IDATpzł$dÔ©“~ŻÍŤW$ťMŮ\óý{ę¶xĐ0rż}qËßžD"·Ł$ł#dózÝ:^ţëż3ašf‰˘4ä ‡ ®f č޵ .?ç,69e˘k 77`°©d;› Úc¨ŞR5®`hÎä‘ɵM eřy…łú3 U>Pv,Mł…`-…z§”Ú <ě¬ĐKŰ=!YÖ:ómą ©*†(bU"©Ëű÷} űíńŘń ÎňŢ&*etuLUđÁ˘Ĺč9ü€šËß˙=Ş˘ĘעŚ7—$ó!Éćđȸ›k¬ÇĐ‘­°mÖ¤‰kZű»UäőohÎ —×Ű­±€d\­˝ce ĄĐý ´ąQň2 N)hÉ4xq«€Eز{M°ŠÁŢ–‘˘ ÓĐádÄ€ţř`ŃP°^)cUQ0wábüxİšÎł©%ŤiマĆDRr Ěîx)]ÎŰ,*íËpä#0rČ`¤łY¦Y7zWSŐÍ ěŕ5łĚŃEďCSŰ=1Ă0°±9S´ßřY. ć mpŢV´µ}ŢXLsJuűÜm ř3%j42ß—^ŢňŮ%;¬~Ąš¬µ#—Ň& —H"ĐP–4poĚ]¸HĆHŠ—,!$¨¨M™ôo4$¶µä+â(>éÎćrxä–a2ą\]C§††ÍÚ2ÚŠeČ×XČÉJÝkoĺ›ÉĺĐ’ŃĄk ý•VÉŰvŢXqă_j;÷C±gĹf 2%ăÂ*2jß'áeŠŤ‹ťi±Ř÷7‡K°­ŔT$hhU†÷ďŹ;Ť‰ĐTMú?ĺ‹#fýs>[TóyzáE©ĐH&DP€a°37Ľë%A„kÎ˙%¶ëŇëššę4tjHmVŔ`+~oH5ÇÇ´v­%‘×uč†tÎl»eu1Ŕ ČÂMmôXD™* ‡¦jnöĂfTęa•˝Ć?ř{=]F›Ó¸x;xź¶\]W›»Ą©HĘţ«Ż­Ă=±Oäňy§FżłÂg˛g6Ö·4ˇ©%ŤN ©ŞyŢâ%řâŰoW5YC„klb`–wBę¦ĆT ×_đ+4ŐP&Úw t Ŕಠ6sR±ĚxŰr˛ÇI7 äó:ä†v|Y5Ő- Ýf€ÁÉô•îMs\?mí~¨d,Ľ€ÁË@0§îkżąŰfł•ľÇeUÝÖiČ›ďľĘ{C*˝Ćö¬.µđ>űßkĐSUě¶ăřnýFż–‹‚Ő)qîÂE8tđ~U˝żđo$cq©Řd=!ÜÚ÷ä‰gpň, ůśGoą ™\®ć*‰ 0Y)¤ËPť""+óĄŤRD„\6ëÔŘÜ€ˇm4ťŐÄ Teó¸ĘaDXś§ ÝŇhórŚHhĆT…óŇQĆĄ- űćĽÇrď‹q^‘Ö«u•ßÚ±­!ăm:W[h€{÷Ç‹3ß*„‹’iPU+˛ĐO˝:*ç>`žćX6Ă`gmXž,±ßžýpÂŹÁÚŤË{PJTw"XÁ‚0Ř~ľ c˘˛&śóé«ő‘l.ĂtAÂć 1MALĺmŞŕΡƵŞ{?´‡.Ö„Ę«H·d˙z9F¤#Ľ»Ą Jk×ćý{{ơǵWk©ńńşß|ótq-«:př°jŞ”3ÖJ—ٲÁÜÖĂ÷Ó$·˘Ů­sH–ý`ᢪŽýÜô×ꇑÇď`čt¤’Eq‚ˇ%ťÁŁĽ뛚ܺÁ2ŹÁ °<F™6`(ôX®‘¨—1Ń ĂYą"ď Q –A«żq“ÇËë:Z20€–śŃîĎfĽŤ=nš¦ˇ!‘¬©÷C{± aĆÉëŽčč~é0EěŰÚĐ µá]ŚÁ}µ±Ë¨ś1+¶yżłąrą18máí~'ś—ĽWřžç*°ś€Ůď-ÓŔĂ{!§ç‘Çüc,‚0wá⪎ýĐ /Bĺ ¬ F«`µ/Ő’„“ViÇ3€?űń1ŘągO4‹8‰Vă¬PQ Ţß_|ńEĽňĘ+ř裏°xńb455!źĎŁK—.čŇĄ úöí‹!C†ŕ Â1ÇS3:·7•ľ»CbaĽŞđş®*ťJ!Ëç=÷FČäŚvOéLĨJ}ďŃ;%´őtűÔ— şŕ†á¤×[Ů{{VÔÓíĽŹÖjCT=ڵcĚIá™JÝ×ć0Î%‹zÉńęH Ž7>§śç‚U±đóŮĎbÉ˝? ~ŻĘ9¬Ës¸-ąq Hb2DÔÔŐí¨üi{N›@Ky4µ´ éµ—Ë6T`Íú Řĺ¸ѰÚK“÷eŢ: Ň5!b–ź˙ÓIĎ9ůﵼ,Ą†¦¦&\uŐUřŰßţĆ´V҉ş®CUUśuÖY¸ăŽ;ĐŘŘX`(JŤ(s¦&•LČfAők&–Íç 29LA›0ÉX}zhŘ/7çÜ*ľ¤(UĎŐ¨ÇăńŞöS»ďľ;†ŽcŹ=Ç<ň˛X=VE…Ô/Ú%ęł®sAV,«tź-‚Ů耶#]«Đ$·đXüůpîE¦i{I;ť÷l]®úLąˇnMĚĐţ{âŁĹKÝŐ…/ćŔŞš8oÉ2ě×w÷˛'ňŻĎ˙ ‰¤ĺ’’FŢ–Á˛ ” §—Ą0®ýßój®;P 0Ř?ß}÷ݸúę«‘H$‹ĹĘVlöwź|ňI<öŘc3f ~÷»ß•ý°]ŻĆ»×Ż©*xSčěĘ -hŮĽŮľŠ„ɸ …łšď ˛E¸¦ŞnG×>Ç9G6›­z˙Ő«WcÎś98q"Î8ă Ś7çťw^č1«űÔ¸0®ÄĎl+ä 6ŕÉ'źÄňĺËŃ«W/üěg?ĂŽ;î]×k•^ßÖTż ¨;ęý¶O¦S¦ µď’Ë TzßDnĐzµă´U1 ·<ňw<đü$™rINĹ4{BL!p×o.Ć™GQ¶ÂÝ帓Édĺ1„ËŮ`Dx¬~Űvî„Ꙁ¬gőT`PUtj  GuŢ|óM'çŢaňyäóyôíŰ={öD<ÇĆŤ±|ůr¬^˝©TŞ€ŇÖu?ůÉO0a„˛€CNסëzMÁB ÉdÍ L0…2x<ÝČéf»×d\±‚…«Z٨ŠU˛ QEišEçĹ[ŔÉ) ‘!«×Šl6‹ÓO? 8q"2™Ě˝:N$¸đ ˇë:~ýë_c÷ÝwÇ_|‡~ß}÷žxâ‰âHęµ‚ŹŠ<&Vg+OQT$ńď/Ó`CöÇ}˙|1MŮľliÜ1(śáă%KÁŘ‘eďŤ9`ă¦fÄ4Ef/ř™ ’­˛ů,îąrtMU[ C‡ĹÂ… }€!ťNăđĂÇoű[uÔQˇÇmnnĆĉ1nÜ8,Z´Ča4MĂK/˝„N8/ľřb«h¸VŔ“kQŢJ+ÍĽĽn"ovWĚ©¸RÍčUrśsÄ4Íç~ŘŇÄë6 ¦VR/Ő0 (Ђɓ'ăÄOÄرcq饗PnI€á¤“N 7ÜMÓĐÜÜŚ… ˘ˇˇăĆŤĂňĺËqÄG`úôéČd2‘%«To±€ËfŹ<ÍÚ/P«úĂŮ5lőĎ™ۛ!'¦Ž±i@s&žÇü“I0ß’3jűőí‹—ÇŤ-ëx?»îFLç=ą»pJ18łć‹i°X†!úăů{ĆVÍ2 ¶śxâ‰>}şďóT*…I“&á€(ŤOś8çž{®/B×uŚ;_|qq–!źŻąŢDC2Y“ŇČĺóˇÝ4mć>›7a˘]ÓÁ¸ě# ü™vUÓ )Ę•jXŠi2 Ĺ€`ŘßéŢ˝;Ö¬YłĹ´7ŢxK–,Á%—\‚=÷ÜÇs 4MĂúőëńúëŻcńâĹ4iÖ®]‹ź˙üç[ĽńŢÎßn$ěmŢ(c`¶ę7Ź)#/Éͤf®! € ąŢ%˛, @QUtnLVĚ4lU ö<íLllneVޤÂ9ľśüB«ÇÉĺóŘîGG#•H¸“퀿KÂţ'“Ë`Îħнk—ŞÄÖĂăŹ?Ž .¸Ŕż°ăŽ;bŢĽyVn~…ç\±böÝw_ß~ą\ëׯG"‘(ČŇ é¨c«\t¬ęęŹvđeŘ‹n÷,ČäEMŤłŞą'…sOkkV–˛s:JvP÷CĄ ! Ř.‰ «" ,ŘÇĽě˛Ëpä‘GâcŽ)xţ:şhš†ÓO?Ď?˙<„čßż?fÎś‰††$“IpŔxöŮgѧOwÜq4irąÜkČëUż˝Ą Űu!Ó´6a-8Á9 (`ОS*í±‘`AH°`A&Aa łÁ™/ţß1Y€)¬MUSdű®©ŠAĂVQ§Á+?Ü{€[ç@¸‹¤Kaæf4—A >üŻ#Źdť’.¸ «Č­ A \pęÉčŮm»ş"‚a¸ä’K|€!‘HŕĂ?¬ 0Ŕ.»ě‚^xÁG“Ćb1Ś3&´H­~XÎ*+mżĚ†a %“q˛5B29łÝŞr$ă X«Áh VIç†dÉx ßş^ż ËPě3[‚eŁMÓÄ‘G‰)S¦€s!«Ťn)-ŻU™kł+Š˘ŕµ×^ĂÔ©S1~üx!°óÎ;C×u$‰‚آzń¶Ü‚ç¨äą(¶ŮĎA9[[‚źöÚ nš€®ů<Ëą(źtÂ4 ܲF!†IČ› Y“!c2ä †ĽA0$đ•b.`07śÜ7kV§¶:Đ0lďţ$d&rk(Č×T/^Úęqţúě ŕŚYvÁ8»Ż…Ěś ˛×ţpÁŻB)ŰZĆnşé&ßg™L'ND,«ÉHŽ5 ‡rď\>ř`Áő !|U[{ 9wk0Ř "‹W„ę‰élÖqő„ł \Q΢˛(÷Â)•ÍYLĺH´ŇG‚qMÓL$J&|ńĄÚ·ŐJ(ěXő>~kÂű\‡ĺ°Ű×Đ«W/¬\ąŠŚëŘ >KÎ9–.]Š%K–`éŇĄčÝ»w›ŐĄh«{©ÖŔ{·r:”–mp·|dm1 6h€Éˇë`’}đ3Ú.Ó`†ĽÁ3]7™»ŮčA`š]~7'·ŞŔńÖő닼®#®Ĺ\¤“Şš˘`Ţ’ĄľĎ€˘Uç-^Š_ݞz"ŘíűמE«q•ašóŰËJö·Ż0Ř2nÜ8źĎ{äČ‘>c_‹b¸ćškpě±Ç:,ĆĆŤ1ţ|ě˝÷ŢÎK],°“H$°aĂĚž= ,ŔÚµkŃÜÜ MÓĐąsgôîÝC‡ ÁŔ}÷-űştĂpâěU§­lR)Ě_°oĽń–/_ŽtÖŔö={˘Oź>8â#L&aâ.¬ôU ™LS¦LÁ‚ ĐÔÔ„T*…=z`ŕŔ8řŕ‘ËĺZWčŚ!Wť˘MŢUc ńD3ţ;ď˝÷.Vű-8çŘyçťŃżŚ5Ş$M»jŐ*ĽňĘ+X¸p!2™ :uę„]wÝ#FŚŔ^{íUý;ţ||řá‡X¶lššš ë:R©vÜqGôíۇz(âńxMÍ“ÂJD]a`Áţ<‘H`ÝşueĹw¤R),[¶ |đÖ¬Yt:ŤNť:aŹ=öŔСCˇ(JhĐ®ĚOŻK–†*Sasąrąâń8rąb±t]Çů矏††¤R)tëÖ͉!2 ĂW›˘˝Á@±´ĹÖĘIG5{Śmŕ``†!3P'ÖÁqexĆ\Ŕ$Ŕ $ŘĄ'¨"Üw`Ç@dą&tyŚjˇmu ađž}‘ÓuÄcŞĂ08%śaů|¬ Šâ•şĆ?÷/$â1Y6Z.#ą™v˙mfeLěşÓŽ8ëřc‘Éć*~y[ D„^x¦i:Š4“ÉŕÎ;ď¬K!Ć;ě0dłY_ŽüÔ©S±÷Ţ{šRů•}*•ÂäÉ“qűí·ăí·ßF,ČŚ°Wśůlť:uÂĺ—_ŽkŻ˝¶heKÝ00gî\Ś6 ˛ű ®ľúj\ýőÇăxůĺ—qŐUWaѢEH&“ŕZÂĂř™ĐużřĹ/pë­·ú®9ťNăꫯĆsĎ=‡x<îË<B8”ń%—\‚ŃŁGuĹţr˙˝¸ĺ曜·řµ˙ţC‡E2‘ŔÝwߍŰo» Í›6!ŹűV׺®#™LâÎ;ďÄyçťW`Đ/ĽđBĚš5« -Ö4Mär9ôîÝăĆŤĂqÇWöÜ뺎kŻ˝űŰßĐÔÔMÓ Ňt…0 ŮlG}4îĽóN 0 ˘ŐhË»®ăUęüşařV%¶;bÄxçťwđÇ\.‡M›6AÓ4¤R)d2ljn†ˇëޞâścŐŞU8î¸ăśófs9d˛Ů˘îťd2‰sÎ9Ď<ó ’‰1´duäóyÄâq´´´ř0çK–,Áźţô'|ôŃG8ůä“€’Ďç× c ÍÍÍľ8EQđÉ'źŕř»Ú—Ź@*®RzB ‹a˙Á±dÉ(ŠĂ0ĐÔÔäÄLlÚ´É7†ńx÷ÜsŢ{ď=Ś37ÝtADČd2hiiA2™„®ëhnnö€d2‰±cÇbÚ´i%Ý(Żľú*Ž>úh_Ě‹išhnnF>źGCC8çhjjB&“ń+•JáüóĎÇĽyóĘî.h†`ý|…}f„zč!üńLaÝşu2d&OžŚ1cĆ ±±Ůl¶ŕůÔuét§śr ćÍ›‡˙řÇČfłÎąÓé4®żţzÜ}÷ݬK%ďđŰożŤ~ýúˇ{÷î>}饗bŔ€řÉO~‚Űn» Ď>ű,îşë.üńHĄR¸í¶Űj 6k`SĎĂă™ďűí‹ÄŹdó=ţ6XPU¦4 ˙2Uqňşç†`Pĺc1. 1UaP8!XµŢĆ …Yűiś 1ŤW\şU‚†ÁýúÉLHÉ0«e¤€eóóz«×­Ý÷Ág˙eµŔ¶_J[ŃyA„¬¨•Óó¸côeČĺu”[§¶RŔđŐW_ˇŮ“BŞë:<đŔv ¤ ˛ Š˘ŕ†nŔŇĄ®‹'›ÍbÔ¨QxőŐW‘Ëĺ°főj¬úę+äłY4mŘ€‡z©TŞ`Ľhńb´d20E錇§žz Ď?˙Ľ™Î\uÍuřěłĎ°víZ¬X±ß|ó îąçĄĎ9Ç“O>‰sĎ=‰Dů|Ä„ °fÍ|ţůçřú믱rĺJÜtÓM>ĂĂ9ÇřńăˇëşÓŁľAmRUĹz>$­¨Ş*ÎýĹ/°jŐ*!°ýöŰă±ÇaýúőذašššpĹWř¨đ††śwŢy¸ĺ–[ŹÇ‘Édpć™gâ>€ařć›oN§ńŐW_áśsÎńąŽR©®ľúę˘c–Ífqę©§úX•D"»îş «WŻF&“Á×_Ťőë×0wî\śxâ‰ç¸őÖ[ËJ! ¦V–r-”’çź©T #FŚ(8oCCN8á<ůä“Ř{ď˝Ë8Ţa‡păŤ7âŹüŁ/NâśsÎÁ“O>YµńVU>ř .˝ôŇ‚Ň׆aŕ#ŽŔëŻżŽłÎ: ={öÄI'ť„éÓ§ăŚ3Ψ=ÍŇv1@öÂ!·%.¶®ŔÁ­Ń5Á•Z‹ń8(™%`ń8¦ŮAŔh§ţ‚Â…â !¦2$†¸ Ä‚ÂÉI·$;N_>Ü:%4…W¸JHT™ĽłŐŐi€×ß›“®Ľ1MsąăŐc@^7đĚcpřC| íËŐ«Ńď'§˘1•rCĄNM«$5Ჟ˙ż9ó Ź2¤’CK2{Ł\Ŕ˙ůĎpňÉ';AŠÍÍÍřöŰoŃ­[·v AЋŰÝvnZ©®ë¸ńĆŁčúO *W´ż®ëčŐ«ňąś|®»î:\|ńšőAT@§wëŃÓ_űo±eńâĹřŃŹ~T°_6›Ĺő×_Źßýîwhii ÍN™5kN;í4‡9Ńuýë_ńăcŽB*ˇAUT']ô®»îÂÍ7ßě;ŽG}4žy晢s{×]wáĆo,Hµ3 3gÎÄŕÁ‹Ćzüţ÷żÇ<ྦ¦&¤ÓéP—Ă]wÝ…›nşÉůn×®]}@ĂŚ9c ·Ür î¸ăĄ^Ěço×i0MÓYŮš¦Z‡ˇYľ|9:č |üńÇčÚµkÁĽ˙ţű¸üňË1gΤÓ銞㖖ěµ×^N°¤ ŻľújôéÓ\pAĹičŇĄ 6mÚTSŽJŮ oŚL ¶4Ä@ľĹ(LÓŠkđw’,ĽŔĎn… M„°X%‹I`ŕĚ*0§0ĂÇçĚ€Rdž-ŚaP* D„Ď?˙ÜGˇrÎŰ0ŘM ‚×ůňË/űîěľűî¸ęĘ+‘Íf : Ćc1ç^c±FŹ !_ ĆľüňË2sŐ ÄTL퍢~y0`;ě°‚ű8ůä“qŮe—!lQîůΨQ٬ŕ?ů‚©ŞŠoW}‰®ť‘Ś'Z-ÂÔż˙’€FŹ]đ·|>Źż˙ýďÇ 7Üŕc ˛Ůl«+ń°ŔÇbÁa0•Já±ÇĂŃGŤ9sć <őÔS¸ä’KĐŇŇRńłÜ˝{w¤Óißő¦‰ßýîw3fLQZęÚź~úiś}öŮVD5Ëó˛ 2NÁfl¶AUMa) šË=!ËéŰ‘LžŇŢĎfě}ăUöST·ĆąéÜŘ®Ű4B7L ěZXŽć-* †|tŇKžĆˇdďM•!†Ľ‘Ç}×\ ˝LjÓuI4V”ńŔĂ7ß|ăŁU»téRŃX<űěłřüóĎ+Ăx"ó˙÷ ŚĆ§ź~ę°€SN9-Ő(!îɢ°ČžýűĂ0 gĹŰÔÔTĆXLh¸ń†‘J•.?ťËĺ0räHĽőÖ[ε´´ŕŹüc!¨ H&“Á#°dÉY2MGÓúµNPR©}›››ńôÓO—5·‡z(fĚáüľóÎ;ă”SN)ëYŘ{ď˝±bĹ <+·üÉ'ź8m«óů<?üđ˛ç˝_ż~áścÆ %Aj51MMMřđĂ1iŇ$Lž<gź}6–/_Ž\ ­× 8ßzë-Ś=ş,7GP„čŮł'ľţúktíÚŐůĽWŻ^Řgź}0eĘxŕe/‘HŕľűîĂ#Ź<âÖ.ńőŻÖ¦34!ŻŽdůVë¨ĎÎmçfv×ÚŔüÚýtě =ËĂn ·ąµ7đŃÁËJ‚í,ܨ,ĄĘ©ß*Aěżg?Ěž?ߥwl´&¬„Ë–ű”Ó+o˝Ťl6kQĐŢo0ŘKPFŘ{÷Ýq⨕•bYÇNf IDAT-`°%HĹV žxâ ĽţúëŹ_·=pńĹű@c ÄÍ7ßě[ˇ…3ć¬lu™ŹNŇXTÜ_Ç‘Ëdpîąç–U$¦WŻ^ľôÔ GŹEiv{NTEÁŽ={‚LŚ €„(Oa 6 »îşkYßíÝ»·ďÜ'ťtRŮCŃłgO43ž¦iâ¶ŰnsĆ?YaźŹ )őĽ3=Z›Ó4*ż±±·ß~;>űě3§ĆA°1›mđ ĂŔ)§ś‚ťvÚ©ęĘ€v†…÷łŮ,~ĺ•;v,=ôвë&|ýő×X»v-öŮgźŞŹÖl…QÚŞę¬mm±ŁÎ“!ʧčgčJ%B†‘ś ¸Í¨B†Úç=ŻC#¸­4 Ţ«ŢţxUţYVt@0–®üҧ˙úě ĐTŐ z´\NßqŮR4“Éâľk®(+ŲVŔ&•úO+Š"rę#„ÝĎÁŚ>¸ä=' B —ËAČrşą\cĆŚ)eĘŔăD</ëŢí¶-»ě˛K[ě˙ p°í¶]AF\úËe‘‚.‘Râ5âBě¶Űne?ŢUr1Q—_~yUĎÖ>5kÖŤ}ôM›69÷Q*m×{ż7nĆ °hŃ"L›6 ={öÄŹücŚ;Ö—‰ăs“ärřÝĺ—[FťÉŐg>cI%,؆¦&|őŐW0L#:Fy$Î<ë,|µjUYăËĂ_˙úW\zŮeŘ(ďżý—Ăä‡ ,äĎDe“• ÖĆ€ŞľŚŽL¤P›ă¨Jg2 >Ĺ6hĎ~Đ Ý2R `$˝=’ihÉd¬"Pš†¦–Ly{6Rɤ,ć'†Á xśvôčۧO«%•ë‚«ąµk×VĽÂ*h$ źß­Ň1çś#ŹsC,ZĽ~ř!Ţ~űmL0ˇě10%nWÖÂ6ŰlSő ł±±Ń×0‰IDó´ź¶ú0ÄŐęć¨sçÎUÍ1YőÚ±W†÷\›6mÂś9s0wî\üóź˙ÄG}TşĘ±aĄ˘‹ICC°ăŽ;â°ĂĂÝwߍńăÇŁwďŢ;w.vÚi'ßőšB@&LA nS0›je(j,€Ęđłźž.Y/ÝŤÇ‘úrC~®¸ň÷wĎ˝¸ŢÓQLť664ŕÁÄÇź|"ł¦Âív˝-•`ĚńŰzŞŤÂ,ÚŚ5¨§}ŻŮ»@ĺěFásĎj:h ‰ę>[Őö>Ů*Ac űďµ'ňşŤ+~d.BŞÂ±ô‹/Ń·]ń×g_@2žp3,dőG/ĂŔ¬rŃżą¤ěÖе"ÂÎ;ď Ó4ť ®´‚Ý=÷ܦ¦Ö“W2™ FŤ…THńŁÖ€F&“ÁŚ30cĆ Ěź?ź}ö–-[ćŮ©¤ˇ–nätá{ajI/uXΡ*Jč‹SÄcJÍĎ\GĎöu-[¶ Ż˝öfĎžŤO>ů ,Ŕ¦M›ś˘NڱVC±y(U{ˇÔxŮu)Î9çěĽóÎ9r$ľřâ ËťEÓV•OC‡agiP¸‚X<MÓ`š&ÖŻ_‡Ť›ĐÔ´MMMXłf-ľüâ Ěťó>ţ3y2®űĂđĹ_"Żë®ˇ÷\ę™gźŤľ?Ř ×Ţp@]LëľöÎ;zŔ`ŚC—î jUá9ŁšM1ó6J“şŤěbtÎA«}6©ŚOËżjVČ‘”w¤1 Uq@Vɱ©.¶=”ô­ĎĂŹÁ#Đŕ—^=ş#&Y·G¨ TEń€†ç-FŢ®ĹÉ"ł D¸ę—ç ‹•5Ť¶qŞĹ0ư×^{A×uçxńxoľů&:č ˛ŽŃŻ_ż˛ľ·jŐ*©_ĘËęH$xřá‡ń裏âý÷ßG\*qű~˝ ‰---0`V¬XQ×`—WĎé&tCÔő­ăŚ!•H8é€÷Sˇ©[_·IĆ>˙üsÜ~űí0aZZZŹÇ} Éž#"B>źÇ6ŰlX,渞ǰrâĹúJ”+Byä‘>|8üqś~úé0…€)L¦aőiĐuh±|ü1^ś4 oĎš…ź| {ŹčÔ©:uęŚíşuC÷ݱĂ;â”ÓNÇ}˙ď/H¦đŹ'ź„n ĽěŹP˙sŇIxz EMĄŞ¨xřˇń8÷—ç!ťÍ´Ş§Y•ku*űS7ĘŢŤ@˛Ő˛\ݲjMUJŻ”=ą€ĹŽ\7ăK•}Ł–[,÷üTŢą¨ű©Ô1[HŢgA©’˝ÝjA`5Żš/KF“Śe ܨp‹i=o>ľ]ł‰&™ň?2YĚ©kc#.ýůr%RĆŔÖ©ííđáĂťľ€U'aćĚ™e†reÝşue#ĎĺË—ăŘcŹĹşuë (Šc|„ŚcĐuŤŤŤčŰ·/úőë‡áÇăČ#ŹÄ’%KpĘ)§řĚ™śhµČSą¬Éf0v}Ťb]%S ßş˘ÇmĂ}ůĺ—ăľűîs <Ůi…ş®;A»îş+úöí‹AaäČ‘8ú裱ďľűú@CXźb`¸–ąËĺr¸č˘‹đç?˙gžy&Śl$¬gÂ0Md2üô´ÓđÝwßá—ż:cďą»í¶a !]Vš§)ëú[9톩Ëŕfa‡‹y·żľčbüâě3qĘi§!“N‡¨^“ Ěś1<üŇ-éÖ(żĎ¸LCQ™e®ë•[!ôdÇp9Aoĺz®©45PçU´kC&ŘGˇÚëŻü ž#QU§l0ÓVn¦*Ź»U†Á{őĂÇK–ÚśťĚŠrkŢţÍ7żd©ěféyŮś®×`Čĺó{ĂőČib¦¸UYSĽ´őČ‘#ńÁ8Šů±ÇĂ5×\S×±š9sfYôô_|ˇC‡úV­ét?üáqĚ1Ç`äČ‘ŘsĎ=±m—.0‰`†ÓgÁ‚ˇă‘Λe·µ.v]vĆF\Ó¬*yĹŚ¤5jŤm)7I9.”b5"ŞÝ7켌1üěg?Ă‹/ľč!4MĂĎţsvŘa8ŕ€Đ«WŻšî­śţ•Ś+áđĂ—ĄŻăV]ëâa&~8b8®ľćZüěçg"›ËsĐě+Öĺ=?w~cŚËXĹ1ęňk€Ý÷Ř ŤŰŕăŹ?Ćî{ě˙-ĂűüsĎâĚł­ęśŚ·¦t9Ľm•Ë{W˘É™d¬˙Yť‹dľťµB˛âŞ2R2•GĂWć®p]®+’äÂŤ+/Ě9Eh†ţÍ“ ×Ęĺ3˙9f€XîXPG–tQ!čˇÖ€Mů~Ą\*˘}÷ئaXŃńNÁ /XĽs?ýĚŤe°ÝNô±ő˘ěßż?~|đČTPţU«ŔŹßšśqĆx˙ý÷#ýůçźcöěŮ6lXÝÎńźW^i5˛!•Âgśá©T Ó§OÇ A|—ŢÚ á×hU4KgÍ`÷׊ ¸*3 ĘIĺ´9Rq™%SA†D%ŕ`sĘôéÓńěłĎ:Yů|żúŐŻp˙ý÷űŮ ď#Xé18őč¶ĘC·nÝ$ëe˝ŻŠŞâŞ«~ /Ľ'ź| Ňé4¸bˇe ŕŚÜĄç}9ň»zĄÂąÜ·PňşŽßŽŤ˙ň˙p˙_ţ"3nTŰ–;î‘ńăńÄÓOËkUʋޯtÉGô°9=%ü¦‚Dqt ´zeÜG%)źvLĐ/@$!¬Š…Ţ€NVpçZ‚…\ QďaĂqÚh"?ÓB!Ě 1ď%“p„čĂ\žĎáWkýĆ쌅ŕ VŔŘş‰—¬˘Ç. R íłÇĐ J,ćĆ4xŞ]ĚůäSpYĂÁcćí¶bŇ™ŚŐĹ2[YKĄNî ¸ŕ‚ đŰßţÖ9f"‘ŔW\7ß|ł.Ç˙ň«Ż1yň䢝*mYđÉ'?ľł‚M§Óxë­·°Ë.»”•ˇAľţ‚iĄýŘ%Á9çÉŽ–ĺ>űV6 G"¦VťéP,}µ’•v=AGËđŔřŇ:Ź:ę(Ü˙ýeW,Őí´Ôßke«ŽCŻ^˝đí·ß`‡vpţ>é_˙²+ĐÜÜâřďmŔŔƸEĎŰ+î €×bX˝z5¸˘@QÔ"¦8ţNÄo/ąyÝđ¤[Ę᫯ľ†‹a§ť{‡ôŽ ŞVze®őýÇ&ß?v•0ë?Ň @ĂÚŠ§Ň«ćÖŹR>Łş+Y ńD°2eLLf§YŔ(xŤĚ˝LćłŢţś"_l …NË%ďąA(ľŚśŕtrĎáČKH0Ď}R(/Á<fÜ˙`¸} ŚĘę%H|ŇA§v€2°ďîČçu$4M> VĚ‚ĺë¶;‹ł;X2 ljO଎î˝vl5ĹŇ7¨u ¶\y啸çž{śőÜąsńřăŹ×ÔńŇVôżůíoB[FeÖ¬Yľ\úAˇ˙ţegt¬\ąŇ>\¸VváGů+ TU•@ŹĘV_Á€Çj7ułŢ†ł^ňÖ[o9?çr9üć7ż©¨ěđĘ•+«<µo ĄÝ\Ě–÷ß{‡r( ĂôÔÓw»62ĆÁąt=0™V¸–M›šniçň»EVů\—\öü푇qÁEÁm ŔđřcŹâ×_ ]Ď—Áj9jż VC!†Řçž±-/ź(0VÔą€ů—ĐE  dAHVČ4Ŕeś†#âîÍŠ`3ż‰µz2X¨Ęf؇ť°WďN}Ĺ"@Đ~¦\ ĎěZ!äx‚WA ŹgŢűgE.„}Z‡Ec ą¨Ĺ*X€Gˇ ô$wńŨşwv«ě=áÜçčŐŁ»|X¬npvĎ)OßKOmá4ĆDřă%•].Ú j}±áć›oölMÓpŃEaĹŠUŻ^cxřŃG1yň䲔ţŞU«| łwďŢew lH&ńřăŹ+1 0Tpď É8bšVVYçŕ‹źŚńš3$D©8‰Ŕ÷ŠmĹîŻÔ>Ąö žľýö[ço¦i˘wďŢeźcęÔ©U˝ű{†ęĹžR©”ĹZÉq^˝ú[ôÚ©—ÓŐŇ16 >—»;ÝĚď7&`š§µĽµ´aňËç˙ú×řż{ďE*•rľ’J%ńÔOŕäSOuXŽ‚ ®‹…٦šŤŰśź-°#7fmÖ9ä9Á¬ĎąçÜś[=^B7Ś)ŕÜŢüç`ŠĺƱ6\QŔĹúgÇă*WpEµľĎ÷x2ÍYQTůݵqgSÁUŠýŻj}ŹËc»sĚĺ˙lž€v€|OGřP80»ÇdßkNľ]¸ďMaP`ö޸$E Á‘}öŘÝbČJźdľÝňÍ·_z&śqě±mW\xú)UťSU”6©^zřá‡ăšk®ńu™B`ź}öÁwÜQ¶ܸq#Î>ë,üú˘‹|­ [3}úôń1 óćÍĂĚ7ß,ŮßLbܸq¸ňęëˇĹüŕÄÎŞ°•3çńX ‰XL‚…ZěŚň¨‹o9Đő´#Kź>}śźăń8nľůf(2“'”Ĺ‘ŤŻőë×’ ˙>8µŽ‡ŚŘ ˇĄĄĹyvÚi',üě3?{ÇÜČv§˘Ö JČĚ˙Ľôş÷čž={Zi˙ź˝7 ·-­ĘCßńÍąÖÚ{ź¦Š*¬˛ŕZe•–H/ E´lhr5†FŠzoôĘĹäjáÍ#A Šš¨ŘĐD0"Á ˘Q$h440pĄŃ Şö9gďŐÍoÜ_7ľfÎ5×Úkí˝Ď©5y6uÎ>«™í7ŢńŽ1ŢWÍ9hͦř?ż˙űńÓ/z†Ă!ŞŞÂ/ý»_Ŕłžý]7s»f<Śĺ°%*ĺz¬Ăă ­"Ôᢊć4Ů©I FŇC‚˘ć¤7ÁÖ«Ův’~˛ŚJÇRI” †Îu1>\LuQ`›‘Q D<ˇ ”†!ś¬•‡÷VČ#^R.Ô%ĺĎüGćđ‹#l^…PÉ^/Ď8d/* LY ń ŰZdó4”ű|Á­h捸‰«ŕ{#-X` Ć“ ~ęź=·—!Ui\Ú”i‰ăyţóźŹo˙öoŹhäÝÝ]<˙ůĎÇu×]‡ç=ďyxĎ{Ţ“˝÷Î;ďÄk_űZ<ó™ĎÄu×]‡×˝ţő0ŕĺ/ůB‹ŕŰn»-űŢ'<á xÉK^‚;î¸gvwýĎí·ßŽWľň•¸Ď}żĎű±ŤťÝݸ”ÁŚwľóťŘŰŰĹąłg±cÁBµ†sGĐ =ĂQ…iS pzíüäh1x׻ޅG=ęQřÓ?ýÓćV ďxÇ;đ˝ßű˝¸ńĆń±Ź}ĚŞ0†Ţç.©”ę,O¬ăü:𸷷‡K/ú×|Ů—=ďxÇ;pQü.ŽL–…bö öç3wÜo{úÓđ3/ýyL&Ó˝mĐ&N‚¸ ÎzČqÇß ű·‹ŮtŠ÷ý÷˙Ž?䡀iě·? §ű`ŁdDĂľĆ CB/ Â-@äĘ`"ę2A{@ÂpŘ^,v5vW^M˛Řt”<<:Źň>¨;$˘Ă9öŔB‹÷sj즅xsŚ'´—­Ś X°a¶¬ázPĚ˝AŮĄ’ Mа µ—b–߯üI‹‚=·Đ JÖTđł‹Ëh Z´|Áçc6ź…;]“¸UÍCíŔYôţ¨?_ůĄ[iAÜD¤<fĆK_úRĽŕ/öś)Ô‹^ô"<üá᪫®Âµ×^ "µ×^‹§?ýéxÝë^‡Ýťlxń‹_Ś'=éIřšŻůšî›E)<÷ąĎŤË`0Ŕ ^đÜrË-¨‡CÜóşë ę·Ţz+ţďçţ >ń©OŁ®kŚÇcĽň•ŻôÂA ŕSźü$®>ÎŚľ™ň¨AhXĐóŐ‡“Mö2t• ¸µ¦?«ľo‘†BČ4~ř‡8 đJ)Ľď}ďĂă÷8®ľújś9sD„ŻţęŻĆ+^ń ěěě@kŤ=čAřľďűľčÚ>ó™ĎÄ5×\ďţîďŢ–Ž–÷ş×˝pűí·{a®Éd‚ţ‘Á÷<ű»±·w¦¸;Z"CŁŞ*|řCÂĂúü‡×ü&®˝öCNhq9„&\Ľ„çüŕâçögđšW˙žőťß‰KŤ-1qÔK@â˝Q`‡6ŕŐ_BpPÂ2 Qč`˛A"`łý^qĽL6ďaź3ⵍ,(ňÓ)(ć÷tÜóĎ"Âjk[Ű×äYYň°A0%ś ĽVÖ:|%  ÄRÁ°í¶ďBU®˙Â5ľöm~^(µ¸X®łW@íŢ‹’“K[÷úŰŤÉ.8IqŠ_S¶ ˇĽÝçs?×t^Ű޶L¶Č‹ěbă„ń!^üĎp%–™×ŢٶŔ>ç9ĎÁ{ßű^ÜpĂ Qą‚°»»‹óçĎćó9Îź?ŹłgĎz»dˇŃ{{{xË[Ţ‚g=ëY888ŔźřÄčłŇ­i<ďyĎĂcóčuJ)oD4›ÍpîěYś9{ŐŔŁ˝˝=ĽůÍoĆă˙x|ŢÍ7Cű^“ÍR=4ş¶;V‚{Y‹íU·›oľőW叙™ń]Ďţ.|ÖgÝßřő·áŽżżĂď·KQ‰Ť°ŃÎÎ.Çř—?ôCřĆŰľżóĆßĹ—=ň‘77ßr ŢöG„3çÎawo/Ľź Ě?˙đ˙fĽţuŻĂŻüŇ/áiĎ|&úJ#.–bw=ť,Íl0±¶mt N©‹śŠ{Ś­Xŕšđö ‰K»ëŇ{*‰?”úQd”`H™^ć|Ľ’˘‘ő ĘB4őŔş‹!ws ­3Źş|ÄP©äSü§pZ ~ô4ýŃ«sWz>Ç _řÂ~ffđ|śíç|r ö÷qa­Ď03ŁRđ ŹóůăńűűűŘ·ďí»M§S\˛ÇżżżiOH–a:ťâÂ… ŘßßÇ… ˛‰®-Ý·YOYrÇ ą÷N&“čĽËía{ţćoţŹ}ěcqńâŬ_EkíŹáŃŹ~4Ţő®wáĄ/})´ÖxĘSž‚űÜç>ţ>2uţYvŚ«şŽ.Úő¨GáŐŻ~uR¦“)^ü’—ŕź<ë;đMßđőřúŻýZĽřE/Âoţćkđ¦ßý]Ľę/ÇżůÉźÄc˙ÁŁń°?7Üë^řŕG>‚űÜ÷ Á¬1›Ońc?ńř·?ýSřĽ?źwÓŤřÄ'ţ Řţ ű™Î¦xÚ3žĎąńFś={Îü’Cy!î%cĎT*’•uERG›5Ý*FR=$x3ÚÓ¨ 1"5źE©–ß9ŕ  Ś6ĚĺÎÜ­ŽČÝ‘Ń °Ť’nşĂLQ¨1ábÖ^î\ 0,}˝Ş-ßĹ­€&ĹŤ˝X „žGš—ˇŇɨM™ŐAĂ:8\%޵˛? Fbŕ™÷q‚Ű·<÷_ŕ÷ţ䑉ËEÚ!>řĆׯL“33®ąęŞcŻ{»šđg>óĽá oŔ»Ţő.|ŕŔ]wÝ…Éd‚sçÎáĆoÂýî˙ĹřĘŻüJ|ÉC)6ĘĎŮŮŮńf2™tË™Ý]üÉýŻxç;߉Źüă888ŔŐ×|>ëşëń =ŘC1›Ě|]ŐeŐúЇđ†7Ľ·ß~;n¸áÜvŰm¸é¦›"uÁÁ Š}Ódşż}›úô"”^ĂV;-M”2˙>őA×xxďuŻżté~˙÷ď˙űńéO;;;¸á†pÓM7áqŹ{ś/MȆDĄ^őŞWá}ď{vwwqßűŢO}ęS=Hq˛Ô®¤¤Wô qďK'(ŞŞÂx<†ÖłŮÓŮÓŮ Mٱwö,>ř˙÷ĽűÝřŘÇ>Ž öqŐŐ÷Ŕ˝îu/<ěÇ?ŕŽ ç…±łłké|xËĘ< đmO:žńm߆G?ćËŁ¸VŚ5–ąh—?pÝú‘"PÍ2}\Ľ‚ {“*źE*3Šč´ź1p| epö=”¤ÄśË1 1%öl %‰©Ű¦ě¬dŠÎB"Şdîkej66ňáÍlŠůlŠf>7Ó+®ĚLÜ«ÖĐŰżaůń¬\ˇó»¸hŃŇnůö%#rŐ/Qşô€ÁÍź(…Ţ˙ţ÷µqz`*~ćf76ö‡ hW6hřń_|ţÍË~ÍŽÖr\˛žë/řţŠo˝íkŹ„ŔîqŐU'ĘŞ€ÉtÚš™®…ş'ÂxÚ€@¨ëşW™ äš¸Ěw®Óˇ2í Ŕ±K rSuţM–¶úśswl)Cáţ+›&—ą†˛é± @8Ă©¦iĐФPŐ*UŮůţ*ĘTÉ‹?őO KŰl6ĂýľŕV|ě“·Ů*ęĘąş˛¸tÇ,ŕHc%©±?ż^Ń–…–±»#ŃßáŇĎ8úD›™ ´»Ä5±q٤ĚŕĹó<¨HÁ‰}•"Ó/ˇ`=BTĐnÖZc>›ˇ™N1źĎŃĚç`ÝX!˛LńÝN¦B– ±¤ň˛ĎÂ*ŹîýŕŽ¬Sô îWZTYJ€AîAĂ­é¶~Á­73 Ş:KrÝ×Dřß®˙l<ë)O2˝ «yÔő© łůłů|ĺ Ü{Áe3aŢŁáČ*ŮňRd•mÓ•%ź…U^sš¶e|"Ö%Ú$ĎŹűĽőÜ“váfmçů }Í„LZxYä@^őŠ—ăYßńťO&q §>‰ *ÓąÔ"ČJ•I>s˙‚‚&+tHA5СHI!8“łPAn»¸° đš ~×<`,¬mŔKipe/¸ÄfźLkŠQR$2 µŞ*p]Ci VĘJ&˘¶˘ IDAT+ÜŰ«ť€Ú‚ďbv!ĄúÉźW.ź»u†b/„dÇ©xLěü“d¤Ůł ëZĄî á÷ąłé Qn iŕëóhŚÇ“´ěש{q<Î~†,Y±ű0›Ď1›ÍcQž…vµŕ3¬khfs`P˛˘ =Ą{Łő+nJ¶AÇ•Â2ś$H)17GżáŃÔĽ şĘ®ľ ąÎRƶ˝3gđs/y ~çÍo6^'}ö·MX. `á$ŮćÁB*ňW$±ÍÔ™Y8pşŇA V‚BCcéô’z ĘŮbŚťX0$Š rHItçݢ=ŠD—B)PUT]Ał†Ň Z7¶ďŹZ—5’,C`hiz”€|»%‰R÷EG±É^”|g® ŤX/ŚT¦%‰-hčą}Îő× h+$@<™syçţ>H)o«QD ×¶ Ž™iđTŻÖÎć^î: tş?đéĂ*TJa01ĘéłąËiăÇzĂ©ľ.eÚĂĺĆ2'HH†µź#ŠłV :Îţjˇ·BL;‹J%ţüĎţ ÷¸ćÜ|ËçőóUˇž˙ś ď¨8‚^ÇH¦úUŞŚäŽ×^%h!`ěŃůľV?(;ť!÷‰»mˇI^gU*µ‹L9$9g&ď«`)=ĆQTŨt n´1âb3ZŰĆ6,d†·9ëÁŕňUéX[ ť/“úÜgÄpb_ĆÂe® Ň%ÉkxŻxĐ0žL đŮ÷Ľwí_LŮM8ý†ý‹ˇňnáô$·9Źň1–'ěÍ®-X0µĺ BVŘvvvĽ+čÁx†FOĐdĆ‘ §V vî§ I;ßťBjćµ1 Ý×N~‘y•â3A§ %Sńo{gĎŕGţůáźýË˙ăÉÄ*. ®—z-·Ł J‰•ĐüčŇt%ô Ůű2Q .Řj(Şpî\ňÄI÷fuÎ9Ĺ1ĆaáďČ †P°˘SÄśɄتzÖ4ÍfĐšű°‚|k_ć™±»ł‚fĆÁxnqËńÎ3;ŐFJ˛ĆźŠ8µ±[vˇ+ŽźÄy ޮί «/ JAŽűWÖ5•”‚"Â~˙÷ŁŞj|㓟Śńá¸cą·A—iíE–ş2ĘÎ…Ű)w©‡lźâťłíi`2ČA:˛ =eřö\1ő>R9ŇŠbLŮë:`•TH@9%ňvű{ĺŔ ĐAŞ`®QimG +LšŠĺ n’‰î\B9eŹ4:›–¨^tŁŠ"}#Üš˝‹,ÜZlË ‚fŤý qfw˙ę%?‹Ń``Ń%’ŽeÓ,b†ŐS]Ő?¦bżÂ ´î2Ě3c4BaŢhNćŢxfÓÇ»‰ţ…>ŔÁý˝ lAĂ©€(>š8ăD€(­ÄÇíó*ůÔ?ţŁĎĂ{ßýnÜuםxϻߍ§ű·ăw~ď-fܸ˘Ľtvď±fĘlŻ™™ša]›ž—IŰÎÉoť`^Čüôç§€Ž:LÚ{‘-/(•Čz*QPýf©"™Ŕő6µ]q Á›2ŮRÄożőđŃŹ}ĂÁŔŁqŔĚ{—r ĺ‰Użł®«µfˇžöe3«>›úŽşć¦ŕ!aFžzP×ĚLgÍ1•#6Űż ď“ełćm/Ăi . µߊ|™BIÉĺ>„>Yé'=ő©řşoü\uţ*Üzź/0 ^Ó„˛qBÓQO`F%űG˛^P¨'m(ĄcZóE*b[H‚ ű>ŞË^30,Ą¸Ž€žm`‘4Ű˙O¦@ü9pîÓVżAqU3* ´őŃ`ęÁěô­\=Ľ.9)Á=ďsÎł;ą§Ňę‘ě<'ŁÇ[ĐĐhďĽë.{»»řW?óR ŞĘÔÂÍÁÚ÷4”Ä}ú‡ş®×HBŤ1ťm…Ť©T‘NŽ\Řq8™cŢčc ›ě_H۵îşö[Ŕp `)pÖĚ‚vBoô_ vÁĚŔ}îűEpťçăńÔçË$ŁliśJ”š˝>‚ĄŠI ÓQĘĹŻS0؆˘D’IX>$ýR)•cĄ$h)ÁRÄAă^ A^ř¤´I˛ŻŮ—_ŚĘf`3TUˇb×5tَ´FĂZo«llř/-ę Xň‚eLCŹĆÇŢ脳ňа{gďě Ö±m÷š·+ 4ö/\@cçŔă oÄ˙şýv ęZhyKoű€Î÷/\ŚôîwFCŚ'ýĺ×5nŮ4 ¦ł™źe_g-Ş÷:e©®ŃÎÇó€öŹa;ł3h™YßÜ=SR&ě:ŢľŽŹW¸8U습^ŘHŽÇ:ö0(4ÁF”µŤ¦Žk%=‹J qŽŇ—ĆŃƉ‘Źř¸R7t“$ŘźŐŰŁŚzB@TQGd!´±Ŕ ŮKą}źIZ0“Ę-…íw2>HlÄťkKMľÜUˇŞjčZĄhŰ9ël|Ś{V":®Ř‘Ëó•.)>jŮǰćYű+4bfewF#<ďgĄĚ ăoXIăŮĹCö/ŮĆdĆp8đ7đq†Ůl†©ő%Í\ô>ë–R&S˝nf«5 Uа;:ľŰQj2,ú‚’;ĺ:>÷4ńu@­[Ů 0)żŘ˛âĐ«Ď,ç_ ß(+c›%éj DE ±¶c¦–űFřQ°Kߣ¸Ż:ňNĘżŁ"«ŚśŚű8”ó<ÝlŠuĽôB:PÂľ¬¤Č0uÝT`ÝXĐ/|=Je jďR࣌´ČYs/fbÁĹ&mD›)A^ŔÉ9Şs„rË€a«ÓP ş‡ă±_Hőµ˙ wÜyj9Őŕ˝č]Ă•Ő%ÓqzéŕJ)ś;sźąë®žÁ‘O²Űt6ó†ByżBúx5Ś Ç“ŽŁˇ-Č9°Ž®c?–}˙" ěŇçw°îúľŤ—ĎZ“âçĹOő"Ŕŕůw.©ERś•ІFFoJIŕ5.ËťrÇ(h8 ö´đLCş—JGQAÔ}˛1ťYCĹUŚÄX« sҶéŃ~ÉąOŢO̬*UŁ©ć FY p]Mě ĽęUăřĽôV|¤%ľ€ ŕ†ăz˛›’`–ĘśYSË–i(-¶˛'a4ŕÇ~îP+˛®®y'ܱĆŮU{EHE„ý‹ń97|6š¦ńăŚ}.î˛ú ab¶Ä$„Ć&ŰŹń´±Ú›(ĚŚÝQíÝq†Ôó˘Ô۰ŚäňZbă¶ObĄ5Ű,¤•ő?w¬F¬Čr<06ZŠú€\Y JË/÷ŹĽÂÁ•>óň…öAŃŢłĚ{¢G2 kRłĆudp7áâµčyéR¦Ĺč*[+Šż’˛ŤR T)¨YEV!RŁ7`ŕe.J)g+A¬ŢřČy‚”&|±=N×ôhFPťl÷q¬Ű—5hđŤŹűűѢűď~ă7qáŇ%¨JE© ꑤń ™Ža­5”R8Ź—zľű*Az›ak‡ĽÜ$ĺ™Ö7©“9ęşŢ¸<˛{ŽŹ»Afčm,CúçT´čn¬ĹůJźĂ㻾şčTbGŰrPCbńĚ µÉÔBYPŔrĽ’Ů*Čşi«@+đQÁQRéË‚Yđ0Ş<) ÄBî©pŚKćäÜŤ8»žĆ¸ĘČ[-Fá_ŃŞ”ˇÄ5#ęu-úŚV.: “sôI ťłB”ý÷ú>-ó±Tł/kĐ@–Yc]×ř‰_řET¤b'S±m×EPVcS uvŃÓÉ4q™k×a®”Zě`:ťb&ŔÂѸÚő˛ĚŔátĄÔĆĄ°O˘ˇ 8¤0z„}#ę,”CĘĆ/pŽ’že“‘jŇVXHŚ÷iS#6ÍŠ˛ÝŠ"EöpiĄSÚsŕ‚Ú˘ŻŠ%xÁó^zm8“˙—Ψm‘Ŕ:cc«ŁźĹÁ¨.ď’­€żxĹË%ó.üží¤´ň­gÚ&sfźÝ=ŁśH=Ľ´°%L/;)Qš´-čT÷ĐxęäËşËoÚŞĚĘŁŁńQÝÝAĂáxŚŮl-V?űňWb2ť$ٲÝLNR!spşéw]¸­5-ő¸á‡»hQ?CÚึT«“ĂěżÍçăY"`4ntńgf ë ŁauâŤ|ĄXňKؤKčéń"ë|»kÍ~Mv ݱîÄô„Ͱśëb*S 0´UItŮ´ö3›ÎR$¶ľbGăŮ:í ŕr:OYFşě¦;žoö‹m6JÎ2šą¸‡#g˘ĄAľi“Ŕ #„xˇĹK•$¦{^€˛1ČŽi—…u+ęŔĆEXŢСŹÁu:ĐĆ&%®ĐਙĂĂhAWDřÉ_üecŁ 7pkCpł*d4L§ÓžÁX›&ČşÜŔ7›Ď1ťNWWoěÍ:0–u¤ňý łóą9QŁápŁÁń$úVaJ˙~™†ýě^đ®“ręŘĎzĂg¨Ňá0?śČÄÄ‚g!5r–TĽ ŕlc|ŽH°`ÁćęÚÉ>¸Úqx†)c0ą=ŘwąIö˝ůgF2Ů*6@Ú–iHÇćJüh˛˝ˇw’äÚ®-Ž™1tŤé*®Ž)”ĐpóŹÄqřžtű=,0 cN¬ô7E®¦ş=aďőTôTŮŇíX­ĎKűĺr-€CűŠ)ť[°Ëˇ—ÁŰŹ÷¸{xMfU—%hpo˙Â…X „?ő+żfD?Tž‰›Ţ О(Żc{×…‹$ĚŢl`EťÜ~ÍçsL6 ÚîĘ~v–˛Akóçş®PmČÖŰ÷/ěVVÜÜn‹~'«™3«ĹhGď ÷¦ŁW…(‘Ý;UŔ`™´°%÷ljČĺ=p˛SV$›©=˿˂Ayď¸zK§ť[̬¤Ń“ĎŢYäHذ ľÄ±ŐÚ2”‘$.—ηCeG”ż4”fVĺÔâć­Z^ś+B5 VwüÔń°đjNë¸%ű’ǢŃŇĎ«>ď+ˇáË5¦ďF-`ĺÖÇě^v páâEč$»oš?őËżĄ”Ee±™ičQ`Ź^eĽU|fs«óĐw_¤ Ôádb$hO¤Ţ<¸ţéŠ97𪊰;`óÝbW.(pA_3CŰąl|Ö‘1#d´G1›ą'ůäO ©Űť-Ą ´Ş_ł§Ě94äeámńůÔĐB% °HnşŤűö „.5ŐEÜÄ~JD!•€ˇču˘ő+Vżň ¨ľ‘<Ýń‚ŽłÓŚPnĚťzóˇXäSş÷vÄĎlÓĘčł·"…6ĺNX0ŁrY@ÄÄ,x®U‘ ş†ÉdŠiÂ~úW~ÍLęÎ/ úµRtÓąfí­bďĽk©}qM“ÉÄ‹Jť<ťťŢ­á™Í5&Â?¸WŽ6Ň_ŔĚ*ŚŐÖ«ˇŔ”ĄJ{)X«ĄĎ’Š,,JE+Rô<Ë]FýGě6›ExÓ¦\Č@çÓ]Ő< :Dhá žÔÁsvą%«ĺöďîv-‰µ’<¶Ç~Ľ’Łßîˇ!±Á-¤¤Ż®|Ř \łílQŹF˙RĎĹ2ŃžŃć4ľ:îÖŢŕvŤ­:Ňdđ&e+męHQ_N‹-3ăâÁĄ˘\ďĎüÚ+M—>YöTá+ľôářý˙ň'Úxí\óÁř°·ÚźÓşżxé@Đ™§Š“ű ŚgóąúňĚęŤYNźĆţ…“–!° „Z”\‰(c dx¦ü;®´sv4j>’9#%×mžö6™¦F»hş€«D~Á¦ ŹIůgÇL\h;¨™Łž´ L9Ř(XXôŤEşđR‡ě[˛ôlr»ÍmĘËTDI1@ójŽ:ÖX ŮlÁt’duÔ U úŞ8«NŃ ]#­Ł– »#sĹ.ßk$ 95qŇëéeJ} nűąWĽ Ě:8Ó•h.f<ó)OÂ?üQ÷cďGO Ś'ă^@’™q8㪺¶sĹt" íÂQϤ„¸•RĘŠ8­s§ĚÇ_ůý ąd¬™& Ŕ•4w‚-s”óŔb ,xžŤ ‰0*ź™:Ş”V!é)‹ö´7IfSFzjOu9áń‡°ŢS K˙Ë. .+Y•e(?RĘzEÚóŃv|I‡$‹Î†RěíaI‡–ě<˘ŠÇ,Ą¤Ć‚˘RĆuĐÂkCâśĹ’âäqrż nN@A Ŕ°Ä@NrÍÚ čň<Ĺe±Ť'Ě­ăŁÜ†~ę—E4?Ć?ć˙5.ŕ˙xÚ·â΋ˇ!Fv´í8c<™´ËŤÚ;s2ťzń§ă3sűQ)…Ńh´0Cc6€ÁKë öag4\kĆęúÎîp%†AfFÓh[âŃOç8ĎqńpŠ‹SŚg8śĚ1™57v$ŇH‰¶şknŢcťôs<żßş†r’ŐrűŇ^ŽÚ$€F<ŃÚö W'˝ô‰ ĺą .@fĺ.Pčđ;-~ܶÓ:ţ;i'1%Ř‘ʧ‚•Y×P“=L™hUÖ™ %3’Č‹Ďqix$::ą¸ě9&’§¬řI\r Ş˛I•ŕ'X‚sĄí_r˝K6Ůĺľ1_îztź-Ń­/‡Ĺš\:8(.¸/űÍßÂád Uęţç9<âÄ}ną“ńÄ€J„ĺŮ“¶<­5Ćb*bíYzŹó ”ÂîÎŽa»K)i˙‚üśŃh´ÖŕĹĚ k k%Ęĺ–é"°:”J%„EĺívŚ„‡}(ö"Ź­ŕß5KRRśçOpäŇlŠ»Ň CÝ~EÎ=ÁĂšAúF×|HŮ'yKkŻIˇ ™5˘×Gá5\,˛°/ p¤¶™gÁH,‚( ş$út2˝ŞĐ1bŮ)uĂťź©=,Ľ I1˘YR'íDË ^3ý;=QCÔŢŁZÁô.\(®gvwńâ_ůUTÎú´Äˇ0›7řžüŹ.]˛×…‚†“ń4 lďŢét5:‘˘Á±4řąďŘí ®+hf¶é1ot0ÔU˝6o÷}Rú4вáťMcüççsm˝bYŮm árA ‘F@ĺÓśŽ˝Č5SG¶Ů)Ím»Ů‰D;™ËJźË]ő}şűĆ# dtΑ<+H)DuÎř÷8‘&"‡ÓÍŽPn¶J±×ł•bˇj¨çŢÝ<»řź®qŢ–/eJA—,š¸¦Ç¸ŹÁbę %ó}Xç vęAĂDětńóż˙ä'1 7T¸™öF;xú“ľÉ€†‹—¬·:˘šłů.ę`ä6ÔC""چCo Ĺ0´˝ý T`ŁŃpmű'Ý)OŠĘV!í k0RRęvlÂbKpź*H®ý,atńDzyë»$˛Ďö˝yŇßŃ-ä¤â m ϬňŕÁá‹ĘşA/ňQŮśSŚGşă ˇEJV%´n¦m”…c^žS´äRJ‰–\˙z኎{dˇ*őŁ-¬EWëCş*ŹT&Ň} ÚNM¬kdăî"îÔV–ŘŤđâ—ý*FRő±€2đ=OűV˙ľ —.bPUAĂ\fâk¦VţąT‡®«jŁRË” 0 "á¨Ăńaëä'ú éçîî쬅9Îé˛n+QEݡ[Přó•6°iđz áKK ëŔ VQnÉä<1 ˘‘Fe{)ѢL3"#@‘sôJĽŮÁĹl&B$jpŚŠ ŻUĄĹwňef@­lꬒ VfqbhyK˝¶×GĂ Ô˙ňňŞ_´\ęt?PđĎ(}ëâ‰Č6Cî+áÖ˙㓉ľ¬AĂÁáaëŰG˙öoń‡ú§8ł·Wľĺí˝{ńŇ%<çY˙$P÷¨Îž îp’Ął—ň`ó Ş ×ŃÎĚ­@Enën‚”MŽJ©l!ťL§hš&Ë”‰€ńTűŇóuÔ}NͦÖÂ$BFňď[PpÂy<ѱśo"ň`xyřŔqç˝°¦nźĚ(0ÇnĘ–1ŕÂXűĚZŞO¶±ĎBa©¨ëŕâ ĹĚAÔ(Ç‚q`IXă)Qţ 1nÉ…rŻN°]ZEN9ebrÁ†ŢŤ]`ˇ%F–”8óçĺP-˙^őTeÇ‘Q%LG٦§‡e8µ ÁHE_j=QŁáżţÚߎjhĄWNg3üÓg<Í€O|ęďMÓ¤Źb‚Nöcr vnmLChrˇ®ëČjŘmłŮ,sň„ď_hZűä¶3:şęăîh€şę $¶@ç` ĚPć‹°ÝNîŮ“Šˇ§ ‰2rŻxhĺŽUĘ4xL–ĺgâbŁ%é‰ÉIü±©ŤłáN˘łE Sˇ1ü‚d0Apđ ~Đ–ýńĄ %¦"şH.«-.Ţó) J`ÓňLCVE6N¶ٱ ‘„~‚^Q±ËCžĘ^‡ÖëIŢŚ:¨‡˛P}¤ČTŚZ ˉ¬“tę@3cŢ4&P¦HŮΩţÎ[ăń´Ý–Úľvow·=î+ýŻ?ů÷(zkćă´Ôąg[óh€ÁŽ‘‡C ËyÓćĚä÷Í‚ţy.wF#›…ŃJעR„ÝQÝj’¤“~ógť5ČmŮ‚Ë0\V˝$)ňü1µ©ůÉ?:mˇ>HfYČË Qö(á0†"—Úϱ]ďZ—ú#DÔ‹´}Čă’(g¦đřj†”¦NL*ęČ›˰J[ę%q3÷±†š+†5 Ą€´îĐĂŃzaPçĺŹty6­A,ČBk'ŕÄńŞäËe•Öˇ6˘ëÓ¸p¤ÍŹâ‡xŮkţ#u….• ÖŔł˙Ń7GżsLű'‘Ť˝»˝P©…At8)koë[H·¦i0ĺwłMçÓŽţů=Áŕî•Ć;bP+4BŻ Mép«]půmÇçÄz ŕ-)aAh™ˇą0a´É-­B IŹâ®L`§x9R~dŃZÇiH)Ç!dŠÁľ8=&ŽíHŞ×¬(śÄ4ß΋A8ʏ †I+„±Nięţ őęngsě-­ťxĄźŕâ„·)Ť–öşń7ËHÔ§m›7 ćó$( ™ŇÉd‚·Ľýí8ăűĘţŞ—đßňÍ~adf|âS·ŰžíuH'÷vwfZÁjЇ®oaggUˇoA˛MŇϱL˙‚Ű”R‹±üţ¦łÓYłe ®h°Ŕ"]fHűÄŠE\ľ a˙Ż´ľşyůÂGęD˝DŻ˝µžvĎŹ ńúź7ČeÖ×i./ż'RBŠŚ,Mdv ÎAć©[-ŁíÔ÷ΖĹD -uC´X‰öĽ•Ö=«ŕ˝>ťPs;Ůř؉Rťč ± §4,bSç˙˝·˝Ýű/ÄW8ĚőŕYßňsĐ𡏄ŮŁ}ö@˙Śá,‚–Á ¨“•âÜTÄÎęŞęa,eöáĐaąOěŰż ?çh} ŰíĘ tlc”«0GaÚ–yI& GKP,Q,ú("\ IDAT¸›*g%Ę‘žlôwo“MáŮőS‰Ë»8)EˇąŘ•Ľď…YűrU˘N…/i…Âc= ˘t‘J<¶C)ĆĘŻŘÜśaĹ´©í;ˇĆú•H©p˛´ąfö¬ŃR°ľ]€b]ÇUź–…CkŤů|fm[ËŻůĎďřT•‚mFđ§"Ő đ‡<Wź?ź}ĆßýÝßa÷쑵¸7µÖ^(Şx˘ęŞ0KÎb˙Üßum&Ćy[$ăśG8? _+ ąAÓ,· µŹa»]I 8'ÂL|*‰§µ+N¦ş R#„’@L eĺšĺgQdđ„čÂ9-‘ď”ň9§ŻŰűI oyĚ~l@T "YfłŻˇ™Ń}´c!ě\XçO¶ÇKVJ‰sĹiOeł5őbľ“Ośř”Fé+Ś@KŇŁ§Ú› iYÂ?™QCjý˝ÂŽ/ř{ŚĂŽÎŁś Đ@D'YvzpJ)Ľőí˙u]Ű’¤aĢv­O~â˘ĎźÎfřŔ‡? ÔuĺŽnP‚fĆąłWáp:ĎdĂÁŔîîÇópp~­ść¬!Ěg˝Ź˙p<. -»®CŹa»]€q*Y…u§oY#”X,g5Ş[uX-Jľ] 1c+K¶Ay¤}FN:_Ů]I‘E}‰•&AÝää©0Ę"12‚ܨiřnJ 6DľŢk˘rźÍńRĄŇL¦YĹ×rC·ÓFX}vp„ĂştŻÜä1µ‰Łő2ťšň„łĄÎ»ąś;ŁŢúÇoŹĚX!Ä\ś’Ëáä_ű¸ŻÂĄń ĚFëŕp2ÁźĽű˝ wˇQ‰,"ÜĚŤîyíµĆ,ł Ť¤žBBÓą˛€ěyč“a9Ŕ-H+fk®dł wg°`&tČč×Ă÷ťh˛‘dâ*˛«”‘–Ľ©-‹Ą\Č3ĆŇ6úé„‘ç4Á©úąHkAG$ Šy,ą†Bi«­DŔWrŹ$›š7.«Ö]â¤,áú„Lôń?5GŰNhL&ĹszÜšwÜąŹ˙ďĂĹŢ™łą ‹xŻżçuřâ[oÁ…ăN9žLPW ţšŞdČÖ( Ťë®˝¶¸ĂÁ Ő@ŘłňĎ}v Žşp‡Ă#űJl·Ë ÷‡)ˇ …Ó:ÓE¨¤ú˘%ұ¦)b…˘˛×GĺMç'‘—J2i^‘ŇöHĘ’c†´´ř‹|ËéĐhbD†ĄMÜäK YĂZ!%ŹX™ĺÚř)e,ZßK…/\ĆbľaŃĐeXLě{Xś{A0öŤ˛ąČxűůi+ą3^. A^Wš7Ú+ 6:v,üóżx/ŞáHp†0\b2ü _ýU8m«u0 ńçď~o<šq›ĎqÝ=ďY\GA'fFm'#–Y8× ęşŢÖv»L˛™h:®±Í–]<Çeť~a{í(a„¦BOă{ťřRłilsěżČ¤Yqˇ @Eć´ŇqBëfËą°ĂŁ&‡ue\ ý^ĚNJ'j÷‘©Lµ,-ľ„ŐzV˝5ÚiŰx‚ÓîÓVAĄ„#Čn9á+aďąĐřčĘ%+ň´–3+nuÔ§‡bfęTt™ąÖhĆ|ŢŕÎK“Čň$L,…ßľçýďÇ V^°”8ď+7sü‡?ZkŠr‡fĆ{ß˙—ŘÝÝ5w•Őtu8Â`4™ť]\ĽtwefOn¬±¶S ËL7¬ 0¸Ěr4nŁćÝps} WT9jYÖÂĎ»[X´*A;`yEŮš€vrĚ<µŽí‰¦ ç©"—5ňÚÖ0Á ‚tÉC+ N–Ma? aŚ­t¦Î¬łăđ/QÜ0ކůŽţĆtš- Ľ-/oÝ´DlCŢÖ«jaŽ)wĺBsI¨E„A%ŤĽr Uλ$r4řËƱ†ąf4Mc$‰u8:śL|aëNÖ5Ţýľ÷›ËĺĚĄ‚i˝ß¦Ó ůĐc2ťç<űďo|ë Şj®Řéązúňónşł¦ÉzvFŁěöÝŰÝőłŃËÜü `|8^ĐŢ6>ŢÁ{;äËy˙»DÎúŻ„ĽDđ&ëT™őÔ[şŘLËłÍÜTˇ}ž$Ĺä8 ÔĺűýąsoîkS9}bdR¤EđĹkĂrçxĘś©Đv@ RŃůON[Ă VĐxňę…Ŕc Ö«EŤ;߯čQÂ9a8ś¦‡ťľ!Ám‘AJúK|é@Ú‚ŘčSRˇĽ,±âŁw,…đKă9Ć“9ć gŇd:őh­ír×U…˙őßódkA¬Ašý¸ůĆ{c6›Ľ/ůoýżoÄpPŰ+«ŞĘÜí·Ţ|3ćóyöÝŁŃĐ/vÎěě¬t®mĆ*×$ن»X×űr˛tçţěĚyÖó!«#k©ÁA˝ĐʵŔ‰#wěŁ@Dą,Ą­TJ$\ZÜeŰIFî;Ѣ;áŘŽU ąí8ı”-&q®ÄŞHN´‰ =·®(ň IĆD‡EĺĎâ®kÁë­jP÷%_€©e?Ý%C”$4űŢ<Ƣ,źzě¸üQK%J€ĂeĐÓĐ&›Ţ˝¶ËDzEžŁ}0˘D“„:<<|˛ˇĂšáš•ĚjI(÷y&<µó †˝^rpÍŚč ŃÔ´0cv_&cNC*d§Ó~˙­TpŐq*±"B#­÷§e Žű9µÔ•n¬žEvť˛˛‘:§)gEĚÄłäx±»ĄŔj\·Îá` ň”8·)Ź,€ ™h§!ÄG˝éŰţNKĽ˙%¦ădÚ¶Ů|ŢŠ»ĺöéĎ܉I”ĄsŔǬ­ÁZcg4DÓ„j˙ÂĽîMoĆ|>łŻçŔšśĎć¸őć›éXĆîÎȆzeŔ0ťÍü8©ĽAW]„ëşF˝m|Ľ[1 ‹sĽS´Ż¬~K€gMßĹ guÍĄz­&+N',IfW.á Ëŕ|ÉŃĹ2H&‹µËËIfś”äŻrlQ ^îş°Ňe2ţZźď˛SŕtĘ´WČ´€2J:ü’Ń P‰~ł ­XvťëiDÇĚś€…dĚ4RÜ‘ś}’ÂIĺdń%ůWŽžśdőČŔĹ"śOű¬zçJíţ޸#ꥱŽ;X‡>,c]Ť¨'}Ňrµ`¨Źň€R¦™$k^ Â+˙Ä'1¨k¸xp u]á'_úó¨+%îM;‡-4ççÓ)|żűĹhĘŞ+’Rر%Še‰ăÉófŢjD˛ Ţs>ŰĆÇ+$¸@ŕ˛rĄ6ÝsľdlÂŇŚHy%p ö}&¦0Q`YĹ€‚>ĐqtŠ$˘Mď%ť}ďGFÎq›S? 3dżEÁŐ0#¸ Éě•+9+ĄÓŔ±h˛'O hęč»Đ˘şOÜţ: ŤŃw2˘r…ď ČÉSĎ0ÇĆWíYw‡D:<—ń4}‚°ľîuííśÂ%•tÁ[z[Đ?=ۉ2 MSöUHOďĹ‹—â;†CÍM»˙iĆx2Ĺ[˙ří88<Ŕ Şđ/~ü_ăSźľĂâ4ź#$L̸ţúëqĂő×L!Ä’vW©<Ź‹€ˇ kv^(RKŹwn·Ë0i~Đ ËŻřÝG'<ÉÁKţ›Diâä¤)DtJ ~!NqädúÎŕ¨+ÂwG¤QË îú ťr k»ć±gśPPX]cA.-9BKR­Íšę2j‚?bWť®1ÚµŚ“2°\ëzÄgz#”âôµÔ#ĐRŰŰW„äŽ]`¬`čgđ˝$ś–ž”řéó„ó:žĐµe­{ćÁxl®ŹÖ~Ö4m6b0Fßüěgăľćńx˙?|čè«:îĚ‘Jyv!xäĂ*¦ĚŤ: °łłłtI‚™qh?«ĎűÚŘ•ô6ŢŮé.Ź0ݞôÓÝŢ“ĺCď3ş“A÷„ră`8u ̱[c\cu,ňá=RÝ0ľ—Z]_OC±DPđLF-0KGK´4•™‡üŘXh,&Oh"ËD)š˘0{Pš™ßs9t@¶EĂzçUm$ł¶×%‹¤3ßĎcRbłM~Ô”Üďt›ď5÷äIĄ€U8'Ş-űgs™Đ®°6»¦ő¬µË6}Cx¨ÇÄG×±vŚŹööÜH´¸ŹN4°îWÝw“)ŻpůěŔU§đźŢôfspUh'đX€·yÓŕ‘_ňPË ÷ďî1¨ęŢc•.Og3Lgł•2®6Yf¶úݶÚuĄě„HČ:˛[+J’¸č±‘Nś1ťŇëüÂË›Ź«‚"2]üÉţ3Ž8Źľ†cęG&•»í˝$wqĄ÷P~Ł$t,b‘š^ĽĄ°«u¤X×ZîôdŁá"ß' ě.Ů€0?łˇI¬]ńó#&Ł@––Řáö$×ÇÁd‹-•¸ —Zb93ÂńóoX §NPńĄ˘@eŃÄ1–d ‚Wax=«őćŽö‰©rôG-űáő±ÄNQ[öHÝ€c¨Z"˝F^O+hčůş«Îť´ŮEž(Łrü8tß´Z sAçł9ľîqŹ™˝Ąő2ŰÁxl´!ŽşGů‡-“¨°@DŘŐ¶o#Ő•?]ä;K5ĎÄŁkŚNĐ#a‹4 ě|Üy%¬Ôh4‚NäőőĹmÝ3!‹˛fŽotűă¨J$§Î©uÇź&qňšń4DÎęrA¦ą`o/Á0…źĹ |ĺ»$:iGĽýk™JČ"ş7u¶J•vDN'îR$T,CĂgZ! !ëm!Ř9nÂń-¬Sr›Zś05¨M^šŃ˘®y’€!g—LÉ(v® ·­ľř/ýö "퇼™†ľŰ-7ÝĚfĐ;ŁH\{śşHś€*|˝é«űh Ěçó^Y}»°Îš.3cg8DĄÚ­Â‡u…ѰZŹPÎ1,î”-´Ńq†/öoŤą"4Mc˛„¶=ňĽQ¶Ę9€ , NĘeMä›éR×Ů$ΰ19ö%»'l ”ĄÉ݉bZ3zÉş¶÷s>Á{ĎíRÔ‹„„•@źČZ$gS awm3— Ä”µŕD˛:L\.ß$ “ËZ8dď˘ÜV9(b-U¶‰xt0pB@ŠŠyµ:„aĺ3Ř®.}Ž™ŠHJ$t’MoĄ×—H>ął=rőűÎ>«ś8WRW`¦E÷˛Z!­^–ËľŚ§'˘şjÇ6 qďĎ˝ źúÔ5µ#v´Ý¶,2ăO˝í6ĚDĐßÝÝńúĂ-„FkL¦ÓŤ(223†Aq´’™Q)…ťQ Ą®pűă nšŤÖÍLgs4Np±xdľ“úçV˘«kS%öSJ#fD%°Î×gć8›-ńőHىŔ‡,ÓÜë•"TŞB]UP§v¤¶™@٬ľŔU®PÉQPëJĚ8Á#$ľŚńWkÉđŠÇ%@8qnz©B耝ٛŠJ…8ŻhÁ”&Ž [nüČÂÓߣŠŇ%$yĐ-Ś·ť÷BŹö‚ĄÖh« áĆ+EońW§|Ě€ű\× Đ#‘\ůś(hPJe‚JĄm2ťâ+ůexÍë§=ÍA˝¸ í(”=îýŮ×ăkűĺ8ŹÁĚŘ;sĆ/ÓŮ Š( ÜĚŚŮ|Ž™e%6Ń1îĂ0ó»0WgXaPWŰ)Š•Ďo`­m®çd6ĂĽŃľŮď)Śá#řĘ«>Ů âE©o¤%ŁŠöNŠęđâďLtäb[)…ş®€ ¨@U‰ĹI jÉŇ–\SKô’ ´Bř€˘N’]¬ń9§bOŔ;šL<±)ZڬÇF^^h $HÚt(‘Óű+żáZ€C,$ĺ¬?Ę1ň(6Mŕ0=zב. s""NËî@ 2 .ٶ%N4ż%G.Đ0¨kĚç‹Ç›¦Á?~ĘSđŠWżĂÝÝäëN_ó ÍJöńšÎ¦ř‘řżppxh˛§Şňz 8ڧSĐt R ,šć65^ĆĚÔu0FÇťa}ĽsđW0r`Z¶a>×5Z7Q€č·qFú- Ľ7äyYż€ŚÄŕ8›ęĹŻo“ňĺlωŤ24qĄ Ő©¸Ű\±:R>5•÷’“ˇ™ Ö–HÚRÚű °/ÄI6IĹĎQé÷×ç´0A'sM†Ń˘˛ńťýÉ $t0vͨ%$ŃáŘI˛ö/ÜG}%BJs#iş\kŃ:n3[ftNÚąX"L˛¬ţM-M Ąšű"{|ţŠ»y˘ ˇoł!á!÷˙b|ÉC‚÷ţŹż,/vÔu)8âŇ„/şĎ­xüW|9Çhfś;sĆÎC—šő-묻׽N:Ŕ Ĺ›\ö¶7ŞQEUŰíČ9‡k`˛b,Ú6D–O2µföYFŔ]OmĚD,ŐtÉĄŽ‹ŇÄ9÷řŚĹř%Ł/í®µ2¦s|’˛SĽř×ŇÉ6é 0•ČĽ‚ ¤– ĺÇ%𔑙fNL’Í{”0&RV¬‰{.Ö\Ľý´Ôiź‘2pç Jw–fLÜŹçɱR-¸D©Ľą’­  uͨ‰}Iř@G˝ŐHÄVב0ŐŇ]†-F´äÁĐ’ â(qű$—îápşt©×kÇcüű˝}ü Ř`Au-şNŃM‡xŮż}±gövv0Ôv"ÓÔ:™.ce)ĘF3&łZo¦‡ˇ®rŔ7:nĂýşăNśaoŕ“/…˘‡śË٬RžIrkć@m7)'YiÚyĆ1䤫'ĹĄńH¦h÷î5†Ü®5@…Ĺ’Ö˝­FˇÔCÂE ĺ¨2Šd`§(ő%f@)ŻWŔBuV1CešO2unŰ÷áŔĘ‚‹÷G¶ËâźÉ˛śVfźŇ;Š:&đü$MAo"żń4r> xđĄŤŇwĬ[zÜT¸x!–»LŠ~ëĦ:gIµGöÖěňkŐ’.ž[)ËPdWz[K©-«5®¸ť¸ë‘PęĂ6\{Ź{ŕ-żń*ŰÝ,:Ł}†XúŃvĹ›1Ă=ÎďáŹ~űŐ¸îšó8»;ŔąÝîyŹsŘV * *Â@)( Í8Ěq0™C36Bi„™ˇpfg€Ń°ňÇľÝ6C8”~A"ß"¸ÖYĘ<ć8~±Up$3‡@é‡DÓůwÇb:ś2.sVd‚QŘ?&źIfŞôŢí‘ÂŹd;„dö:B”ťž:Ô—L ş5QąÓDě˙ëÄř”}ˇl cŐ˘îN{”Ő$g)Má3/î2̢–((Ą@Ę2R(P’ĺ0ĐÁ‚ĽĘÖ ^ö:Í×…žeü&ŠoŁ>ŹSŠUSUCëD(÷…rá8‡+ňQË­śď^É~w5í*>÷Ń?e ’mGąH[Đí°y†˝ÝťĄ‚â­·Ü‚?Ó›p˙/Ľ/fă‰ďjc47€žzč)ĐL€f n¦^·~Ó7ŕťż÷&ÜóWC)ÓĽuîÜů´ 5p8žăpC`! #ŹZw†5övę-«pw3 (EPˇRĘüT*üY)¨JˇRE6Pq>z·@}@ĂYSAÔ™ŇHĎA˛»09CBkš]?“ý‘ ŔR“EĆOHBR%Ŕ©˛ą7Y•K Tąő~ ¨‚ŰÉД Ná řQP¤x’gá-UzKcITŽîň;ŇĘ /W8ÖnqÓcŕźčîů’Ev*K˝6Ř”m'®ÓŔ ś?wwíďgYs"˛ŮżÂu×^Ť?|í«ńÖ·ý~úçüÇo¨Ş‚RFä¨ŃLpý˝ďŤo|âđśgΞ9ąő»`fś=sÖë ¸ţÍŔt:GcËÄ›Qé î™Ă¤Ń[váîľYŞHAU@E q§ÂڏëÉ` ŻfK§×Üj§*Rh"”” ĄĆÎŔćxt'Ś_8ĺGË:p!Ë&{_ŚdŻ™| ÖĐ^Ě®óí: a~¬¨pŔˇôb lńͰ¤d‰ ©M[ұU1ň‰‹c»· '®\dĎ^Ű2Ýv\KoKs›]˝@ˇ®*śŮŰĂĹ•˛Y–R¨,X†pN'xô#ŻzĚc0OđŽ?ű3|đĂÁ]űű¸áúëńĄ}î}Ă 88<„ÖŤUlt†TŁáĐ…F3¦óĐł@TČbÖÔ÷•6=îíÔ¨Ô¶Ńq»Ů †¤UežŤJ‘żo3ĺĚŠŃhFÓ5hSŤ$ Zn\ŽŐ#Sˇ ľ‹Ý±¬ăÔ‘u¤/M2U9,č›]Ćíu (/GÝy.Ă$Ű@hfőµTą~Ź’3Ň$…y‰‹Ń'"ů…»•ČHű-ôó0KPÚßjŮűr ™­´˙J¶S"ŢÔ&Ŕ˙Ó‰tä"J+>ŤÁë:h2¸3•i€lŕ§u}`6§rů)¦RW„«ÎíagXa<> Ň·mâk"źN§PŠđ¨/}ü€űgŻ˝tpeîĚŚťŃ{»{Lătf[G)©-…Xí¸‡µÂh°mtÜnIlQE$Jnjń…2¤»˛5÷9аźa•Ođf]ĹÄžô&h‚9E7Şuz$«x©b‚ Ů÷¸¦ąÜ˙bQ'Wţ¤ĐüÉÂÎFJŹk¸Iáî(żyQś]5¸ *ç=„ů…roP/»D1Çĺ oť-Ý;î'7U;x5çJĹ 9¬W_Ľ/´Ęů” Ƕ,ˇíÄYĺĚĚX머xâÖżŔĐ»Ž 4ČRĂ V¨U…Ş˘(öv1¨+\¸xŃ7Ž-suÝiĺĂŮ3{ÎL缜HSé"Ňrç`4b4`gXyO‰m)b»ÉJ6Pş<§`éŮ×ó`_WٲśÖAö95vŢäÁ8‘ŠM!ťbˇM¬p Koşç’7m®Ń7§&ŃĽÇŽpŤ2D%Š ÁŽĆž 5™÷şB€ĎĘ´ů?9RšŚöÔ€ő…HčbŤDd‹Űł˘THB#w4…©«+ c#$ ł\,ĂňĄČGĽ¨×![Ô8ëť‹Ďeo¦.˛…ËřĄTzlÖçÖăUÁ5.tľv8Űî•“xZöĆ]"Ž,-GÝFy=™é±€"`8¨P+…Ş 2ó`4˘ľę*ě_¸ŕË }·ápŮ|Ţ XÎěíAU\<ŮóGB6–zßPŮŤŘăíĚŚÝŃgv‡Ţ\j»m·îç&ŘSkÝ i´¶ÇNęJˇŞ*ĎLhĺht-¨^ňťŢÚz+RJř7™®5Ĺ0¬Ýh{öĂĄŕíśOÎu" Ę išŠÖźü3bACéĘČ‘d°Ëe€[&`(č*ě85s°BÚn{ó=)a‡0Ƣű‰„é SrQly%l=Ąô´¨ĹpäQ`Gş"őŁJ(‹€yŁĄ ®ü!=Ś=ˇZĆIŹÔK¶É=s®ŹÚŠ|­cɦ^OK€Ź‘Xť­Ě7 hŘŐ…±ýě)ĄpŹ«ŻĆáxŚĂĂ޵ĚơňĐę/¸Ŕ\×5†Ł]Ět:Ą— ŘZ/ţBţË|îůł{ŘÝ*:n·%ď/ëŚze`d\:Q+e»"ÔPĆÍІI­}"í ^,^ĺN´fhj u9TJ™ ;ĹA¤pâNąp%yŰn^.vNĂikżl…ž|c L‘ÉŠ”˙J«3{KiX]…ĽÄC˘śˇĹˇ L˘ÓáŔ“–€`G^ňÚőżŔG#(©Ř¨’N[Ţqűî8Ç“˝J*íęDśMˇµ•*dĆŹŮQ«Ţkť·©T^E°~“ČÎMŇN`}čýo¶ŹĹð+ÍĺŇÝX»;;ŘÝŮÁd:Ĺx<ŽX„¶ «0´®•ő`Ş‚Ahš6ŕqÄ OíĎŠ©ĽÇů3¨aË-l·Ł…IN8ÜŘIŘv‚¶,‚•:f@S"ĺ}=`Čě¤Z)ËlT¬¬Ôz]fĂ—éřNjEqÓśŕ(Ävě.gÚ ©¦–"X™ ’;683|s|¤ÉRŢžęö®MR1g3IŠ DÚͲŹĂöVxÂ"ů ŮĎbߩ؍2"Aj.Řfřś›P˙čěĹv  ¶lË50H&ť–q í޵ë˝ěˇ%í&i\1B‹1K) f¸<@ĽđkťfHƱ°Átn”ƆĂ!4s/C¬%x¬…«Ó\¸Çůł¨*ŐÉŠl·íÖy3 %ÉŠ¸2˝.¸FHwß5vDĚW˘sĄ —)KŔĐhm|$ě}_ŮQgE *0ŕďâSÇ[Ňacś9VňöÝ9‹(M¤Lx4´úF hß‹ań|ÉB#u„ ě‰ .,z˘‘@GKŰň‚ř§ Y¬8!EĚ9qÔŕŹëç;’Ż‘|”Sˇ‡7Ú”I¶mF Es63)˘CYBLĄtyoŃšúzLĺ2yň2čęÉÂÉŰBĄ ň  ]tҬŃÍu®Ż`g4ÂT)L§Ó%÷j¬ëŞ>wf„3»;ŰFÇí¶&Ŕl¦$śG‚–n«ÝôFÜÉšĘ×€«O˘µ6Śś ^ š9k®´4*e;xŕKţ»=ë…NSü(óü ó¸ŔQ:p,L3)ÔÚ©ďç!î¨HĽŮM:¶Źl{cť‰ŘcfŽ‚0YëfW̦´ýߍ”Š4‰rKGúëý&ĘóĄ$€„•t2p ‰”ł!'ęéć®Ůâtśý}X·đ?-Çv‹ÓJ˙´pAÂÄ\ń AŢHŽU7Úgm `8 R ăɤwCeů[Űó)f#˙|ţě.”Ú˛ Űm˝A\SŁĎ˘Cc–Ö:ŚcúRť2”©eÜk”ô’ŕ` Ţ4FJ’@hV¨,xőe›đކMó řY†ö4¦Ş»öPH‰Î°”wĂk5¸ÖîH´KÎĐ,¶´täp&-!QщáI Ë”„t2Á@4X=I’ACmŢţ9¦B,ŽÄ]롤üąÚs˛śÚ&AůQßÜśJÚwËßćNŕůgűX z¤ˇą’V ^â#ł×Ö˛Ńm°¶>8)şÁŻ@Đ Oµ¶@a6_ Ň­Ş*ěíîb:ťb¶Tą˘{D•"ÎźÝĹp0ز Űmí÷?k@+ř›Ć Ěw=/#mK J)T6H@ü»Y•°´ŇB×6{©Ř34Č Ó*«6ÉútÚ[°˝LňůΓśň˝*_„ČgÇ‹•=ý®—H?9Ij·Űŕ­ŁĺĆL5ÄŚ€ą¦Ś€ íç„z<űŃP;˘C €lŻ…&#Oí]Ű- qŐj>x€RwB‹dĂ‚„Ëž_-H˘$‹‘WiéĹ%QňeŤÔ5â!—¨´ Z´?W®ő#şü®„ŃÝćN= ™–ý»Zę­qÓd^×á6Uźľ‡>°ŤÖĎ5ćÍ’"LEz†0Ť0 0ťN17­á=?/A»VXçŞs»ŘvÖ[va»­;“6la×ćŤńDq‹š† c‡„ ]2;kAÉŃâ‘é•ĐÖ!uzB™ ~6É3 m*´ADŠĽś0ĹÍ=ä˙IH%€\ ?Î(Ż•—wŽ„#âĺU+m§ *˛âć$ř©lřŃJ6슶ł^MS cÉ× 9]ʱBK©—ҵ•|#(­×—jAz1W”^ű諳>–ăx†Ĺ"J8+-›m‘dôŤ#íw­T#Ť_}ô¸BŮlĆó†ŃčłąmľYł®y;îů|ŽŮ|­őÂŔďPiUU8»·ÝŃŰĘí¶ÉĐGÂ(Çô&0ćMQ§rôOĄt|’ÜpBÚ*(4JűČĺź5(‘uÚ<Ëv“y_F:ÉÂD‘´íćdEŤő÷FËŞ’)m”MÚ6E«Y`XťżHĹPaC’˝ŃěĆ(ŹĂ°„H©uBš(ŞČN}([´ĚâÝů ÄKŻéŢ Ă„„ĚčY¸lĆÁOj<#ÎĆĐ m-|$#`cAÓŘŕî0©>t„çB*ÁôĺĆŤEoËýMËÁ€+u;VĐS;Śąfč†1ס‘‹˛˘őm„ ¬„ÉćlC­˙Ę×+"RŘ °;¬ďŢwĚv;¦Ť˘±9#ÎúŠÉ>8…đ) ÚĚÜLGÚŚßá «Ý ć°Q“W° á¤ÖŠJî"Ëu"G†6V˝?ÓQá©[$¤A•© łĘű—F¦@äÖśŕX釀ňď’Ç©LFλ)Y¶T&ŘYú#'™ë<˘zyŽŞM2Eé—C)@ ¸á€PKŕÎĽ&¸=ĆH‡Rły7·bZę®\–i ´s2§ h`†ďĐněâçkGI ?‘ĺŮj<(ŃY.÷])`gh5 ¶Xa»Sd jtśIűĽIfˡ4ßǦf (Kg+R¨•ďp0ćWŞ˛ÍĽěź[ŔXŇSE^çÁiDśÄł@‹l/áÜ“”u ›>ĺMz4O(ďAP®G€ÉË9K9j÷˙Á ±%›&Ö¬?ŔË=pč•°ßç&+XČL»ŃMř^€¸’(öžpwNN‡ç“ r·ää"GS)‘&"lÇ+i…RŤZFŕ©E°HX}+ůµŽ"–ĎA¬#ŮŰ cpM;éJý´üb‚ő©· h8„@ÉoâÔävD ˘agXE^[Ŕ°ÝŽ#“Žš]&Ä\X6(yEt«ćP#×ÚŚňi ŞŚý6¤´˛˘H¦$Ň i,`Qf\S‘‚R°â@t|OD«3¤ËĹd QD{—ą ±D;kččë(ó%0"‚§„˘ 6®ě ł`őáŃB\‡Ą.óUn…S©·ô¶“š8¶ëćŕGANQ@D@jU;˘âŮ*e÷ą—Ĺ첼iŹIyh۬+z=­» ĚŃóĺQ8ätÄ&îé~źI6Há /JŇňĘzDUŽ­(ÁeR3´éŚw¶Ľa‘Ł–ŞˇµłH¶Y”ŚEŁj@cý#\y"ÖŇÓÚŚ4ëFűŕ§čÚ°:_SKöcé=-Ŕ”»Ëü Ë<Žłî}×7C©˘lx+ôRídĎR°L Ýxˇ@:Á€Ęq%RŮ0ŚŠ*'&€˝/«6—Ĺ(ý‰6ĹĄ”QhĹ^Y©™őí¨=oNa0·9®şŔ۲„łôę«‹ś&UO {T`\Ô1ďm;3%ëÂCőv• ŁA…á şěŔÎv»B0Ź%Ť­M#˛ę¢É"B6¤Áf8Ť«ÁŰĎŃZŁ!XÜ\f4›>'ĺĤŘf€Đ€j¬”éŤh›Ç?ôĆ9ĐľRŇŽA:€8ö•Đćőa´Ń­:cł5:™(ôh’ÂÔN’2Ëb3fś.)R˛,——ż6GG‚„а‚L‰·{‰mřý Ťš”E÷Śá/! Š3dť01ŹŃˇwăń#®ĂP¦Ô°śpł‡îY /ĄŘŇłqĽ„DŹ7µődýYÝ‚Ë. j…Ń Ţ‚„ívâ°ÁO~5Úë$¸ŃKŰ TX­řĐPcgѦiŔlJnÔ×g0Ą mu´g*D0·ú D¨Xˇâ“qąĽ¨,‘ž\:úmŮ÷;NkDş[‚fFĄF#;±UrÜn§,+đţBŐŹ#űÁ–°ę›Čt¨Y§öĚ–‘đęŹÉ!ű,QXEŰq7Ín$™#ˇ˝Ív5ôWp Á\N?´|‡˝W&ÍϾˋ{Č]pX„ŽşöÚc)72I2/ŽĘ ALJL%(9NéŢŞ3P!‹O¬”˙ÎhÔ}Ż™râF©ýsĚZąî .G@ÝŹ\{*l*ôen´tt±˙žţ2$Ş×Ú©›ĐXß—\Á2Ň› f"˘Ž'"¶,Ăv;B‚°î¤Ă:9Żăĺ~{| ątS; ádqŁ@­‡„N6Ú Ę\€qž‚ż'đ1VĹMŚ^.)š±PTDeA˝1CélŠu{„Du°Föí„IC#ŰűČ eP°'Yq×ŇeÇş…aŕHWŮç1‰¦N–€A™fQŰEů T;ăč›wXp!pr\󧢩W’Zw4c–=1¸őI´ŘMĚŕz<Ű@«<´e[­µ°l´áEŠ€uuCŢ-@Ă,l·…_fyĺ”éŔŁĘ’™8ĹŚŢĹ‹VÎ(lJ,™ó•€ŰŢŹtF]eçIBIŕr#‡PT>OtŞŤ“ărŠB9F Jćëł´†ÎU˘%-ÂEž'č[‚GE‚‰±%¶+XŰsĄU 5Îpż¸Ń@bmA¤¶\{°ÎöňÔˇŃ/¦¨˛ĺ(e'f(¨JAGŘď5B˘< Őiť‚ĘÉ,%ňÍq¦«‘6]¦ĘÓAž+ ŘʞpÚr Rń$`%މBfÚé±ÎęD±C LŮj$ÜÚ¶+4lÁÂvë|ŽDm×űš´÷.‡8łřá3”„´ź Ř‰'[ËJµW"Ci'Zá;¨•|Rş‰y˙{¸)˛?p˝nĘ! HN§ähdiîÍ´2¤Ś9ü$¬ĘâRĆóÜ(×cŔ‘ď‡E[h ćRN0Ę}7)@>9Yp•|şąYĂ1“†QŚtŤ®¤ŁŢt®2•nő  Â3P¨¸QQg˛D-î–]Ň:°NÔ Ž…q€AˇwÉŽ) gŘ«k˙xÉßgŔkµ˘â Úz¶`a»…lĎŇÉD¨A+2 nš3ŽřÔÉTD‰=g´CÇÓť/¨,@)`´µý¨•ô8â>…ŇćT ťrŞ×wZ‚ź]Ţžľĺ(Čf’˘@űđŘľSţ_e #هJÄž˘T™#F‰łSŻ#ď珨:–íŔ6řˇ)ŃDeA©»RěNôŚCŘ?ŻXI±ţ„qÇl¬¸—śÎ°Ą ĺ&ɌآJ9(’$Ťvc¦wÉSČ" ¶Pä±ţ$·6 wßń®üŔ:ş9ń¦D}rĄ©‰Váę ¬UKţ[ řk)ÍŻľĎW hps]™ŃIĄh ¶[ëÓF`TŠPU ş2ŁiĚ‘•PĘą‰/Ěz üiXSąś_î»ßÇ=^“%ŠĆ‡Ą®ŞJYőČnĚ A‚ÔŠAsI‚©×»R‹^<Ă×ĘN„‰­E›Dµ+KDA(«ĺ;ŐHňt~ä Á2ŁŹëţFúÁ xéNlY weý#"‡ŕh{NśN –mYÁ,¸’…–âXA„ĺg§¬ŤŔ”°\A¤*0!ĄžD®I¨?!ÄÄ|MµßňşĎÓB&ÚţÝŹť5ŠŻŕ§qŚK[+«ŠčĽ®ľ]ö Á-DZa80Ł“[°°ÝZź) ”R Ăş1PWA)ÖÁĎ–·ţAśŰ_^blű?Ę3w‹^“f‹ €%ÇDfÖ@UÁ÷ ő aĎ%Eą}¸xZöhř §˝čQ¬$í‚mY$Šl쀞k®Kw$ôX&ĆщvQ’:k;îj]LťmąďQeî´`fg\¦cvŚ´Hő­~5k ZČÚw+p-))Ń8`–'řI[Á«ĐÎ~ÔŔ˘LOm=´˛A r`TČ_yďëY—uxĄt/›nkF&´}]É ÁË=*“)FÍá[°°ÝşźEW–€˝wXW>/ÝÜýĂë! Žë$ˇ+©b¤’‹rtY÷M€„ňzHQ¦KĹň„0jrÁÝk+¨¨2áŹEĘ1;'Ěâ$ (É’‰Űe„`Ejí59´b°ß/ĆŰb‰wżłŽţ”%>RÁkC‘Wˇ/ ˛L‰ň~ŐůÄL®rÉŤH$Ł-µŁ»Mt\d˘N´ëÓZ›ĆQ?‡ÇĘđO9ĐŞŤT>€ŕ Ŕ|X‹|Bâ©ůy‘ĄSĚř—k.ŹĂRl^…HÔMGŘ0ŁĄµ,żXéh•›ÔU3T iť5°C]Ź—Ľ7‘*š:©oŤ~ÖŞ×ífF{EˇNGFŽxKGŁŰÔkßź "}G2ÇŃË4¸ŁŞLÝ9e¶%ívdÖJŽĂ1›™ůt)QŰű,ŽĽÖőśíóL A…Ž| í*†IčĹ Čk68ŰëP˘`ݦFDŮč:Y™gEn~´ío€čěłvWś2 J'ä&)q,Mâ\Ç„H}HŠ_óę9tâ±±đÚ¤¬w|\ňĚÂňÚ˙Ź:ű@–^0”ŠŮ$˝ć8äFăEjĐLf?$KY—9hđ@AęşÂ VŢfv»m·ŤEńđ}Źmé«í<­ëy\ÇřĄ—1zέ}\ĚĆT´śeHř¸dô$ľELúl1üŞ› eĚČD& f°1÷*ŹnĽ4ě;=†¨Ů^.śłq]–ć5$JŃŚŚÖáőÚý]§¨n OĘÓâ¸Ůfµ”#ŃBYŁ &”'VÂH©ŽĘ,´!š0€Ę 踷˛te…Ä ë·Qs‹LŔF:™7UĄ0ŐcŚŇV?5őI-ŇSz¨« µßş,ąĚůŚŁ­q¤xS`rh=ŢyÝşŕóR¦čCŹú‡KłšŐ¬G!J©JUY\ÁĚJú7Ë>T •Ç€ ,sí&ëYLâŮÖJ1Ú…8ѧ9ź(ň>^y“¤Z@KYŔ  ŢáC 4¨Łm9DG´‹$ň}$ő†KŤżĘy·¨”.Í2‰˛`)Xś'ŁŃ)Žťő#wFš“ćŤůdđÉŤÍjVł9lÂĽ•"úÜn(Adšä¬ˇ§ÚsMTbľČ ÁAˇ ďpr‘My¦¤L5«ÄÄTř38÷EŃü§ŔŢAŇ7B*ű"e^4d™ Ŕ VĐ Ö”ËĹä ąś2 Męśş6r#|„¬j•3cĘî&Qő8Ą9rä\ł(S‘xšŹlÝŹC"UĎz¤ ’q$ hhVłšUń¬äygÝgpYCji4 3ÄA^˛ë®wöUÁŇ›Š.G2x×t.Äh/ĽDBdŔ—@ÜľQ†ąĺ9c)EŞŮ <‘ňĘŽ@80A8§ĐŮ2€ÁŠ™yŰíČy˛äü˛óśŚ›DŁ–Pg“.¤®%[Î¬Ý s4™˘ś˛šđĺÜ«äŐ±×8Žř˘’L}@W 8Ů É$¬éűýŚHźa°€Znßä44«YÍ* ä ˘śhIŚFé,Çj2¸Ă“ ÚtęC`[Űw…ü‘ ËJ='łˇ°—äx3 ѧ“Ń @D 6ĺ …H`Ga>K·LĘÔů9B'y҇PęęÎÉůaËB™Pá­]ëDĘaČ5$đaŠÂLµ¸OQőÓyEŇ„2éG¦ţ5WĐ2—GL€x ÚďgŔ+śÁŃă¶©’gvçşË hhVłš• )`XďS\l¦O‚‰D*Ú‰÷1çKćB`ˇÚTŃţîÝĚ˝S`<ł`3R<˝ż…é0 |0TćĎN_Á5MzDB"ËŹÇ™9dŔNBfĚŇ”*t8ôh3ěźR$Ę,Őa.ú9éΩŹđC§*\·Đ‘A ĺ2wŹB[…ś°łĚŠk%R Ą|żCĚÄ=źýŔżI:p2ő)ńŐp2 ˘ŚŇOHÁjŧm Zlúpčl@CłšŐ¬(8/fĺÄ„É>±!§ ŁŻ@´ŃĂ”’:´K·ÜhŁR(ĺâ]"!§čX©§€d[‚ °€ÁPqúQ%xr‰ď™bP‰ţ D"~ĘC["Ht‚±– ě^&!ć6 8”8ÉçDCĚ_Pň±ÁaÚţ«rŁ™µsDY=ۢHAµZd©„Ę· •Ĺj®Žáů/H¸BĚőZj€íś&–ŞŘ͸y·|—Ą‡ÝţT?ĘĽ'šŐ¬f­va. c>ű\@!×ío3Kň(»Zż˙QŮ/C‰ y&HşźRŇĚ'•ŮęöK ‡´ 'I ěĄjŤB¶ĐoSCxTŹŢŃš‚^CdČ™1›rű­-,!/km{ ś¤ô ŘË dĹÁź*p]řTŐo%¬ %ŽšĚââqSß Ě„jµ :-¨Űž®Nč»˙°śdŞ č\ţ˝|dq€„“źçĐIP#톻‘rr”÷Úi@CłšŐ¬®`A)µ0ä´©<,IÚ–Ň:¶l #‘éRٔ⌄@‘KáLOPşß äEp”˝ˇÓŔH?‰ýô©¶tŃŚe¤}†î&X6_Č1;VÁ–6´ŁÓ-żA˛” ÇČô(Ë”¤ÚQéd'Ę´-ʱ ł¨Ý-7Sš…sa˙M)(MVĚ2ą`™išpŽ’óEuŃ45ŤšćMÖ cF&šŚ‘‚XbËb`Ąšu%Üůô,•V¤,§SĹ}|ÝĐЬfýf|ŻŔ‚hxĚŤ°qxx:šÜö8ů`%˛P7¦Ż™łNÓĄĚRö’\‚i¬Č˘aěó\ká+I7›‡şvى։ŇüŞ”ú@PĚbH¦‚Ͱo’Ěű=¸–OŁih ďÇÁ’¦@â.™Řn @˘“ŔS8›ňšIEĘ0ÂÖRI™Ĺ±Ę&Ráf©;ĐNý2ŽűnĎ»r \E hDę™Đâ#´.n“kP ]@ş.0śß\ŐvĐNlLHŞ÷kłŐ€†f5ë˙(`Xř;ë2l*´•_¶ľdy}f%pe¬Ilëm”&סŻ@‰T‘3ZöŘÉĎ`©Rh©_Ë8Ŕbq\ĹçČő2Ž ·âĆűykB<>*‹Ľ<±Ř$šĂţş‘Lż]ćňĹĺ!‘r™=G”BŇgb€’!~bÄV™R“—ş˛ŔÁ ­5t§Ýn‡űk©·Yí™@›¬g:לäJö%6ŰĄä˝\ą%Îý„Ă}Iý˛ź8j@CłšŐ¬ °°`J™}«zxSjFÄ.€’Ď>SĂ\së(Â{ú6ô+$€@DŻČ(’‡żŚ™\c«MŔ… ÉľV§źŕ2z˙ďFĺĐ8O˛ ţÚ6A•‘&ô>™"µÚ&mß#_˝Úş IDAT˛Z®‡ÂK^slă­Ë•U Η…·’±w ŞQ8äĐ’pžÉËH!b 5XđŔşS/Éźă}ęűL@‚ńčE6‰«˙MÜËp¬”YTďhˇWÖNÍş ÍjVłş…Gś”;KŮ`)¦#k˙eݤ˚Ŕ’ĚÎąS˘hßÜ3~ X|9BÔÎ%ŤďšŇmqÜěĆŽnçô8]ĺBŰź¶Ŕ¤ EŤOČÚ Cłico Í‚iÍ‘DBQŃBŽË®KĹ1]´$ ˘ó]ČÂŮXsŚë<ŕRQi„#—KÖşX’˘^€zQ×°:”z1Ñ났]ŕ Ó [@µ‘ürűěĄÖS˙‘44«Y XX} }=µCÍ[6RHˇMVŞ‹Ł„%Ş?fŇÂ7"ŞŔ phÂ+=kÄÁhJt’r@‡ĽCĐ `×EgŹCÁ řŢoľeF ™µďĄ°Ţ”B1RŇÖů±ŔYąj° «ĺ„PśđI`JO†Ś8cle™MöĽĹN߸a®›2ŢÚ:I˙…(m°pÍ&Ýfěd0JĎ¤ąŽ ŞŁ$Ë9 L]#®nQľ„Ýš¶z"Rľ|ŽŰj@Cłšő( Ź–E5I`u¤ŕXţäýmä•ëy\BÉŃQű¬ÄF kbŔŤÝm%ť…µe Ľ*Ł€FkqD …ލÖŰAPö¬;@h€Â,ů˘•°XpÓ "ăM/Ue»7ßëŔ±‡C0˘ J–¬É™fͱ˘CÓ='á=C×ĘRÝ7mŕgDůÚu©ć۬f=zŔ(őďk],»kűJGÖÂ,?»ŕěšţěůÓşlËżXŚŮQŇŚ˛¤ŕÝ]CŻň×^§Á•,(f´Y@Ö@§cz5´†îhÓ ŘééNh”űňYOŹ(RF•Ńa‘"Żňč ©T|Jň=™”źDżBBd öl uŃČFe‡(”}ő;&Při°€  l â˘yYę „7LCłšő„YxÔZĐSůŹSýGę’öĄ®ť–ť÷Ł’~ü:*18`Ŕ‘J˘BZ©ŹšŢU(‚›żJŤ7· AJ4ЧĽ@¤e:vô’ ÓˇŰ(i,±áű8ž¤@ř **e‘ÍřÝHh4ŐÉi ~.›Ôš ;ŠI×ÚYuImą:ëh(MËkj8×=AÔ*či@Cłšőo=ŇKsV•ômät)ĹĚ]ś‹ą0˝`Ű HÔŇmť@ŰQG·ÁČÓÉO!¬AV¤É±˘:â7í},˝ˇe˝ŮÚh‰†EĹbäN›^ę´Ť§€mtÓ¶Q 1É"ţ ĽĘ")eUÉżß·ă±ěđĐH¤ˇćF ůž"Enś”Şăuťđçެ纔TRĺ8X‚HúHú©#ČžÔéµ ÍjÖŔ‚Řú°„4»đH?ç=?Ě-­î śUśfş1Mó°LOѤGBřHdß!ŘŠĆĹܰ›ýX 3µˇ#ť˙8†ă5ÁÚďłRa@Ś_úf;ŃôG!5·źˇëá@‚–ĺ°+pá üą#÷ją)O@™ńNŇěMµĽcfŇˡˇÄ´ŠťK)…fKsÂ(,›„•G0IŰO śmśÎ4lA7Űp-)iöěwűa›bĚ’ ŞsŰľÖ ľĽĐЬfŐ b ,,D˝…ővmrLK=\¶/Çá´”Ő…,_°ťLâ9%sř\”¦ĚĂßITłvś¸/˛q{ Í~lŰLĐ×RÁŃnŐL@Ph^¤Ü$AŘéČŤ“-¬ˇś4sđ}0ľ†ýŕŰICÚA5!ç1ÁbĘĹ iaa=Ăí9gÚ0+%Ć›‚Urže©M™žRg .T±9gf^’Ů—'ŕ$LFĚÜ1Ů9“ďi»-ćH„)Vµ kAá´;V …ž›44«YŹ®µú6F)ďóĺU^Š( j˝éQÚŃŘ!•„ˇ2ě—ô Äý’ŕî–ń ff«7ŔV’“ăŮwčąpŠŽR" © WÁçÁµX¨üI|*Ç N,9sˇ&e‚5Q Ż|ż„m‘W‡c?H `Őn:ĚÍU¨.l€Şř[Â4 Ď{ţµíɆęŢc<eEűţŢH#˛MÓ€†f5ëŃ Ö?X`¤ łÜ· tfBRĎ|\ĐńĄ ę”Ď" ýŕÁśy‚3Š}pV° Ž.űfĹ=†s€Ž¤©<` e™nż|H »č}Ňxŕ{*„€’ ř ±[§ĆBCő¬…ÓśđŚŰ÷»ńĎdş‚HT+âvQŃ #_‰X}šęĺí•ýUłT Ęî’ş ŻoĂ|}•hE”44«Yʰ°aKŇ~—ăi Z‰ „Ú€ÉţY{Ŕ}Xć4¦ýĎműi(¦b@ÔŃ54±Ťgξي4‰¦:ß+`_Ě!«g7~ɶܡEO#Ły;m»l-Ĺ•·đ&ßß»`‚gK)°8.»‡fhî„X¬5-zČëDxńgÁ0Š@P–Í ĄÂÔ‰»ďś5µNMžÂXŞ©ąPˇěˇHU‚I7qŔ'ű~ ˇ,›i“Ŕb˛,S~Ş˘'aÁ?ëęÄQQĹÍ}52ŇÍjÖ Ŕ†–~vňÉŽ'‘ ˛·ŇeY%^źŔˇŽ^#t±»ć;ß"@^š8 ˙B黪űqÂ'p¦2ÎÉă?Ś&ú–Fâ0Čŕέł(&#ᬔ‚˛ĺ)R ŠZ&ŘŰ7FŔŇĆeu 3‰Qł#ą2…¬»˛ŽĘ#±˝„˛Á޲°Z‘‘”°÷—˝{|Ó*‹¦Ëç`aB Í™‰Ř˝HŢ<ˇ Ń=piN˛„†ihVłq̆´¬ć¨u?Ô‚=u,„N G#Âe˱Nc,,í˛rm 9ţg ‹59rń˙ł´qđ$¶¤Ő E,`Ń/ŔÚVáI°nż5ĎĚłźL­Ý0,A»I[>ÄőX8jťÝČ…v:ÚĘ7÷P¶Ą/jEĆ9”IăŘ Ęă·¨×Đź÷–Đrpü “–Ý˙hŘŔÇZ› ZsŽDŤ8p (Ľ &ŘzWř~¦ŽHńm¦îu:VJ âÔ)ĺç T¶ż’cŘ5q ßjÄ€ý6D_DT^ˇ˘vSŇŁÁ°ÖŘĘ/Kß°ŇÉAł ÝdÎą&¨oT‘Q·čď;O%A hhVł&XX(ŇĎ~>Ţ>čµ{8ů^X?‚™ĐŔ‹ą}ä~!¨¸qŔBĚ—‰»`LÝŕ« ÍjÖ<­…âBéŔ€fŮÂgţÁ—lV­ŮfÂuJ¬uú$8–ĹŮ`ĎíÜP’™…€j·néwÓ (I‹:ż°µ¤"ÍP!nüŃ ]Ęý1ŕ@CÂr€ÄoJiaË˝hµoH”š„D`Î ąsIbşźĘΕôä¶ű+Ő÷ŘFG)Täm†ŇImź8/öe.Ě•»Ř)ˇ7A H˲sţ%ç @ j’a>ůŽAU#*ż´ hhVł4»°áŃ űÇHZ0đ 66Č]µü9ů#Už $Ë2săű*¤Ô2|`‚›ÁUFK7a  ĽČedĄÉĘ'ŔŔ‰ČU`<8sĐĹyQÝ'ë|iŘŚŘW:góěe2çË÷`P^)±(”‹Ä’˛p¦W±-µÜ 3ˢ )çˇAÚ•„ŘžčXą$„Ed˝şşÍ„9€0Ç€şpZzzJ.ÇiiŘ{HúOŞ4٤§¤/wY¤§z›É)].lb`Ž« ÍjÖzcË '$`ľ°–żĚÂ0§K“7KId˘ůaz9HRŃeEE"ŠF"Ł2‚JžÔ^€Éť7öÍ‚,Ç7+UąQF›c¶«˛ŃB‰řĆD™ß ˛ËDa?XWçÖe@G:aDZQ‚óďt˙ÚH„ń¸»ŻXě#Q°Ě¶€Ä”7T ú‹g%1wˇ  bŔ;Š$ůź/°0 m6 ˇYÍ `XHűPĆ| ^˘XŠ;1Łö4XŮá.Äó€ŠăňÖ]GÄÄÁNšÁ‘˝°2Ýá]á=S~BĂß'ˇ Bu,ť)|@ئ˛ Y‰H¨3fä±ĺŰTNÉ# R(żż5‚´E;F„jľuCÖĂ=>ŻěB˙¤ ÍjÖÁ‚+E$JK±;e(I°¬xkŰ 'F i=źÇţź…6°S’=w{'ĎO«ú IíÝ Eů¦Dz(%YwÄÉ˙né1G«H&|ż„3śâ˛2DÉi(tč'…Ś‚]A.ł ­,s#öŃżÇÖ(±0/ěUÔÚ™Á*ą?©Ŕ™Ě/ř¬ubç÷c74"i@CłšŐXŘٵÄžIHĘέ’ťŔŹg Ř7î…©rľ\Ôáy8—ý<ěś]±«•+ |×BUăĽÜFÄ={gíCžm†´…xB~.Č™fLň~N mě/üId{-¨hRIdJĘçÂŚĘěy “5ť()á“7¸Bč‘n“oĂk0Hf©b‹JŮy]“$šC’h{’`9 űL…ŮËJ_1]ýÇúŤ·ěiđ­9,řžl.0çç#ą hhVłć0lHéçčŕjȶCŹa#mm”˛–ĚN„'h5řny˙€©uNŞ×vĐל¶ěB îüQ*(áŐ+u×Ď)áů±"Äq0 Ű•FVđ~Á [[ąi[ŢĐĺ=Us.‹\D ĄAZĺNQĽ]«á šśţ‚‰’ ”’ŮÂiĘ×8ô/ř!Nü?|cޫބßĘ49”ó`ĄÎő¤u0)uJ]-Yo †Ś“XŻźM6 ˇYÍŞ±6x)‚CŠ Ç'ĄCĄ“'öFA¦łQ(;j UL'x7EŃC75_ňQVoŔ "aEQŞ$–efšëĘţI5÷‘ź(PT˙2Á3;ÚŹjR­ě´ű‡P2›iŔKË›Ry2)ŃŹĚfÜBä)”7’Ëęߨ#ă/xó+1'ŰĂ@=KŚo…ĺlŰ’ś‹ ©„gEojŠ=śĆ9fę9ž››Đsőüh Ě_©„éw’„˛Č¤ ÍjÖ …Ô¦z!° €)=đŠpé›ďYpR‚~ŹĽö‚Ë6•‹Š ÁeF)(čt!ŃDçlŢA—źú‡9ó%¶ý f˛Qj4$ţ$Í«Ň` ©űśFĐđWWö”˛±Ň`öjéÓźŁgy ^]ř2x{-fái‘AVTII2®äˇŁ¶Ąš” °UÎŹBö@h'»Ŕަ"uŰě6ÜÚ ç'[ŐŢIBîś „2ĐЬf=ňŠěZboé§}ĎA¨!Ű ’ĚŮ»‡9ن4ĺ<őëuc©”‡Čv}qp öJJ,Ý ť-”Ň«L ÄŃç‹ÇIĹ”Ć${Č×ř!¬·e ć$ŁvExfť>˙ôÍŁ˘ŃůBőZj Šľ R1A Ę ěÝ.K=zF˘ĆLbeŘ4r×ZîBÜgŇKĂAůXŞż×”t-ŐGP«¶±ˇ!*ůĐܧ¤ĐЬf-„ŕ';Z ŕ`Ý&-p)ɤ޸-O™Ş8«uy‡#H–$¨Úą Ě> DęHšë¶|ěá`×VŮHŽň8ö€QÝ"”…dX .jJUBúXŘ_{ĄM»y•ŘNąsĎqť"cDéĹ'Ă”bt=ŚN–t![Ü9Ó,÷— ŔłŐ%€–8^:Фş˛>e?›ë˝YW¸)člÖ  x¨ŤĐЬfÉ@•«Ĺo0eGçnčţ®u ť-ËŕÄ*ł#EŐJM0Ŕ-•Ä$ ,ĚHˇÖĹR=B8G¦AOÂ[@qd(zć(ö!Űxť ŤxdŃ•çmĎAę.“Đ6ÄëŃ˝ X4Ş(ÂĄ˛“pĘqNyr‰ęN„¦Á”ő ŕ8…t‚‚+ď Uy$ŃK¸’Tç űI9¬,XD ť»Lw}Ű@”^5:q§ÍĂűńń™Nlĺwr çI-Ĺ1]Î…çx~Öhp2łÍjÖÇÚBö8—éĘ{uľ§&\ĐŤúldćŕFĺ’cŹ›÷ ‚; p@q‰Ü Jé’}#° >FďAdâ\Íő)Ą˘óĺ7˙©1a~š¬r#‡úŚ‹Cš8ÚN>»µSÍdG>‡&FYÎ'{MXÔ€ŇĘPĺĚźÄö q€‰ęH‚ÁŕÄfJö´řńXĹ'˛ŤIeÓ|[I’Ő±TEFÝDm"Ér:¤ťŐ¸0îâuG6^ öľqűŞLEéřŘŮd±ĄŚÜ}¤”­ĘŘŠ3+S>ăĄacžĚî3•@‚f.–îÎo„F ŚÝ7â«•śę1ń9µQpHY,sľZÜZŘ aAJĚ6«Y÷ę| 8±Y*‚‡řˇě˛.*ÔM“~ňHžX–/¸ôwYşEfşą‰ęeOs9GőĎoEç?'ćN˘e€´Hď©<«‹¬¦HtuH…E«śÉ6Ű”¦UÜů H±ŚžQŃ':~ŠË1öb?ťA–U“µç‚ěs1‘OMĄ(™`O9×8hŠ;ŕđ?fQz° I0 §@[–x É^PQ•’ŘÜ%[P.Ą…2B!_­)—r܉{>řńQö–hÝá‚În=†ś\ŐŻ‹ŕĘ=JŚ×Z F“Q ŐĐáÜYŁŻ9@Ĺ®÷”%­÷~ęí˘Ţomîaű)©•˛Ĺ}Nw¦Đ%:řďQź_é44«Yë1xZŐI™Ľł_f_w$˛ÝřĺfY5şřgŐ˝ ů‰ŇnO*0ónÝíYh…Ü~(ŽĽ,CFjźÉ®‚ڤ@+éÂ…´ť54YĘźŠYTÜC·zZńŽvĹŤî.f0÷ «Xs²=Ô8ÍÎčűĂ,„•m>$AŽëPťˇş `X#`ůÓšöä„ŢW’Ă\ť%©Ü°l.Ł&’‰tĘĂď©údśBű>ű*ő‰IĐЬf­OŔŕĆď(čőł|(3ywĸ<5+gŞH˛óź*:Ô%°4ďú«6–0$…Ř`)r›Á“Jb©E”śŃŕ!&č„ͰŮułeĺÜóX)úĽ(W©&Żh$t0ŠŤ—‰˝´”8 R Ef¬–Čło”L!]bJ°!%e ˛Q6ú¦ÔZăz<§Ô62Ĺ,ŚĹ¦tMî¦HĽĄiplÉź‚xD%€jEË~G@7ěRÍĽYÍZż€Ác-Ś~XÇłk,3ŕŠě?W^ vŐçbđç`M“aÖ§BC·ŚĚ‰î”;H’­Ů+2–J ŮbáIńŚJĺŚX‚XšYŞg9Ó( LýTÁÓAú0‘‰rîLł(‘{)ă°©,`€ÍÎ-hPĘzu”˛`(´+ú? EÇ g@FŚ=űŰ(Z÷’Ńśľ'ĺ”zĽgć>ĘËčŽQŞ÷mŽÇ^j ŢďÓGr^ý}¦ˇYÍZŹ€Á÷7j÷sađă3KŠEó2ˇ\i!ü¬FݸFCÁŠűy –ś™9–6Ş\¨‹÷‘—Y"%ĆSß ¦(ѰŠ.-—$,şÉ[B;ĺ=ďĽÜ)»=2üżąhJd …FˇéKpűŞčŔ ­ « đłL Ç)}čłjšŕ:ąl@G"NČ8óŇĐ ŰÓo,î1§§‚Ŕ™BVükŢAň€P‰ŇZŇÔ hhVłć/Z×~yµ[“4q±Ž.ľíp–âźu×h¨“ťÍw ˘.X¨ËmP ľěG!EüTT(÷Ęţůw¶&LqR-ëÝiůX"Ščˇ )›c`Č™"G‰`ó)? © ”$Ů{G°Đav*žÉ ůű‰‰™µŞ ¨î5Ě{NPîŽŕ^2÷2ÜĆARŕU¨OşŐç$B>¸”$Ť–Ô‹Ń€†f5kŢđŕ h~ÖěÇíŇL¶( T*+I kXXkdë4 ŕyÍçňŰ–Ú·ŃM řéM߯ Ä’Üßeĺ}”uz2ř{ý‰ †äËĚ‘‰ľ#Ť‚ô"…}ó“#,šk3٤»ßČ7Ž"€NŁŃ_ňŘ şL!*­ES J•DL×űŃ×ŕaN}S˛ „Ŕµä†ň‡Ds»ďzż‡S[ŮA0ý—ĐЬfÍÁľŔŔIsť˙BGĐb–SŻ,Qţ©fş#µPO:*ôâç¤wťL§(Îb ~ +ý«+ć¬ÂYh+Ż4©ü(#qĽ3šE ·bHAeRqčŮŕXä :ekÍErŕŔýÜW°‰jŰź!ś<ćE‰3YŮ5 Š`X3°eőŻ{…„ĺlŐ¦Br`|ý=T ć3¨–wšŐ¬ ¶\pőŤ„:¨×9Wk'ŞS|ÎĘČťoLśKYB©ęl]aŢ™†^¶ĎˇÔ¬ťëQ»""Ö‡tđ÷Hä’‘€=3}i: {K¶Ó ąđ"Ť¬XŃ$gPČ ;jŖܨ.Ľż†›ŕBPži€S®4ď%fh7ů@ARÚ¸e F,hk[5jJFx p,9ąŘ*şÍ IDATI€­™(ęT>˘› °,„°óxďű^&.ë9šëQţ|ÎńXĐЬf üËŚťü”tĘ÷Ů*ĹĎD›Šő6)‚ * Ň×Úţ†G_5ŚUTŠj± ąäm¦‰ u×Řh€žNE |!' tÍš«Ł“Ěží"ĹeŠ»*‰Ę"…Y½Âia@8TŤŠ2 ,8ńĺŽJ§z7ŚŻ6”nB°dţ¬|s¨ŞÝ6Q„‚óaf…Äź»ßƆ¸ů¸;ñaWšŐ¬ytf„R(<Ú€Ä:™HŢ–té—“ hčUő±ľćĂ=˝y‡eÉ>ä´Ţ›T±§~ČŮ+r`ü|˘Ëć]Ť˝51ŰńƤwˇfĂ=9ŤJ3cXřčít<|w…ńkşCŢ'’ó Şř˘.»ŔŔ,Ů—ąÝúň‹B¶"ţ¬Xʲé0˝Ş¦VťC5żÔĆ€OCšŐ¬yxž¸2¸śqç¤&M‘˛_  Ş‹pQő±ü“Żgö^–XŕÁO&Ĺ>š‘†ËP2bI˛fď%ď˛nÄĆW~Ä‘Üóă•EAvV$Ć59~˘űRH”q&”:…Îwo˙MAŐŇŤ‹†ýÓ„QRaŐ-łr€Á™q™c=N(›„íx&'. ţUAQĘ”d“ëŞ]hkw…isŤşaçň=eŕ@ŐČć1č ŕ57ůď44«YÇ Bf7XZłŔR4¶ç‚MČ,Ąć·çŐx(wݬË0,@e:źčY#f µŠčÉŢŘ@çłě Ĺŕz|óľ]Đb‚ \<§łQ ¦EöÍ‹ö$łŇе“2 űÄĹ*Ş Qn¬Ň^GvŞ‘2 É㵿¨Ă`M:Čła±',‚ ;ýݍY˘zHE)î®÷G®˛PÔő őôÝN®“(ů•ňz §ôÇpřÎ^Hű­44«Yýţą‰ ±m~”ŻN–Ck¶łč.#-ŁĎ_ý.o¦Şgv•{Ď|Y„×9çTő %Ž•tvôď FS$ť™YÇ* ÚĹX‘«Ŕ ÎP8SAżAłöٸÚdŃé˙Kqc+Xd±4µ’AđŽ›$ Žĺ0o‚b!/ DźµµÖ¶¦ŽaQć Yp| T¦q‘ÉÜÝ…;:ë;‘‰Ź~äUŚyrĐ%ŞŔd’¦şĺ»ßŻ‚ĺ±9×Ýü#`zbľ8ÍjÖ ďKŽFÝęß·Z̶3k_šb f™$…*™‡4}Ą0„V/)*9r´m)ôS"Z›ăr˙Ä÷;˛oćĐýŻY¶FłqXtçÖ5ö˛Ć‰€sŇp?Q˝*§EZľKJGűä\#®ěs~hŔŮj“đ‚°M‹Žđ×C8r¦–Ř.ĐSćáî‚7» ęjV›YÜoŤt{üZ _ Q†ŃѡrŽűÄ„ř|9€äm<Ĺą"ˇ:S*˘ń’ě” ‘Üą;W-Ó«á«Eá˙ĂçżY ¶Xž<ńĹâÁl>ţ~G÷BŻČ&żýPŽ“łÂ˝]‡6ÔąYÍZh`aî¬{@6Íä;ě!ęÜ2Ná,¨\nĚ>Dzu’n»Íň!B”0 ¨±;ÓíýéĎâŔ™ĎľëćxŃ3ź}Ł#Sâ©‹DĐő H°ĺÍČç˙ŕ›IŘtŔăů(¸“ ť…8í¦=”qجĘxePu>î„j+SĘ”ň:Ž ‹gŕ(¨ĐašŐ^ôĺ’bg(—NěpXPĘ»$HKLżđśÓ÷Ľ gK&,€{˙4FÚ¬;ĐŽŚDˇPHšŐ¬° Ň™íS2z€‰-I`ëóƉ„‹bJ ‹Y}U>˛Už¦Ą‡b9bCŚ^Ög墽śčô„7| #aQmŮ ĹâüxőŁ•Tä.. EÍNa'Á•Bď•9FhWdŔě'0ügŠCÓÄŔ˛a`Ů6‹Ă aV‚˘ŔÇN –EpǦ¨° ÉŘ&ůby}ýD’ŰFr(BŤuĺ$äsJśžĹq€łö­(ś(2çžDÓ©hĘízkU§„*r7ťŰ—˝ ÍjV&Q ŔŕpËŕ¸âTŔ‰(glÖî;˛@Ž*ËQ¦ĂňaŹŘT˝l='ô´°u¨${ ±•sy%÷śQŔrÎŔHAkŰ)ÉMż8ý ¶ě‘Q04řÎŤDJ3«ĐŔhŔ ť@*WIVC*&FÁBrvÓcô=ÚS&Ó Á¤DŹe=$ńÚŔ“ĐŚ(D4„B´Śb>±»dI/šôHüâý*%µ—˙ć,¨Ghq!‰đ–R˝)ęn[AEXRä;Ř:®*„q`öRäőpŮżPP(u I##ݬf –i¨ĚtOłÝ÷R&˙ «2ơÄzYvŚÇ¤v}â$YCE6š†X”&Ö»_đBO„BĹ%XŚ‹y@źEsa9(F©™`Ô=ĆĹÉ Ę‰$F*eRHÄCŽ]R •ĘN ŤK3whkFaŻ©ëyŤ¶€iv„ZÄőřYěcrąťQInRzľ’¬·Ŕ2H@ŔBĽ=bŤDٞxOEŞŤr_”L Í–Tć÷ÂŹ‰dn—\ײť­!ŔQÜ[č1Iđ˘é­I$ę© ÍjÖúg$<ËiűŔŐÚšqEÂ~‘DH_mDžŞŰ •vE­3-¬tňłšiČŠ’ÝN¤Č$ďb^Őů( ÎDą`HÓé: ĚnÜŇ–Ť„ąyµ m›"…±„ŻEµ#)Q?‰¸^Ú" OS“ď— R9$ĆY6tş±ĘPnb& ‡Ë8Ułf傜R r+|^6BKG EŞkëbą‰V‡ČÜ÷“6Čýě€A±Ź‰úŢjąUyšŐ¬ő´Lf¦9N1CŮ ”j>e.ů‡&7čTIPĎ‹·äRhŽžáZ“‡ÓŢiŃŤ–>ڬŃ­Oj"Ň ˛Ý˛)@ŚH:Ş=şf:rŮ ęG`)ŚšX›8A$µkޤ'D­s’ęĂÉ[«hăqW=YŮÄ™Łŕ{ÜÝČŻsVe9f<4ś Uťve$ç/DáăúBŞJ˛Zć÷•¸}¬Še;I*p khqŤ,€Ô˝d˙F?¦čŮ›léL eŻ#žˇTĂů„I†a®čśüw]3%“»,ľç hhVłć}ło4JV‹ÁŁç *ŕ ˛ą‹RA(GŮć4˘˘‘súŠF‰Ţ%J>㵑u4gr:(+3“6Đz‚ăýÔéłźmWľUĺT&xÉžË@lé’ŔQ|<đ˝Ńč-’Ä:źăGĹ*Fyż?“´óć`ÁÎlőB DزýZ%J'PTńsť¸V2i˘2®`”S’®°a¨REÍ˝•Ĺ$H¸é)6Úë¤ _x@Šj9MF”×Ć’ťJxęU†şę¨HYŮ‹ő44«Yë'jůüŔ>CMśňcá%¬pH¤BfT“ŘóÔ›ÇÂۤ¤†Ěfc(ˇunÄ’üdE`bŔ`Žwž۸:gĘA-J& Ę‹Ţ,S[9Ťm®>*«ŕ§ş °“MđÔWŁ{jˇ®†Ëyâ]LňëäMÓ<0gĐ1,ĘŻ{Ň+LÚćMĆP)ĂĹČó*{m¸tĎĄűs*ňlunÁ”<ň­™ľyÔť +ئ© ęZd€`˙( "ăźë9|ąT`8ř“4 ˇYÍZ/4ŚČA (âś52#(”Ď)›ORB[’Ď9•*ö&}‰T±Ű%ĄŞ ­Šŕˇft©ő<ěµY3(aó ¬.‚ë~·Ł¬ˇÜ̬$»J6Öˇ”ˇˇE{ôl#ĽĚ‰<8ĘI 9QAĘő[TQpWfQĆ0Ťąr2!8b¸úB —Äm$”¤,{!ÇAs7BrÓ ŚLS.uńą,ÁŚ˝ ”ăäaQů>őňÉ3ŹĘ;cnhĽßjbšUňÜáÔŞç˛ŮŔšőh űĺtćt,Ň ť ű2 ' č‚•u9T˛ëźČkřKż5hzŰU:} \Ô—ĂăAgČp7chVŔD%‡Č‹@X7Gt÷îůäĘR’®'V#š Ó®ĐÔŻ')ů‰1Cw^´÷|Ó ľsŢ]ĂŘë Ęš˝˛'GWÁ˛‚T{ÖńŘhdl†Ľ\Ă'#Häb¶í¦zŚ«ĄC‹Ę“RuTą|4ęG4¬‰eX”0Ř0‘Jš1=ˇîA±äŻ2i/ΕDž#Jč'¦’µ¤˛!,4—ŮGh`fhf´ďĘĚhµZ€N§Sp¤ŔŚÖşđŢŞĺ~ż—ý”Űíöţ:űáL„ĘŽOkŤu““śš.Ń" µFFF02<ڎ’ĎÓZăáuë0=3[şťVKatxŘlgh¨Öů "t:LLMá¶»îĆŻo¸wŢs/6^ĽŰm˝ Źß}7,ÇČđp×k±vbSÓ3¦ÚěŰČđ0†‡†0l÷­ ¸ 73ۆR~ßq¬E>jíNťNĂCCP–öuTf­3ż?=3µřőŤ7á–;îÂCk×b‹ĺ˱ďc÷Ŕ–+–cŃŘď 'ˇĹO¦gŰŔl§S´ĚÚŢÓ$ĺ024ŚEccA¬ŃŔž™ĹÚ‰uřÍŤ7á–;ď½<€Ť/Ć;î€=vÜ‹ĆÇě}Q­aáÁPbhE‘•cEe-&|?kT0Ă”sm,M±kĄ˘ z¤' … X8™úă„-™sФ¨‡@6Ą9:;bptPžäDÇŔĂ#rú ý2Lń1I`‡Ä[ů`˘0IÄ~Ę3j‚ô;ˇ­Ô´»ýČßĚ”‘°Ž‘@$3)ŰĹŞ©ň÷z ”uoťąF÷č&ĂÜ„ÄxÉ(iÔÚ«7v÷ą’Ń{ ľ([öĄ, 0©µ^3ߦUĚŚµ““xĺűÎĹß}şÄJ)<éUǢÝéŕęK>\Đ. żű˛OăĂ_ýöÚi|íĚw˘ŐRPJáČÓߍź\űŰÂç-Ų%c‡•[áŕÇďŤW>űYµł/ĄŽ~÷YřŢ/ŻĆO8˙đ”*ÂJ)řÚ7â–»ďÉîÇÖ›ŻŔÓöŮ Ç=˙ąŘhŃxvłłłxĺŰOĂôĚL633:ZŁÝéŕń»íŠ×ľčH,Ýxă‚ZßÔô4žwě›°dŁĹĄ@†™Ńét°z«-ńć—Ť-–/Żü]abj˙ţłźăăź˙"6ŰtSř¶·addŘRĂńÔC»ÓĆ=÷?€w}äc¸ăž{°˙^ŹĂ®Źy FGFpÇ_ďÁĎ}-ţz˙xăK˙ űď˝'ĆGF}×"ŰiŤ?Ýv;N»đbLD<îč~săMŘk—]Đj)-Á¬ńţ·ľ[-_îŠfĆ}<„w~čC¸ĺŽ;ń„=vÇö«WcłeK±fíZüú†›đ›oÄa>/îs06:⯱ü>ĺ\/ł÷µť1$q®ĺą×w:´ŰmĚĚ´1Ű™A§­­RŁ)eű@”Mn…1”ďżpÓÖ)Q˛p‚7N˙BE¶Ů@ÜnęÝKµőŤ`*2ÄѨś Ţí2śęś‚}Ó+ˇDbÇěűÜ5UĘ0d%k ­Űčhăęč Ăh…{\ů‘I‚MĚoĆőZ:Rűłâ4λV0Ëž` › Č6çąkޤւűʞ]*̡h­ŃžťĹĚô4f§§Í÷š; 'çń…P4[W8y‚EŁp H ĹÂPu±.ů÷*໣4l9ÎK(ěąóN»Ů8= `FĽÚfí‡wě‹čGÓŕĂţŻ~¶Ţbóâ)gmm‹óü±ç]„Ďţŕ?pŘľOŔgĽťN'úťv§=wxLáůŔÚµřÎĎ˙?¸úW8ă’Oâ§śg‹ĆƲŚÖ“SÓž™)D?¤$ÎłłmLNMˇÍ#ˇv§k®˙N8ű\śńú×bż=k…V¤/ţűgă‡Âi}żľásÄ ě>«ăm·j%>ńžwŠşµy ­]77Ľó=řŕioÇâń±€Đ(‚Ćš‡ĆKO~+Ž}ń?á ýž€ń±Q(jů¶şçvÖMNâcźű<Îú×OŕäW˝ŁCĂĹ’R¦ś4/+âŻŮJďRđ…ôłÔş<‰……Ę{L¸bˇq`»ôYi8F '^ŕË5łzĐ˙~ĺ_^˘„’·‘G[ĆĘ7ćqÔŞfŤŽf°fŻ1AĐfäNLv8ňÝR “ˇ€°18€Š‚ÝGíí­eÍśmp"!ÎD^`ŠéţÍ ů;É5IËP룜 e93ţ ©Ű¦˙*"ł9Δ^ŞBŻŤˇ]xçcčŃžÄţÇĽk''{.yú»ńý˙ą/:ôé¸đřcŃÉPük''qŐyď+ ćçîKxď§ŻŔ‘˙ňśűúcđňżűŰJđ©«ľ‡ˇˇ!¬^±?ľö:ÜűŕCŘtÉĆ]÷y“Ĺ‹K÷ă˛+ż/ţ^xú»póç?]dTě3:<‚ŃŃŃŇĎX4>Žçz–.Y‚wäŁx˙I'btd¤@ÓŤ'?O¶1¤t§+ľu%ţßÓơ쏱Ńřš¶@PĂ › µđÚ‰ăß{6n¸ůĎŘsç…8÷’.7ů~Ż-ŕ_šů˘ę†Oe9Rôµ~Ž =ýŢ7}ŕNíaݶÖÎs@´śŞ¸ęN’µ°ü3‰ŇCZˇŹ ElHZbŁBŰkP®ÔţüéÜš>'‚üK(06MgׇKoß“ĺJˇôËt¨ÔîśÂř'ůżJŤÎKTÂ9sôý!U«őoWdz‚¶FĚ»«9Ĺë@úqŕD}”ÖOŻÖóňZłnö?ćX<¸vm!ç·üůaÇź„ďýňjśpÄ?âÂăŹE»Ý¶ôžxŻĐůh·Ű…—Öo>ňůřĚi§€ĽůĹŐ7ÜTşżJ)\ň­ď`th>ń8 µZ¸ô[ß1_ř’÷"¬t?^vřßâoö|žÄO~s]ô~ٸĆŕčsŻáˇ!p.8ĺd¬Ţb ´Z-h6MqZŰĹ0źĄĹă‹đ¶×Ľ—őxxÝtÇ”Dä5d­MViËî'{Í™łíYüřękđ‡<#ĂĂŮóĺ2ÖĹăă8ćŕŠo^‰Ůvr ł×ď­ěÁń÷¦Ó’wS/¬®ŤÖćĹöZmk†=?ćł µ˙ýpî‚~fmŻŰĎpíĎ C™ ׫ ÝO¦Ě˘(;‘Żß‚|LřŻ®Ě†şŇ0l†¶÷2ĄJN®W=›*ďQśś\{{n´6źăĎ—¶eîmÍâ=ţî9˙âäţeqç&‚ťÜşFA8Ĺqç ěţQ˘É糧ßݰZł§Ď4šj÷ť;/ä÷·î‹Ůô0Á'Ü˝Xîq»áXí>’“uâpţń"§Ő ýů™ëĚĺz3Ău@zŔš‰ ě˙šăpďCkđžW˝"꼭2ši·ńä׼×Üř{śóşWăm/ý'ß$™~F„¨KöĄŁ5žń¤ýđę˙÷wÁŰ>ö Yz=ÝŢM·ÜŠoąĎ?ř©xü.;cŁEă¸ôŰWAµZ•ÇéÜ>t:Řw·ťŃR ·ýőŻ…÷§RŻÝÎíe¦gf+łČnŰi µ@Š0Űn~zf|ňÓxÇk_ŤĹăă‘QTéöZ-ě»ÇîšžÂmwßÝŐ\Şô|ÚµńâĹxăK_‚‹?sÚíNôľl2 \cCžäYH,2|e(t&üú¦›°|éRě¶ĂľĽâ§ěĂQ뎢Ýxńb<í‰űâ'×üŻhč“ÇoFCDY§Ë˛óŔ6ŕ´TěSPü}łí¶ŢwÝ{oá~ěő;.™…ääŃ>\Â7BĽĹ„??a‚ÄďGüаśbůo }žX·˝Šl­ť”˘ĐoA "„Tµř˘ČuŠSßÇńŰqÂë} ĚO˘^äÉkq˙0‡ę9“T°ö%˛ĺ-^®!5'GM€p€Ě×("ßW‘ls,Mň79ýéw\y@GĐŐ|•=SÜuŠĆBçô"QމçE/Ł;¨ňb˝†A3k&&pŔ1ÇᾇÖŕ´—żŻüűgˇ­u×ňĐÚuŘďź_Ź?Ţq>ůŽ“ńŠg˙mÔĂ0×Őn·qâQ/ŔÄÔ4~öŰpĎý~§Ą.˝ň*Ó`yČÁ`­qÄÁOĂ=<_\˙».Ť”Ő¨°Őjá·7˙ťŽĆŞÍ6HŻŁ;}צuGcrj JQŚl™±fí:ĚÎÎbĺŠÍkşJš566ŠŁźű|úkß@§Łűű(…˝vÝľíΨoˇśD$!–âdŘ‹™ŮY\öŐŻăľ㣣öt8e_Ĺ9íaĄđ‚g†U›ŻŹHíł-Ž‚woJő-Ą°ĹfËńűżÜb3˙bSŁ|8/ÇŧľÝ4Xöůî·§}ł‡,Ű˝ “‘Ő´V\žÜ›ěŘtIqhę“ ‚Č”ŠL#e<A$K-éKű{‰s*‚Dî[Zr-ľź‚}Ă#łÜ bB4ńpšLXPˇ‰=Ć(n["­íËx®Č‘™˘ŃSWw`GŰZŐJh1Š@´Dß©T›¤Žg'őŹ>„T"Ü4řAČäţ`_PÚAŇĎ–q ™±fÝö?ć8Ü·f ŢůĘŁqÜóź[«rô×ŔľŻz=î[łß:ű=8|˙'ötäĂfů&›`‡U[a|t˙ůëßʔ¿}÷Xşx1ž´ÇnčhŤŁ=`ŕ˛+ż[:ć"ňV«UxťýoźĂ÷~y ¶Ţ|ž˛×ăú~OLNbbr ăýu¶uď ÓŃf;×pyÝuxü»ęču÷ăwß×ß|3fŰł}_»±‘¨a–Pęźčs0$;*ć.ÓłłxpÍě°őę$‘í–Rp^×Íá»Ű·[µű첫ą,íjřť˘_ČĽ{ą>C­^{ä8ő‚‹pë]wcfvÖgýŸNÂ’Ť7*LŐl°ç¬gG8­¤_ bNÎ18Ę39¶ëß|yíőUŢ„ĐŰ5;Ă,hŁ™ ďý ‹/Ďj¨ę„Vö`@›r‚/M‰2‹+•Ů’ sE`“㚥|ÂT‰ß‚/OZ†ILXpDZßÁ %;mµ˝µu-9äĽ IDATĘ,„+KuÂt®‚ú»±dCcn@‚}#G@•ň ¨ű—!~yÖł(7×őj„df<´nxÍqXłvçűý¬gÔzďäô4žřŞc˙yŃyŘqőĘěDEżkĎ;ď»7ß~g¬íĹŚo˙ôžťĹKţöP÷Î;bŲMđĹţźp\ĺýđŕşu8ä¸ý~>Ľ·ŢsĆGGńě'? źpÚívyÖ^ă×NLŕĽK?‰çv(ĆćlCÖCŻĹ›Ď:Çý’Âv´Ö¸ö¦ßcŻ]vé9‘ß^{,Q«ŐÂňM–âľđÓ"u“/ÎTăK8==Ťáˇ!Ó@J5Ň]ůA#PŘRňÁ9 öx̶·[µď=áM8ćô3đ¸ťvÂQ÷,lżőjŚŤŽadx-Ąb! ¬g“Ş.ĎYŞĚŘX¨'v{`ÚňÝţ®#4ㆠĺč"‡´Üšš%€NLꂜÓ(R Ş(wS $í® ‘ě‹ (BÓŁŞ8úŚ łă¤|b×б5njŤsĄß;ÇĚ"}ڤ\Umá21:»ß*?'1oKä•:UUľXŞâK2Ŕ#yÄ€ö?ć8LNOch¨…7^p1Ž=ď"{G™qß`‹Í6ťÓąn)BKµŔňe›ŕŻ÷?€]wŕJ‚ź ®»őî!¶ŔuŁĹ‹ˇJ¨ýî#X!°µAň/uyŠ—e ĂCCxÂc‹Ďťw.~ő»ëqů׾Ž;ď1}1{ď¶+žů”±Ă6[c|tÔk|” 7­Ç%§b…ĆdT‘ŞĘ˛ż ÉđtAňa×eţEKWš Î)„2´ ±"&Ë*DSťĐ÷˝$Ĺ›\€ŐvZٍd%§J€jŹ<ĎźÓ ďc©)9MźŢ˛oU:Pî_Ňľę5ű®Ë*¸s¬bcĎZ°u@u ß©Ë1S@˝|—ŁĽ>Ôľ1 ˇŐRxĎĺźÁÓż7”RřĘŹ~ŚEŁŁxâî»â«ď}g×GďV›nŠÇ¬Ú ßţŮ/đšs>€ŹĽĺMó(÷„¶Ůű÷~q5V­XŽÇíđßGˇm‰âź˙.»ň*yčÁĄ=›.Ůżąüă…źwÚ|˙ękđşs/ÄW~ôcüęÁ’Ĺ‹bMfÉĎ:#ĂC…śHax¨…ĺË–á„—Ť·ÝĆÖÝÓ€Ŕx`ÍćŮY@Ńn·që]warjŻ|ţópč“ŔčČHö<·¨Ő_yh€LQ§Łmc"ŐzTpÝ›b ÔRTýÍ/Ä7ö:…Ú5 &™­éąëľß¦ó;4‹ÉS¨”Â’Ťă©űî‹'ďł7fŰm¬›ŔŻo¸ _üÎUřă­·bĺć›ăř—˝[,_ľž9ůáŕ&ޤ>·dŕťÔv™YXE$ä» ( ˘9ňŤÎrÚ}÷‚EtŕľIąaČŘO$±XľŰ Gy_ 7ŞÄčźśţĹÜłLV”5h Ć—’-€Ź´Şôţ ľuŘ#Y*É×j|»‘Klʉz ,˘űŹ`ŠN¨ľ’ę*BVQX©@A=şAÖŚóŽ{-ŕŢz*ößc7|ůĚ3Đn·…Ęaţkf|á]§á°7ť„Żţč'Ćozý@)…űÖ<ěĽ,\ţťďaltGzp4 JDŘiëŐŘ~ĺVřŮőżĂ]÷݇‰(‘{h¸ě®*8dß}pÉ)'â§ľ'|đøěí'GżG0şď;ńxl¶lÓl@qÂ?Cv’#źA–m˛˝ămXbăŰŘ(KÎĚĚŕ?ý^ń¶wŕ’÷ľÇ30.3m)…Í6]Š»ď»onAŢÖ|‡jČ|w˝·ń×űďÇV+6«őH•.’…lł ™ň×Ĺă㜎GÓ¨”sž´,Đ_î¸Ű­ÜŇLÚp:Ó^ťîÄÂ;aĆÜuoKü52d$ŔŤŤá°ŔÁOÚ“33řĺµ×áČŢ‚źv*vŮ~Ű ÷0H<&HąQđýňL˘C/ÎÚ’ËE9â€Ó©KÝ+«ŐAŢ–"šŰ “®çDÇAŹ8a8äg‹ő0đťŔf7µĐŽď)é¨ ŞŐAŽ `ŇăTCr”AŘŔSƲťĹu */”vbGLŰś©¨j.ţwÎ|Č=óęŢsŚŘW}÷LÄŹ Şů*ĎJj1Gý—(Qĺ 0ă™o>żůăÍ8đq{ŕ‹ď>Ý„ÝzÇż{ţY8ř oĆgđĆ9Żő@Ă57ţíNŰŻÜĘÝ–Őb`fÜżćaĽ˙Š/$›°ĺ¦Ëp×}÷ăŇ+ż‹“_ô®2ZÚg/,Y´_˙ńĎJ2M¢ńńR©éč\ŁzĚr|| ‹µÁh‹ṇŠ©é|ę«_Ă^üObÄĐlwźÝvÇŹţçj~ĐS{ ţĚś9uĂ>W»ÝĆ˝<ĄK–dżjĘn90)ßĎATTSÁş©IĚ´ŰŤ÷ÂŁ=ź{<<1‰S/Ľ—ťů.(+E¨ ËěŁÎ¸\®›śÄĚě,–-Y#Käp]><<Śááa´ßľřč§áíç_OľďLËXÍ1҉EWJ ňÉ/ ÇGßs•1Rá'9c ńXjK¸ q„Ŷ,g±–Ů f8 ~”T{‘Z]Ç-—EfQw–&nZ ŐEŠšHťC‘¦sĐ8óM’FřĄŻáiÇž€ďüü—µĎ[§ÓÁ.8;®^‰O~ç»8őă—v›oş ťN­V —]yĆGFpÄÓÂ?˙ýáŮőˇˇ!ü†7㾇Ö࿯ý-ž¸Ű.IOB˝µvr ĆřČČżf`6*VA1ý÷Ĺ‹aŮ’%¸ů–ŰđŘťwě:Eá2Ó‰ÉI|ćßÄď8ĄďŃżé™Y|äsźÇĎz¦u~ŚWKµđ¸ťwĆŻ~÷;¬Ţr +Ú#r%‘ąëú»?ŢŚ¶Ů&xcئ¶áá!ĽěąĎÁG?÷yĽ÷„ăĹDIęĚ‚I¦ffpŮWżŽ“˙ůjµl—PÔî-éŤçlr °bÓMqËťwˇÝvĄžę‡ĘP«…ĹcchwÚ '©€dČ-ă ¬‘SůÔě äaĚ%G•܇EMÁĺŇů.@ŠŹ±uż´ó^’ěôŮQLqýŮ™c!Vc…µíÂDCę3¨b–,G%˝Ń“M)‘P–ĆSŚNIÄMM,Ř‹”ŰOŘ& ź”ö ¨ôŕâ&W"æ)ë!˘u#Č\…D/‘Řż`N‘ÇX¬ÓŇ…Ą()4Č4˘n×uÁÔéźŐL|ěäđűĎ^Ž^t.ŽýÇçŕ‡?_|×i¸ëë_ŔS÷Ţł'$ćĆÇţëâó±zĹ |ŕ _ĆąW|ˇÚ~ş¤éΆ .ĆĎŻż“Ó38űµ¦äá>ëŠď˙ÖMMáÄŁ^ť·^Ť]·Ý¦đÚyő*Ľüđgbdx—]yU¶É°[@˝őî{đ‹ëoŔŇŤ6–›-ßđŤČ—Rzź™162‚_ń2śţÁ‹±vb˛ ˝hľ¸łłłřÁOŽíWŻÂŠe›öUVęt:¸îŔŻo¸ ‡°d©Â3źr ľţď?Ě‹?QHÝťĘĺ—®úžý´ĚöĽÓźˇţ÷Ýă±řÓm·ă†›˙ÝѢ¸$©le_„Žfüö3cő–[zeĂ:`G Sĺ…Yęč›÷/_¶÷?ř &¦& ŰÔĽDłí6ÖMMVúŽĚ/©@Ą1’ŇBµýł˛©&«˘* s&a#©4ĆtFjş&&ŽĄ"™‰ Rîĺ$…RĄ# ŠUúŘqF›ĂšH…®Ě\„”M .42 7K©uÁ¤áE›Ř hqśE;FĹ4eÂş ĺ A–!͵ˇh‘^U N¤2Ş‹R’RÖ^śÜ×™9yqC)¬ä+ÖZóS îúC WUăµj_$ţśçł?ŹuČ‚++g·Ňm”˝ŕ­Ő{-]=‚@3”b˙úÍoăuďż§ýëehw:8íĺ/Áąox-vŢz5.ř—qĚŮçă_üjöˇ_ZJáÇţ¶ÚtSĽ÷ÓWŕâ/}- ™Uşá/·â9§ś†Ďýŕ‡m·qŮŰNÄnŰm㍯ýףŁ5ţfĎÇbĺŠÍJ\GkĽé…˙uSÓřĘŹ~ŚNĆ7CJ)G/Ąđ_żą‡Ľé-h)…Ó^öâ¨\bµ”˛:ęśn„¶Ů‡°?ŢűŃŹăáµY{e÷ű3łłřßnÄĹźů ŢvĚ«1:2\Ş,XőuĐĚśžĆ/®˝'ťs..:ől´hQé}˛zË-×\˙;‹Yj»ÝĆő7ߌ{|»l·]AŠPX4>†sO> Ç˝çLüĺŽ;Ľtµ´iöâ8ťn˝ë.ś|îyř—c_Źń±Q$ł…¶Á,HÎöZJZ4:†çz>ňŮĎcbr2b.$Ŕpç˙—×^‡ĺK—b|t¬pŤŔCŁL¬¦jŮó«#!…ś)˘ŠMp‘\ w}nľëáş+”îEŠĚ­Š¤^Š:ś{9*˝cjŤ’‹ Ói śâcPlôBR„đb€śh”á<ĚďŘzŤćpşÓ©!’č“í|ŠĺąŠż·äÎ-SRná(B,I–˘<á^`čáÚD˙üdg—R™oŃ#3PT,>ÔĄŔ!1ńö珶FHfĆÔĚ žóćSđż6Ëjw:h)…‹żü5,Ýh#ŚŽ ăŽ{ď˛Ţ_üáŹ0ÖcöCDÂO>ü<éŐoŔé—\ޱ‘aĽňîƋƱí?ľ¨°Ź­[‡ˇÖ”"¬\ľ—˝ý-Ř{Ç"m†Ë®Ľ ĚŚcţáŮ• —D„Ë–â˙¸?ľ÷?×ŕŠď˙ŽzúÁÂüĚ4QîxÄK˘űtv¶Ť×®Ăčđ0:şS_öbĽüďŠŇŘ»·©·-¶Z ŁCĂYÄĚÁËžg(űcN?gĽáőXąĹć†R lŤ­ÖMNáłßşßüáâŇ3ߍe›,©d&§¦±N¸ž˛M1ffgqóí·áź˙&§§đ©sއ͗-+µtffŚŹŽâĚăߣO~Ž{é‹ńä}ö¶*’ć ßiĎbzf˙sÝuxĎG>ŽKÎ|— đqĂö¦°íŞ•¸ř´wŕźO= Ç}4žşßľő ·Ł5¦¦§ńßżúνôrś÷Ö“°zËÍmiÄĚäË™I˛ť]”4Ţ%býľvNⶆ†pÄáĎÂi\„ł?q)Ţđâańř††Ś¨“ÖíŽĆÔôľűß?Ĺ%_ř2>ńž302<ÔŐÎ}ý2‚J† Y klsžĚůcW.‹$XR˛ŮQył)ăcŕz”?ĹJ±łž `D> EoCedźołł—–FLBš™ŚY–ÍpcƨnGś-©ě¨­¸”ÓĐYRś)2i[F!1(šözoňäćËşv )=Nšp$»Vë!ĹČď`îÄ1şŞ…ĘF QťŤçá RY!yd†ˇˇ!wÎůX31#žţ4ý¬g`ß]wĆ]÷ÝŹO]ő}üŕę_a¶ÓĆóz ^ňŚC±Ë¶ŰŕÚ?ŢŚŹ~í[ŕĚ…Üyë­ŃŃťŇ`=>:Šź|řuĆ™¸ü;ßĂ®ŰnŤý÷ذíV[ŕÁuk ͢ŃQl˛Ń"lżŐV8hď=qđö1®—"Ű™śžĆ˝=„˝vÜĎ>đ€®Ů»ÝĆ›Źznűë˝řĹooŔ‹źq¨Ďv[n‰EŁĹi…Ec#ŘbÓeŘo×]đ˘ĂžŽĄm”ýśVKaŐ›÷% íjÚ[oą…µh‡†°ÍĘ­˛ÓŽŤY<6†×u~»ßpÚ…Äl§Ť·Ţ[®Ř Ż[‡?Ýv\ó0Úo_\qîŮŘxńâŇ^ĄË—.Ĺńď;;öG`°•"¬Ü|^sÔ ±Ă6Űt=D¬Řt>}îűpÖÇ/ÁÇ>˙lłr%¶ŮĘ” nżënüé¶Ű±zË-đoçś…Í–-5ĆE”˙†µZŘ}‡đŮóĎĹ— —~ĺ+XµůćŘfĺJnąóÜq÷=Řyűíđ™÷ź…ĺK—™ca†¶#KĄC tł;竜ĺvć9í36Z´ďzÓqřöŹ~„ל~ĆÇưӶŰ`Ů&›`zfřó_p÷ý÷cźÝvŧß˙>lĽx±wN\?h űó.şB0Ž‘áaÁZTŐv§Ť‰©)ÜqĎ_ń—ŰoŘvĺVX˝ĺX4:Šáá‘čAëô°™.YCîw§Ó)\#N´$ŰŔVŤ°ÓŃśžĆÚu¸é/Ć}>Ń‘ě´í¶Řbů¦ĂP«ĺmÍť5|?%Š‚ëĄÖÖÖ8|ĆĚlíŮY´uÇ@%ß`ú>ŚN9VvÇLA=ŃO¸}Ő˘¸M† ¦]1“gŇpßË@G#G2BO¤ŕĄ’ˇ,˝mÍ 4¤a-¶ĺČ'{6Ě— t°±f¶ÖŐôśJ%µZţ\°łÂ¶¦Rą@®b!‹ ń,É˙ű*ôät—)qŽPÂTŤťŔ•+Ý´Lé&¸f:M %ľ›dźC´gg13=Ť™éitÚmhÍĆţŮ…çš!«ćŮ©ř ţĽ°pLes ĺ nż8—c Ę‹-K¦¬Ü<ł)?nçwłqzŔŚxµĚš‡ :öĹ0®7ë4,$*łYŹŚĺŤ ćI˘8aC}?f¶r.ľ¸ł>ë "BŤĽúóíŁ¬¤¤’ˇř}ą})2+®;źaÚ$ΗÖívťN§§Ţ™śĄVčř™˛ ł3łm·íŘ.AµÜ{Ś µ3ůň–Ô-Éßł n AŽ,RÔg A€ůKMüŘ%8.ŕ)!ď-člbR­wĽ[§=ĎĚF, ¬‹S0,*Őň`čNÇ~Ž.féDY‘H*ucĘ srFR©jy“†@Ąu»;wţČ•I"„5ů~Ťv;€†v» Ö:ô|D »¦KöĽxN‚y`ĄßŞ™®]Ž©ú lšc^[ {îĽSĎ A­Ż‡łš5—,óči2 őďSNfęŚ8u ŇQFAUcZĹŔl5@ű@”M¦ü{Âô]ČŞ¨lŐ9Żh¤˙N‘HG;á˛îX$É9F&g†ĂĂ•YË*踣ÁíŽůłu„ł¤ÖđŚCĐXpiëÄčđÄç#4F˛Đ2űb{´.`€Y[‚CUŤ`ĺm÷Ik3žÜî•^ü)’ő`Á… ýLú"ę2šż8ł=*f섊ű–Îŕ¨gc¬ö?6"ňěją±3oBÇ/ OorŰĆk%IlwÔÍÉZLĽĘ´I†‹\'lP$Ku‹ô')KŰK÷7Á¦†»¨ßI•'**Ţ:Qµ•"+Ť±”0 GS ±Ś±˙;Zł˘2I–÷Ŕ®Y„w”m4…ĆnP”˝}ˇëřBś'%m>FoÄ›,˘'’po&™Í%±ă‚b"–óÔ”úő†Ă>Kĺž?† Fň'S IŁ3a?j° ! ş"sŘq„®vÉâ†LŰéŘԻǵ"`T/ŚD‚V #™ś˛ GŁĘ6ĹŢÇăľćł„ýŠÝżV<°”8mh8Ďi )ĐPQńڬ…¨ÖC3¦—*Kܦ¦­e»qËhL%ăMŹ“Ň¤®lc; Ńł˛J|űx`žĂq‘ťosveÚ ýáIÖ8żÝ˛j)JţfM*8Ž„Š&orş>bqak ýäôÉԸ؏tB«: r¨źkí@›ůŮ(=Ř o Ž!$1qbSJ“ş Í/DźđhSíßńVuȧ± ç0tüuŰ˝Z0nµžˇÚş?ɡŘęˇ.[r' `X@–Vň€m OjoiÄ»&„3 „‹{x€Ü-Ń_ ˇ˘ân¦ˇQ·s/‡ů¤ÄńxĄ¤ž… Ln Ě]Y˘2¤ě4$ŐćűĘ“5Ѱ?W0­Đ°­_¨…a”¤~2]j6½®NhŰśÜiP‚4÷İ’S\µcgćĺ‹Ücâ+Oë 3ţŮ $Vµ$4j–Dv˝98ŹptÍ04ţ"~şÇűpT_Ŕäđ|kăad˘‡óŢuóé§ß­“·q §^yë‚m=۶­m Ńľov‹çĐóLѻ֍ň}ć=řą=ş`•ž Uq?Ď.`nŹ˘31‘)iH ýSQ¤ö"ĺrŽ h4UI?Y˛Ěµž?8ar0ŁŹÔť+hłYaŕÍ™/ÉDIúR`ô· ¶äkű¬Öä´ţ’–ô P¶¦ĂqŠĄ3˰Pî«°{Ęť­@CEĹ#uwşdž±×qDňú f6Ş)OaŠ6?ž˝(v¬5ý©˛źśŕ9¬)żí]†aLŤ]8Ó„Ž S.>]ęĹWŔ'‡IÇWłÓ$aB1ŽI(×5T{ ŔpĎDéč¬tĆ)>qoš:†Ň€«AŽrÓ‘‰ÇMÜɶsŤ¬ÎgaCGÇ^+1HGně ľĂ¤ęf”šÁRęýź€\kfgşö‚^Sm¬R·­÷ČBÝ9śÚ”!­7]ešFÄbý ÖýŚCQ ˇâOQ&[9xp'Ç‘6Ť7I™şG"îUG:ő)ÎŕădĹČ.(Q jńúfh”<¬Ř§U•Ŕ ‡˙,ĆAćO‚±čĐ×Ríé ±/gă{*¸“Éť‡$´c®2;çËTµ+”čAˇÉm•hÍ”şíxţŮš$´‹ĄŹÚ^Ű~ÜŹ!â„iR-Ź3 ‡±Ř5R"dűGbퟸkç%v1¤H…śń 8Ĺ—Ďè“cÓyKČŇ—QzťMă„!¨pšĺ{ëoŮ7"RYwjj­HČmĚőhň2± H@K•ĘĚß_f|ĐĐCEŧôśŚ6ÎŁaS<‡ăĎ´ŞďcQyd±˝'A<ő1YkňvýK!Čá˝nąĆ&”r y%ŚUúöĚŻIžög°ÝäD¤»0ö›áť: ńx·ăÔšĂ6ćl6Ĺ ?G‚ˤÉâ)ÚÁ°şŹĺŠ–¤ÝĄńôF*“4„!MîVô2H,`Ř=W°—JĆE¬ 1;Sŕă˘=Ń [źÁŔIŚ´Ô0y€©`ÜÝ(廜ąë$ %¦'ᤎ =ŻÔŢÜy“×ö•›;ťÁ¤‰ YCdr.ßťBn—‘2íJDH×_ł?çmłž›  ÇA€™…qmëBP‹2î7í?<^wŞˇg„Á›lW ]On˙‰2 ÍŻ˘â‰ççě\˝vţδ‚ţÎäyůąJOk dÎĚĹ|ű‚„Pb:ösKďýâUžĚÖśűQV÷膎02§î}S!!ťri}îŇ-#)#mqŘÍńy‘ÉrôÄ=AB•?č%DV “ĐQ·Ädx…AŮQ€Đ÷ßD‚zCčŃ,bťŢYHaî±±N óč@7­ře n"h¤3ęމˇQUétŘ7YŽţ*¶5iÓ¸ŕ€™ŐŔC[m¸-1 Y¬ĚEéplÂ@ÜĹÖY•řoÖ8ŰíŃ™XÖΞ55G‚­ł ¨R«ŽúĚP "rĺRa1đňI†ŠŠ˙ż€Ł]¶,łžđ§ô'`°¨ľţ|‘LĆ’ć3&ę|¸gçwĆEĂčĺk˛’ĎyĄŕ‰{ěŇ<š>Ş1"ěťČLO-' هwÉÇ[¦˘ a;ĄŻŠłÇ&öۨlö˙Ľ$Üb é%0öqNm•AŁŁ7@ÚX# Í‘j­ÝÍŽ"#€ŃĹ ˛ű$Eş)@”l)ß›8µMëYA0-Ó¨ 7~ŠŇĚŽiŞŤ"7ťs8JjţÖY6+:20°W,]ş°šD§ń=ëÖĎ6ůâIťl,ł7D˘Ě!Žú\, 5ź •Ę2@†ŠŠŹ <¨řЉů ő5Ünîc°&Ć–!ÜםJĆťvCě«úfzf{^VŇŃ”űN‘ôfŢ)~=6’ÇYw ¤`A`· `Âf†ăÜm©9|±Ëţš@˙»,C,źČĐ7Ňąě·v+š×„Rş•6Ś’đĎďcɦއĐ{G(”ÄţHB˘ŘË FJç3{”ű 5˛jíÝŮ+7=NhżŃő˛,Ŕq¸źčOî4Ę­~8UÓÂ.żí“0® @BH=cö‹wrŐĐţ»¶Ż n˝!˛—IÄŮeŮ–~Í< 5ş5ŔŘřżSâKßKpÇ0-źH…4wɰ¬ĎKîZb˝J“Źš¨±i µ$‡YDĘÉyî^]2Y$[íěÖ• 3öĂôţ?¦©źÎŢ‘Ŕ" ŔÚĐŃŠMÚšu•]±EMúwÚićmˇäŕý `= *:‘§`¦¸űą·Ë(ą4˝$=ěÇF­µŮľŘ€/ő)‹eéL±7ýXô„Ť;phÉ0h^ąY˝hĐ­‘‰Šď%¸+—‰ß,´L‡JŹ{ŔqF]ŢW–Đĺq\Ye‰Ŕ„ĎĘgF…5-łĹŔF—‹‰"eYd“ÚFĹl«F$Ýgň¨˛ÔˇECé`ĽĺybÝč FŐFÄđ)±ÁOzÁŘôמo"QBľmĐDë Š&0x,čľËfčTĽš™™XNlŕf%Š<«ŃÍ«ĂČ©—¸ĐŘ* Ą ôBLĐ9Lz?Dű ;uż,ŔŘ'ÔŁ!†>Ĺ`ɸŠEŘěßwĆlvśCiĂ&TĬŘç†XĂYńÁí{` >Ň~G6Fé#Čl‘Ě(ŤĚkµÁTĐ&7¶Ť·p6hĐ3•ű"˘19RdCĹlŚ· ’ŔłÇSUźR–KîH‡×É•˛Dżwň1źńi`jÉź%ۧţHM®GP›eŞď§]ôU±.˝Nťż? ·\O’ćýU±2šxLőg ţeQkĂ j‘b©ÖĘfŠŐSą–©$wŮ›5fÁĘ“~ÝI†č]+묂[Ý»•4J8ʨ«|ý'A–łµ&)ĚzŠĘ$ËŇlľU¨ Úů@DISLĄ‹V"‰,NŚŁ’Âa%ěĎ”>Č—8Ô¦mcîLˇŰ@îAa÷g!–Ą‰Ai$K±Ü¶ 6Ţ€yëcÓsöě‚ćŮßÖ7¸¦—>|}ą\ţ˘ŇJĹGO2¶RÓjxŮq`LµeÁ jŠ8(FŢÚÇpWYbĚ Ăěbf«ĺ€±8Ć rżďÍ˝U‰Ľ'ŁD±j^h‚˘p¸Ěp ­d¤RŇhµóŔš"&®@·„v0KL¬Hln>±:±é/X٨ łßAőHéĺ°ň‡Bb‹uôpľďĆ+©ň^Šý“®$ĎÜH?ŕćäبŰ~+\Ä^ çŞMTř»SšůÁdíŇŮçA˶­•SٰE',Á7=ŃŃLŐVHz$ÎBhąLb MÂD…_ ±Ä)">6}‚ęUŽ^J÷¤č‚MFkU!ŤXRď˝0˝Ť`Ř\Ćú»ożű 4»‹qŃoQž}vă)÷Ů7ß|óÓĎ?˙ü*eU|t>»‹!ÂĺżÜ'5*Ůk±ZĎ IäÉă•Çe‰<ý€ť¦“Üľ,q$ő'3EŢ× îlBÝÍą÷. âćR^ÝF>a—čÁ ÎČ™88}†B›Ă v!˘X"Ă@‰ęN:č ěĚEsâÉuĄÜ·_ĎT{n„°âćţŚýŃ@Ki(qř$ibŇ)çVš|¬W&ó6Üš”.ě÷»ćJH@ÂNĘ*4Ĺ’ď•PĆ‚lµŢ”!™„e3wŽŤź?žóJĎ[«N5*4a}.Ö×®oA "¬kk„Ô~цmł˛„îëoó__Ŕ<ÂľŻA†/~½˝,pHňŁýč_űÍąęoĆ(DPĐf“˝IŚMĹ1t)ż×Đib•äçs­Ćqţü¶ŇÇaCXmĆĎÉŤ~)ĂĘ‘Úd™N)Ľ vxâ1żâśŘ‡qşaşŃd‚ŻŠńôsÔŞ,dş6°·ĐűŚqčß čv$śţˇýńźčvŰCrőU1·.{Ë;íś`KŽNÓëę6&U™źg:Ş(~ŕer\Ń ĂI*á$L×Ţ~ ŇRÇňZ&ŚŐh}2çG•fîÍ}â`ĄV"X×.ë —u…ő˛ÂĂz‡‡ <¬+\.¸\.đ°^ŕ˛^ŕárő˛Úó—eéęc’dśűů@”…t•A¤†j}'M‹Áe ú>ĐBÖ‡Ňz6xä ¶Ťő^'÷×őoŕíł2…L 3ťŚ´!żţőŻżűŐŻ~őc"Âo$±Ůg¶Z!÷ye˝đ^8 &PĐuô†˝ËÉ­]ű\ Ôüc©˘­Žó>ÓÍx%ĽBK΀š”Ž%RđxhŤ„H¬ ,´ŔÚÁ‚‰Ë.—Ţ)¸¬đĐż.+¬kíÚ€„–<Ůc§Ćp‚%Ź]¶ÓŞ 7Y‰«÷8!,kščűßš7ضMť„đç?űŹźü÷ď~÷íhŮâ˙Ą@ĂHÁ|ůĺ—?˙Ĺ/~ń·XzŇŻť@TŃ®ßÔ´†· Ăăư=¶.‼ťŢQL‹ÖőŤŃŹ:xTÜr58ř‘Ă«MĚG‚ŹĹ~ń › 8żÓ Ěd¤‡EďLJô¦ÓęĘ Ą‡Ö±ŤfÖ9u`đÓč9U ÷|v/ʏ2géIŘľ4]E§Üí5:ŚŹ‰Ö÷XwÓ‘1ěŔĺQ9U©vćv" | sort | uniq > authors gammaray-2.3.0/tests/000077500000000000000000000000001255003167400144575ustar00rootroot00000000000000gammaray-2.3.0/tests/CMakeLists.txt000066400000000000000000000121241255003167400172170ustar00rootroot00000000000000### BENCH SUITE if(Qt5Widgets_FOUND OR QT_QTGUI_FOUND) add_executable(benchsuite benchsuite.cpp) target_link_libraries(benchsuite ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTTEST_LIBRARIES} gammaray_common gammaray_core ) if(QNXNTO) target_link_libraries(benchsuite cpp) endif() ### CONNECTIONTEST add_executable(connectiontest test_connections.cpp) target_link_libraries(connectiontest ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTTEST_LIBRARIES} ) if(QNXNTO) target_link_libraries(connectiontest cpp) endif() endif() add_executable(attachhelper attachhelper.cpp) target_link_libraries(attachhelper ${QT_QTCORE_LIBRARIES}) if(QNXNTO) target_link_libraries(attachhelper cpp) endif() if(UNIX) add_test(connectiontest-preload ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray --inprocess -unittest -i preload ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) add_test(connectiontest-style ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray --inprocess -unittest -i style ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) set(RUN_FILTER_TESTS OFF CACHE BOOL "Run filter tests which fail due to a bug in QSortFilterProxyModel" ) if(RUN_FILTER_TESTS) add_test(connectiontest-preload-filter ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray -unittest -filtertest -i preload ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) add_test(connectiontest-preload-filter-modeltest ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray -unittest -modeltest -filtertest -i preload ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) add_test(connectiontest-style-filter ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray -unittest -filtertest -i style ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) endif() find_program(GDB_EXECUTABLE gdb) if(GDB_EXECUTABLE) add_test(connectiontest-gdb ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray --inprocess -unittest -i gdb ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) add_test(attachtest-gdb ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/attachhelper ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray gdb ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) if(RUN_FILTER_TESTS) add_test(connectiontest-gdb-filter ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/gammaray --inprocess -unittest -filtertest -i gdb ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/connectiontest ) endif() endif() endif() ### MultiSignalMapper test add_executable(multisignalmappertest multisignalmappertest.cpp ../core/multisignalmapper.cpp) target_link_libraries(multisignalmappertest ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTTEST_LIBRARIES} ) add_test(multisignalmappertest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/multisignalmappertest) ### Probe ABI test add_executable(probeabitest probeabitest.cpp) target_link_libraries(probeabitest gammaray_common_internal ${QT_QTTEST_LIBRARIES}) add_test(probeabitest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/probeabitest) add_executable(probeabidetectortest probeabidetectortest.cpp) target_link_libraries(probeabidetectortest gammaray_common_internal ${QT_QTTEST_LIBRARIES}) add_test(probeabidetectortest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/probeabidetectortest) ### Remote model tests if(GAMMARAY_BUILD_UI AND NOT GAMMARAY_PROBE_ONLY_BUILD) add_executable(remotemodeltest remotemodeltest.cpp ${CMAKE_SOURCE_DIR}/3rdparty/qt/modeltest.cpp ../core/remote/remotemodelserver.cpp ) target_link_libraries(remotemodeltest gammaray_core gammaray_client ${QT_QTGUI_LIBRARIES} ${QT_QTTEST_LIBRARIES} ${QT_QTNETWORK_LIBRARIES}) add_test(NAME remotemodeltest COMMAND remotemodeltest) endif() ### QSignalSpyCallback tests add_executable(signalspycallbacktest signalspycallbacktest.cpp ../hooking/probecreator.cpp ) target_link_libraries(signalspycallbacktest gammaray_core ${QT_QTTEST_LIBRARIES}) add_test(NAME signalspycallbacktest COMMAND signalspycallbacktest) ### QAction test if(Qt5Core_FOUND AND NOT Qt5Core_VERSION_MINOR LESS 4) # requires QHooks add_executable(actiontest actiontest.cpp ../hooking/probecreator.cpp ../hooking/hooks.cpp ) target_link_libraries(actiontest gammaray_core ${QT_QTTEST_LIBRARIES} ${QT_QTGUI_LIBRARIES}) add_test(NAME actiontest COMMAND actiontest) endif() ### MetaObject test add_executable(metaobjecttest metaobjecttest.cpp) target_link_libraries(metaobjecttest gammaray_core ${QT_QTTEST_LIBRARIES}) add_test(NAME metaobjecttest COMMAND metaobjecttest) ### PropertySyncer test add_executable(propertysyncertest propertysyncertest.cpp) target_link_libraries(propertysyncertest gammaray_common ${QT_QTGUI_LIBRARIES} ${QT_QTTEST_LIBRARIES}) add_test(NAME propertysyncertest COMMAND propertysyncertest) ### PropertyBinder test if(GAMMARAY_BUILD_UI) add_executable(propertybindertest propertybindertest.cpp) target_link_libraries(propertybindertest gammaray_ui ${QT_QTTEST_LIBRARIES}) add_test(NAME propertybindertest COMMAND propertybindertest) endif() add_subdirectory(manual) gammaray-2.3.0/tests/actiontest.cpp000066400000000000000000000056621255003167400173510ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; class ActionTest : public QObject { Q_OBJECT private: void createProbe() { Paths::setRelativeRootPath(GAMMARAY_INVERSE_BIN_DIR); qputenv("GAMMARAY_ProbePath", Paths::currentProbePath().toUtf8()); Hooks::installHooks(); Probe::startupHookReceived(); new ProbeCreator(ProbeCreator::CreateOnly); QTest::qWait(1); // event loop re-entry } private slots: void testActionCreationDeletion() { createProbe(); QAction *a1 = new QAction("Action 1", this); QAction *a2 = new QAction("Action 2", this); QTest::qWait(1); // event loop re-entry auto *model = ObjectBroker::model("com.kdab.GammaRay.ActionModel"); QVERIFY(model); QCOMPARE(model->rowCount(), 2); delete a1; QTest::qWait(1); // event loop re-entry delete a2; QTest::qWait(1); // event loop re-entry } void testConflictDetection() { createProbe(); QAction *a1 = new QAction("Action 1", this); a1->setShortcut(QKeySequence("Ctrl+K")); QAction *a2 = new QAction("Action 2", this); a2->setShortcut(QKeySequence("Ctrl+K")); QTest::qWait(1); // event loop re-entry auto *model = ObjectBroker::model("com.kdab.GammaRay.ActionModel"); QVERIFY(model); QCOMPARE(model->rowCount(), 2); const auto index = model->index(0, 5); QCOMPARE(index.data(Qt::DisplayRole).toString(), QKeySequence("Ctrl+K").toString(QKeySequence::NativeText)); } }; QTEST_MAIN(ActionTest) #include "actiontest.moc" gammaray-2.3.0/tests/attachhelper.cpp000066400000000000000000000070001255003167400176240ustar00rootroot00000000000000/* attachdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "attachhelper.h" #ifdef Q_OS_WIN32 #ifndef NOMINMAX // compile fix for Qt5+VS2010+QDateTime, see: http://qt-project.org/forums/viewthread/22133 #define NOMINMAX #endif #include #endif #include #include #include #include #include AttachHelper::AttachHelper(const QString &gammaray, const QString &injector, const QString &debuggee, const QStringList &arguments, QObject *parent) : QObject(parent), m_timer(new QTimer(this)), m_proc(new QProcess(this)), m_gammaray(gammaray), m_injector(injector) { m_proc->setProcessChannelMode(QProcess::ForwardedChannels); connect(m_proc, SIGNAL(started()), this, SLOT(processStarted())); connect(m_proc, SIGNAL(finished(int)), this, SLOT(processFinished(int))); m_proc->start(debuggee, arguments); } void AttachHelper::processStarted() { // attach randomly after 1-1500 ms qsrand(QDateTime::currentMSecsSinceEpoch()); const int timeout = qrand() % 1500 + 1; qDebug() << "attaching gammaray in" << timeout << "ms"; m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), this, SLOT(attach())); m_timer->start(timeout); } void AttachHelper::processFinished(int exitCode) { qApp->exit(exitCode); } void AttachHelper::attach() { if (m_proc->state() != QProcess::Running) { return; } qDebug() << "attaching gammaray"; QProcess gammaray; QStringList args; args << "--inprocess" << "-i" << m_injector; #ifdef Q_OS_WIN32 args << "-p" << QString::number(m_proc->pid()->dwProcessId); #else args << "-p" << QString::number(m_proc->pid()); #endif args << "-nodialogs"; const int ret = gammaray.execute(m_gammaray, args); if (ret != 0) { m_proc->kill(); qFatal("could not attach to debuggee"); } } int main(int argc, char **argv) { QCoreApplication app(argc, argv); if (app.arguments().size() < 4) { qWarning() << "usage: " << app.applicationName() << " GAMMARAY INJECTOR DEBUGGEE [DEBUGGEE_ARGS]"; return 1; } QStringList args = app.arguments(); // remove path to this bin args.removeFirst(); // gammaray const QString gammaray = args.takeFirst(); // injector const QString injector = args.takeFirst(); // app to run const QString debuggee = args.takeFirst(); AttachHelper helper(gammaray, injector, debuggee, args); return app.exec(); } gammaray-2.3.0/tests/attachhelper.h000066400000000000000000000033301255003167400172730ustar00rootroot00000000000000/* attachhelper.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TEST_GAMMARAY_ATTACHHELPER_H #define TEST_GAMMARAY_ATTACHHELPER_H #include class QTimer; class QProcess; class AttachHelper : public QObject { Q_OBJECT public: explicit AttachHelper(const QString &gammaray, const QString &injector, const QString &debuggee, const QStringList &arguments, QObject *parent = 0); public slots: void attach(); void processStarted(); void processFinished(int); private: QTimer *m_timer; QProcess *m_proc; QString m_gammaray; QString m_injector; }; #endif // ATTACHHELPER_H gammaray-2.3.0/tests/benchsuite.cpp000066400000000000000000000121461255003167400173200ustar00rootroot00000000000000/* benchsuite.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "benchsuite.h" #include "core/connectionmodel.h" #include "core/probe.h" #include "core/util.h" #include #include #include QTEST_MAIN(GammaRay::BenchSuite) using namespace GammaRay; void BenchSuite::iconForObject() { QWidget widget; QLabel label; QTreeView treeView; QBENCHMARK { Util::iconForObject(this); Util::iconForObject(&widget); Util::iconForObject(&label); Util::iconForObject(&treeView); } } void BenchSuite::connectionModel_connectionAdded() { Probe::createProbe(false); ConnectionModel model; static const int NUM_OBJECTS = 10000; QVector objects; objects.reserve(NUM_OBJECTS + 1); // fill it objects << new QObject; for (int i = 1; i <= NUM_OBJECTS; ++i) { QObject *obj = new QObject; objects << obj; Probe::objectAdded(obj); } QBENCHMARK { for (int i = 1; i <= NUM_OBJECTS; ++i) { model.connectionAdded(objects.at(i), SIGNAL(destroyed()), objects.at(i-1), SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(objects.at(i-1), SIGNAL(destroyed()), objects.at(i), SLOT(deleteLater()), Qt::AutoConnection); } } qDeleteAll(objects); delete Probe::instance(); } void BenchSuite::connectionModel_connectionRemoved() { Probe::createProbe(false); ConnectionModel model; static const int NUM_OBJECTS = 1000; QVector objects; objects.reserve(NUM_OBJECTS + 1); // fill it objects << new QObject; for (int i = 1; i <= NUM_OBJECTS; ++i) { QObject *obj = new QObject; objects << obj; Probe::objectAdded(obj); model.connectionAdded(obj, SIGNAL(destroyed()), objects.at(i-1), SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(objects.at(i-1), SIGNAL(destroyed()), obj, SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(obj, SIGNAL(destroyed()), objects.at(i-1), SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(objects.at(i-1), SIGNAL(destroyed()), obj, SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(obj, SIGNAL(invalid()), objects.at(i-1), SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(objects.at(i-1), SIGNAL(destroyed()), obj, SLOT(invalid()), Qt::AutoConnection); //krazy:cond=normalized,style // non-normalized model.connectionAdded(obj, SIGNAL( destroyed( ) ), objects.at(i-1), SLOT(deleteLater()), Qt::AutoConnection); model.connectionAdded(objects.at(i-1), SIGNAL(destroyed()), obj, SLOT( deleteLater( ) ), Qt::AutoConnection); //krazy:endcond=normalized,style } QBENCHMARK_ONCE { for (int i = 1; i <= NUM_OBJECTS; ++i) { model.connectionRemoved(objects.at(i), SIGNAL(destroyed()), objects.at(i-1), SLOT(deleteLater())); model.connectionRemoved(objects.at(i-1), SIGNAL(destroyed()), objects.at(i), SLOT(deleteLater())); model.connectionRemoved(objects.at(i), SIGNAL(destroyed()), objects.at(i-1), SLOT(invalid())); model.connectionRemoved(objects.at(i-1), SIGNAL(invalid()), objects.at(i), SLOT(deleteLater())); } } qDeleteAll(objects); delete Probe::instance(); } void BenchSuite::probe_objectAdded() { Probe::createProbe(false); static const int NUM_OBJECTS = 10000; QVector objects; objects.reserve(NUM_OBJECTS + 1); // fill it for (int i = 0; i < NUM_OBJECTS; ++i) { QObject *obj = new QObject; objects << obj; } QVector::const_iterator it = objects.constBegin(); QVector::const_iterator end = objects.constEnd(); QBENCHMARK_ONCE { while (it != end) { Probe::objectAdded(*it); ++it; } } qDeleteAll(objects); delete Probe::instance(); } gammaray-2.3.0/tests/benchsuite.h000066400000000000000000000027211255003167400167630ustar00rootroot00000000000000/* benchsuite.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_BENCHSUITE_H #define GAMMARAY_BENCHSUITE_H #include namespace GammaRay { class BenchSuite : public QObject { Q_OBJECT private slots: void iconForObject(); void connectionModel_connectionAdded(); void connectionModel_connectionRemoved(); void probe_objectAdded(); }; } #endif // GAMMARAY_BENCHSUITE_H gammaray-2.3.0/tests/hooktest/000077500000000000000000000000001255003167400163175ustar00rootroot00000000000000gammaray-2.3.0/tests/hooktest/hooktest.pro000066400000000000000000000004701255003167400207020ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2011-10-16T17:23:23 # #------------------------------------------------- QT += core gui TARGET = hooktest TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui gammaray-2.3.0/tests/hooktest/main.cpp000066400000000000000000000041251255003167400177510ustar00rootroot00000000000000/* main.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "mainwindow.h" #include #include #include #include #include #include static inline void * page_align(void *addr) { assert(addr != 0); return (void *)((size_t)addr & ~(0xFFFF)); } void writeJmp(void *func, void *replacement) { quint8 *cur = (quint8 *) func; quint8 *aligned = (quint8*)page_align(cur); assert(mprotect(aligned, 0xFFFF, PROT_READ|PROT_WRITE|PROT_EXEC) == 0); *cur = 0xff; *(++cur) = 0x25; *((quint32 *) ++cur) = 0; cur += sizeof (quint32); *((quint64*)cur) = (quint64)replacement; assert(mprotect(aligned, 0xFFFF, PROT_READ|PROT_EXEC) == 0); } void test() { qWarning() << "hook test!"; } int main(int argc, char *argv[]) { void *qt_startup_hook_addr = dlsym(RTLD_NEXT, "qt_startup_hook"); writeJmp(qt_startup_hook_addr, (void *)test); QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } gammaray-2.3.0/tests/hooktest/mainwindow.cpp000066400000000000000000000025251255003167400212030ustar00rootroot00000000000000/* mainwindow.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } gammaray-2.3.0/tests/hooktest/mainwindow.h000066400000000000000000000026731255003167400206540ustar00rootroot00000000000000/* mainwindow.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Andreas Holzammer Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TEST_GAMMARAY_MAINWINDOW_H #define TEST_GAMMARAY_MAINWINDOW_H #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H gammaray-2.3.0/tests/hooktest/mainwindow.ui000066400000000000000000000010501255003167400210260ustar00rootroot00000000000000 MainWindow 0 0 400 300 gammaray-2.3.0/tests/manual/000077500000000000000000000000001255003167400157345ustar00rootroot00000000000000gammaray-2.3.0/tests/manual/CMakeLists.txt000066400000000000000000000034441255003167400205010ustar00rootroot00000000000000if(Qt5Widgets_FOUND OR QT_QTGUI_FOUND) set(gammaray_messagemodeltest_srcs messagemodeltest.cpp ) add_executable(messagemodeltest ${gammaray_messagemodeltest_srcs} ) target_link_libraries(messagemodeltest ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ) endif() add_executable(minimalcoreapplication minimalcoreapplication.cpp) target_link_libraries(minimalcoreapplication ${QT_QTCORE_LIBRARIES}) add_executable(propertytest propertytest.cpp) target_link_libraries(propertytest ${QT_QTCORE_LIBRARIES}) add_executable(connectionstest connectionstest.cpp) target_link_libraries(connectionstest ${QT_QTCORE_LIBRARIES}) if(QT_QTWEBKIT_FOUND) add_executable(wk1application wk1application.cpp) target_link_libraries(wk1application ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ${QT_QTWEBKIT_LIBRARIES} ${QT_QTWEBKITWIDGETS_LIBRARIES} ) endif() if(Qt5WebKit_FOUND AND Qt5Quick_FOUND) set(wk2application_srcs wk2application.cpp) qt4_add_resources(wk2application_srcs wk2application.qrc) add_executable(wk2application ${wk2application_srcs}) target_link_libraries(wk2application Qt5::Quick) endif() add_executable(signalmonitortest signalmonitortest.cpp) target_link_libraries(signalmonitortest ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} ) if(QNXNTO) target_link_libraries(messagemodeltest cpp) endif() if(Qt5Widgets_FOUND AND NOT Qt5Widgets_VERSION VERSION_LESS 5.2.0) add_executable(variantinspectortest variantinspector.cpp variantinspectorapplication.cpp ) target_link_libraries(variantinspectortest Qt5::Widgets) endif() add_executable(gadgettest gadgettest.cpp) target_link_libraries(gadgettest ${QT_QTCORE_LIBRARIES}) add_executable(objectreparenttest objectreparenttest.cpp) target_link_libraries(objectreparenttest ${QT_QTCORE_LIBRARIES}) gammaray-2.3.0/tests/manual/connectionstest.cpp000066400000000000000000000070121255003167400216620ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include class MyTestObject : public QObject { Q_OBJECT public slots: void mySlot1() {} void mySlot2() {} void mySlot3() {} void mySlot4() {} signals: void mySignal1(); void mySignal2(); void mySignal3(); void mySignal4(); }; static void connectObjects(QObject *sender, QObject *receiver) { QObject::connect(sender, SIGNAL(mySignal1()), receiver, SLOT(mySlot1())); QObject::connect(sender, SIGNAL(mySignal2()), receiver, SLOT(mySlot2()), Qt::DirectConnection); QObject::connect(sender, SIGNAL(mySignal3()), receiver, SLOT(mySlot3()), Qt::QueuedConnection); QObject::connect(sender, SIGNAL(mySignal4()), receiver, SLOT(mySlot4()), Qt::BlockingQueuedConnection); } #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) static void dummyFunction() { } #endif int main(int argc, char** argv) { QCoreApplication app(argc, argv); MyTestObject sender, receiver; sender.setObjectName("sender"); receiver.setObjectName("receiver"); connectObjects(&sender, &receiver); MyTestObject selfConnect; selfConnect.setObjectName("selfConnect"); connectObjects(&selfConnect, &selfConnect); QThread thread; thread.setObjectName("thread"); thread.start(); MyTestObject threadSender, threadReceiver; threadSender.setObjectName("threadSender"); threadReceiver.setObjectName("threadReceiver"); threadSender.moveToThread(&thread); threadReceiver.moveToThread(&thread); MyTestObject localSender, localReceiver; localSender.setObjectName("localSender"); localReceiver.setObjectName("localReceiver"); connectObjects(&localSender, &threadReceiver); connectObjects(&threadSender, &localReceiver); MyTestObject doubleSender, doubleReceiver; doubleSender.setObjectName("doubleSender"); doubleReceiver.setObjectName("doubleReceiver"); connectObjects(&doubleSender, &doubleReceiver); connectObjects(&doubleSender, &doubleReceiver); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) MyTestObject lambdaSender, lambdaContext; lambdaSender.setObjectName("lambdaSender"); lambdaContext.setObjectName("lambdaContext"); QObject::connect(&lambdaSender, &MyTestObject::mySignal1, &dummyFunction); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) QObject::connect(&lambdaSender, &MyTestObject::mySignal2, &lambdaContext, &dummyFunction); #endif return app.exec(); } #include "connectionstest.moc" gammaray-2.3.0/tests/manual/gadgettest.cpp000066400000000000000000000036251255003167400206010ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include class MyGadget { Q_GADGET Q_PROPERTY(int prop1 READ prop1 WRITE setProp1) public: inline MyGadget() : m_prop1(42) {} inline int prop1() const { return m_prop1; } inline void setProp1(int v) { m_prop1 = v; } Q_INVOKABLE void someMethod(); private: int m_prop1; }; void MyGadget::someMethod() { qDebug() << Q_FUNC_INFO; } Q_DECLARE_METATYPE(MyGadget) class MyObject : public QObject { Q_OBJECT Q_PROPERTY(MyGadget gadget READ gadget) public: MyGadget gadget() const { return MyGadget(); } }; int main(int argc, char** argv) { qRegisterMetaType(); QCoreApplication app(argc, argv); MyObject obj; obj.setObjectName("MyObject"); return app.exec(); } #include "gadgettest.moc" gammaray-2.3.0/tests/manual/keyhandlingtest.qml000066400000000000000000000027271255003167400216540ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 Rectangle { color: "lightsteelblue" width: 640 height: 480 focus: true Text { id: label anchors.centerIn: parent text: "press a key" } // always works Keys.onLeftPressed: { label.text = "left pressed"; } // breaks with signal spy callbacks installed Keys.onPressed: { label.text = "key pressed"; console.log("xxx"); } } gammaray-2.3.0/tests/manual/listmodeltest.qml000066400000000000000000000031241255003167400213430ustar00rootroot00000000000000/* listmodeltest.qml This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 Rectangle { width: 200 height: 100 ListModel { id: cakeModel ListElement { name: "Mousse au chocolat"; cost: 1.29 } ListElement { name: "Chocolate cake"; cost: 1.99 } ListElement { name: "Tiramisu"; cost: 2.99 } } ListView { anchors.fill: parent model: cakeModel delegate: Row { spacing: 20 Text { text: name } Text { text: cost + '€' } } } } gammaray-2.3.0/tests/manual/messagemodeltest.cpp000066400000000000000000000046011255003167400220060ustar00rootroot00000000000000/* messagemodeltest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagemodeltest.h" #include #include #include #include using namespace GammaRay; MessageGenerator::MessageGenerator() { QVBoxLayout *layout = new QVBoxLayout; QPushButton *button = new QPushButton("debug"); connect(button, SIGNAL(clicked(bool)), SLOT(generateDebug())); layout->addWidget(button); button = new QPushButton("warning"); connect(button, SIGNAL(clicked(bool)), SLOT(generateWarning())); layout->addWidget(button); button = new QPushButton("critical"); connect(button, SIGNAL(clicked(bool)), SLOT(generateCritical())); layout->addWidget(button); button = new QPushButton("fatal"); connect(button, SIGNAL(clicked(bool)), SLOT(generateFatal())); layout->addWidget(button); setLayout(layout); } void MessageGenerator::generateDebug() { qDebug() << "A debug message"; } void MessageGenerator::generateWarning() { qWarning() << "A warning message" << "split into two parts"; } void MessageGenerator::generateCritical() { qCritical() << "A critical message"; } void MessageGenerator::generateFatal() { qFatal("A fatal message"); } int main(int argc, char **argv) { QApplication app(argc, argv); MessageGenerator generator; generator.show(); return app.exec(); } gammaray-2.3.0/tests/manual/messagemodeltest.h000066400000000000000000000030441255003167400214530ustar00rootroot00000000000000/* messagemodeltest.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEMODELTEST_H #define GAMMARAY_MESSAGEMODELTEST_H #include #ifndef Q_NORETURN #define Q_NORETURN #endif namespace GammaRay { class MessageGenerator : public QWidget { Q_OBJECT public: MessageGenerator(); private slots: void generateDebug(); void generateWarning(); void generateCritical(); Q_NORETURN void generateFatal(); }; } #endif // GAMMARAY_MESSAGEMODELTEST_H gammaray-2.3.0/tests/manual/minimalcoreapplication.cpp000066400000000000000000000024301255003167400231620ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include int main(int argc, char** argv) { QCoreApplication app(argc, argv); QObject obj; obj.setObjectName("myTestObject"); return app.exec(); } gammaray-2.3.0/tests/manual/objectreparenttest.cpp000066400000000000000000000040541255003167400223520ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include class MyObject : public QObject { Q_OBJECT public: explicit MyObject(QObject *parent = 0) : QObject(parent), c(new QObject(this)), p1(new QObject(this)), p2(new QObject(this)) { c->setObjectName("MovingSubtree"); auto t = new QTimer(this); t->start(10000); connect(t, SIGNAL(timeout()), SLOT(reparent())); auto gc = new QObject(c); new QObject(gc); c->setParent(p1); } public slots: void reparent() { if (c->parent() == p1) c->setParent(p2); else if (c->parent() == p2) c->setParent(0); else c->setParent(p1); } private: QObject *c, *p1, *p2; }; int main(int argc, char** argv) { QCoreApplication app(argc, argv); MyObject obj; obj.setObjectName("MyObject"); return app.exec(); } #include "objectreparenttest.moc" gammaray-2.3.0/tests/manual/propertytest.cpp000066400000000000000000000042051255003167400212250ustar00rootroot00000000000000/* propertytest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include class MyTestObject : public QObject { Q_OBJECT Q_PROPERTY(int staticChangingProperty READ staticChangingProperty RESET staticChangingPropertyReset NOTIFY staticChangingPropertyChanged) public: explicit MyTestObject(QObject *parent = 0) : QObject(parent), m_count(0) { setObjectName("propertyTestObject"); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(timeout())); timer->start(5000); } int staticChangingProperty() { return m_count; } void staticChangingPropertyReset() { m_count = 0; emit staticChangingPropertyChanged(); } signals: void staticChangingPropertyChanged(); private slots: void timeout() { ++m_count; setProperty("dynamicChangingProperty", m_count); emit staticChangingPropertyChanged(); } private: int m_count; }; int main(int argc, char** argv) { QCoreApplication app(argc, argv); MyTestObject obj; return app.exec(); } #include "propertytest.moc" gammaray-2.3.0/tests/manual/quickitemcreatedestroytest.qml000066400000000000000000000031151255003167400241400ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 Rectangle { color: "lightsteelblue" width: 240 height: 320 ListView { id: listView anchors { fill: parent; margins: 20 } objectName: "bububu" model: 255 delegate: Rectangle { color: Qt.rgba(model.index/ListView.view.count, (ListView.view.count-model.index)/ListView.view.count, 0.5, 1.0) implicitHeight: 20 implicitWidth: listView.width Text { text: model.index anchors.fill: parent } } } } gammaray-2.3.0/tests/manual/reparenttest.qml000066400000000000000000000034461255003167400211760ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 Rectangle { color: "lightsteelblue" width: 320 height: width/2 Rectangle { id: left anchors { left: parent.left; top: parent.top; margins: 20 } color: "yellow" width: 120 height: 120 Rectangle { color: "red" anchors.centerIn: parent width: 40 height: 40 focus: true Keys.onLeftPressed: { parent = left } Keys.onRightPressed: { parent = right } Rectangle { color: "blue" anchors.centerIn: parent anchors.margins: 5 } } } Rectangle { id: right anchors { right: parent.right; top: parent.top; margins: 20 } color: "green" width: 120 height: 120 } } gammaray-2.3.0/tests/manual/signalmonitortest.cpp000066400000000000000000000037211255003167400222300ustar00rootroot00000000000000/* signalmonitortest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "signalmonitortest.h" #include #include SignalMonitorTest::SignalMonitorTest(QObject *parent) : QObject(parent) , m_timerCount(0) { QTimer *t1 = new QTimer(this); t1->setObjectName(nextTimerName()); t1->start(250); QTimer *t2 = new QTimer(this); t2->setObjectName(nextTimerName()); connect(t2, SIGNAL(timeout()), this, SLOT(onTimeout())); t2->start(1500); } QString SignalMonitorTest::nextTimerName() { return QString::fromLatin1("SignalMonitorTest_t%1").arg(++m_timerCount); } void SignalMonitorTest::onTimeout() { QTimer *tx = new QTimer(this); tx->setObjectName(nextTimerName()); connect(tx, SIGNAL(timeout()), tx, SLOT(deleteLater())); tx->start(2500); } int main(int argc, char **argv) { QApplication app(argc, argv); new SignalMonitorTest(&app); return app.exec(); } gammaray-2.3.0/tests/manual/signalmonitortest.h000066400000000000000000000027531255003167400217010ustar00rootroot00000000000000/* signalmonitortest.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Mathias Hasselmann Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIGNALMONITORTEST_H #define GAMMARAY_SIGNALMONITORTEST_H #include class SignalMonitorTest : public QObject { Q_OBJECT public: SignalMonitorTest(QObject *parent = 0); private: QString nextTimerName(); private slots: void onTimeout(); private: int m_timerCount; }; #endif // GAMMARAY_SIGNALMONITORTEST_H gammaray-2.3.0/tests/manual/variantinspector.cpp000066400000000000000000000031231255003167400220320ustar00rootroot00000000000000/* variantinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "variantinspector.h" #include VariantInspector::VariantInspector(QObject *parent) : QObject(parent) { m_widget.reset(new QWidget); } QSharedPointer VariantInspector::sharedWidget() const { return m_widget; } QPointer VariantInspector::trackingWidget() const { return m_widget.data(); } QVector VariantInspector::widgetVector() const { QVector vec; vec << 5; vec << 6; vec << 7; vec << 8; return vec; } gammaray-2.3.0/tests/manual/variantinspector.h000066400000000000000000000033351255003167400215040ustar00rootroot00000000000000/* variantinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef VARIANTINSPECTOR_H #define VARIANTINSPECTOR_H #include #include class VariantInspector : public QObject { Q_OBJECT Q_PROPERTY(QSharedPointer sharedWidget READ sharedWidget CONSTANT) Q_PROPERTY(QPointer trackingWidget READ trackingWidget CONSTANT) Q_PROPERTY(QVector widgetVector READ widgetVector CONSTANT) public: explicit VariantInspector(QObject *parent = 0); QSharedPointer sharedWidget() const; QPointer trackingWidget() const; QVector widgetVector() const; private: QSharedPointer m_widget; }; #endif gammaray-2.3.0/tests/manual/variantinspectorapplication.cpp000066400000000000000000000027121255003167400242610ustar00rootroot00000000000000/* variantinspectorapplication.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "variantinspector.h" int main(int argc, char **argv) { QApplication app(argc, argv); VariantInspector vi; QHash mapping; mapping.insert("One", 1); mapping.insert("Two", 2); vi.setProperty("dynamicProperty", QVariant::fromValue(mapping)); return app.exec(); } gammaray-2.3.0/tests/manual/wk1application.cpp000066400000000000000000000025101255003167400213640ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include int main(int argc, char** argv) { QApplication app(argc, argv); QWebView view; view.setUrl(QUrl("http://www.kdab.com/gammaray")); view.show(); return app.exec(); } gammaray-2.3.0/tests/manual/wk2application.cpp000066400000000000000000000025171255003167400213740ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include int main(int argc, char** argv) { QGuiApplication app(argc, argv); QQuickView view; view.setSource(QUrl("qrc:/wk2application.qml")); view.show(); return app.exec(); } gammaray-2.3.0/tests/manual/wk2application.qml000066400000000000000000000023661255003167400214050ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 import QtWebKit 3.0 import QtWebKit.experimental 1.0 WebView { width: 800 height: 600 url: "http://www.kdab.com/gammaray" } gammaray-2.3.0/tests/manual/wk2application.qrc000066400000000000000000000001301255003167400213640ustar00rootroot00000000000000 wk2application.qml gammaray-2.3.0/tests/metaobjecttest.cpp000066400000000000000000000063521255003167400202060ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include Q_DECLARE_METATYPE(QThread::Priority) using namespace GammaRay; class MetaObjectTest : public QObject { Q_OBJECT private slots: void testMetaObject() { QVERIFY(MetaObjectRepository::instance()->hasMetaObject("QThread")); auto *mo = MetaObjectRepository::instance()->metaObject("QThread"); QVERIFY(mo); QCOMPARE(mo->className(), QString("QThread")); QVERIFY(mo->inherits("QObject")); auto *superMo = mo->superClass(0); QVERIFY(superMo); QCOMPARE(superMo->className(), QString("QObject")); QVERIFY(!mo->superClass(1)); QVERIFY(!superMo->superClass(0)); } void testMemberProperty() { auto *mo = MetaObjectRepository::instance()->metaObject("QThread"); QVERIFY(mo->propertyCount() >= 7); // depends on Qt version MetaProperty *prop = 0; for (int i = 0; i < mo->propertyCount(); ++i) { prop = mo->propertyAt(i); QVERIFY(prop); if (prop->name() == "priority") break; } QVERIFY(prop); QCOMPARE(prop->name(), QString("priority")); QCOMPARE(prop->typeName(), QString("QThread::Priority")); QThread t; QCOMPARE(prop->value(&t).value(), t.priority()); QCOMPARE(prop->isReadOnly(), false); } void testStaticProperty() { auto *mo = MetaObjectRepository::instance()->metaObject("QCoreApplication"); QVERIFY(mo); QVERIFY(mo->propertyCount() >= 8); // depends on Qt version MetaProperty *prop = 0; for (int i = 0; i < mo->propertyCount(); ++i) { prop = mo->propertyAt(i); QVERIFY(prop); if (prop->name() == "libraryPaths") break; } QVERIFY(prop); QCOMPARE(prop->name(), QString("libraryPaths")); QCOMPARE(prop->typeName(), QString("QStringList")); QCOMPARE(prop->isReadOnly(), true); QCOMPARE(prop->value(0).toStringList(), QCoreApplication::libraryPaths()); } }; QTEST_MAIN(MetaObjectTest) #include "metaobjecttest.moc" gammaray-2.3.0/tests/multisignalmappertest.cpp000066400000000000000000000060171255003167400216240ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "core/multisignalmapper.h" #include #include #include #include #include using namespace GammaRay; class Emitter : public QObject { Q_OBJECT signals: void signal1(int); void signal2(const QString &); friend class MultiSignalMapperTest; }; Q_DECLARE_METATYPE(QVector) class MultiSignalMapperTest : public QObject { Q_OBJECT public: explicit MultiSignalMapperTest(QObject* parent = 0) : QObject(parent) { qRegisterMetaType >(); } private: QMetaMethod method(QObject* obj, const char* name) { return obj->metaObject()->method(obj->metaObject()->indexOfSignal(name)); } private slots: void testMapper() { Emitter emitter1, emitter2; MultiSignalMapper mapper; mapper.connectToSignal(&emitter1, method(&emitter1, "signal1(int)")); mapper.connectToSignal(&emitter2, method(&emitter1, "signal1(int)")); mapper.connectToSignal(&emitter1, method(&emitter1, "signal2(QString)")); mapper.connectToSignal(&emitter2, method(&emitter1, "signal2(QString)")); QSignalSpy spy(&mapper, SIGNAL(signalEmitted(QObject*,int,QVector))); QVERIFY(spy.isValid()); QVERIFY(spy.isEmpty()); emitter1.signal1(42); QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).value(), &emitter1); QCOMPARE(spy.at(0).at(1).toInt(), emitter1.metaObject()->indexOfSignal("signal1(int)")); QCOMPARE(spy.at(0).at(2).value >().first().toInt(), 42); emitter2.signal2("hello"); QCOMPARE(spy.size(), 2); QCOMPARE(spy.at(1).at(0).value(), &emitter2); QCOMPARE(spy.at(1).at(1).toInt(), emitter1.metaObject()->indexOfSignal("signal2(QString)")); QCOMPARE(spy.at(1).at(2).value >().first().toString(), QString("hello")); } }; QTEST_MAIN(MultiSignalMapperTest) #include "multisignalmappertest.moc" gammaray-2.3.0/tests/probeabidetectortest.cpp000066400000000000000000000071501255003167400214030ustar00rootroot00000000000000/* probeabidetectortest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "common/probeabi.h" #include "common/probeabidetector.h" #include #include using namespace GammaRay; class ProbeABIDetectorTest : public QObject { Q_OBJECT private slots: void testDetectExecutable() { ProbeABIDetector detector; const ProbeABI abi = detector.abiForExecutable(QCoreApplication::applicationFilePath()); QCOMPARE(abi.id(), QString(GAMMARAY_PROBE_ABI)); } void testDetectProcess() { ProbeABIDetector detector; const ProbeABI abi = detector.abiForProcess(QCoreApplication::applicationPid()); QCOMPARE(abi.id(), QString(GAMMARAY_PROBE_ABI)); } void testContainsQtCore_data() { QTest::addColumn("line"); QTest::addColumn("isQtCore"); QTest::newRow("empty") << QString() << false; QTest::newRow("too short1") << "Qt" << false; QTest::newRow("too short2") << "Qt5" << false; QTest::newRow("unix1") << "libQtCore.so.4.8.6" << true; QTest::newRow("unix2") << "libQt5Core.so" << true; QTest::newRow("unix3") << "/path/to/libQt6Core.so.6.5.4" << true; QTest::newRow("unix4") << "\t libQt5Core.so.5.4.1\n" << true; QTest::newRow("mac1") << "QtCore" << true; QTest::newRow("mac2") << "/framework/5/QtCore" << true; QTest::newRow("mac3") << "Qt5Core.dylib.5.3.2" << true; QTest::newRow("mac4") << "libQt5Core.dylib" << true; QTest::newRow("mac5") << "/path/to/QtCore.dylib" << true; QTest::newRow("mac debug1") << "QtCore_debug" << true; QTest::newRow("mac debug2") << "QtCore_debug.dylib" << true; QTest::newRow("win1") << "QtCore.dll" << true; QTest::newRow("win2") << "Qt5Core.dll" << true; QTest::newRow("win3") << "c:\\path\\to\\Qt6Core.dll" << true; QTest::newRow("win debug1") << "QtCored.dll" << true; QTest::newRow("win debug2") << "Qt5Cored.dll" << true; QTest::newRow("complex path") << "/Qt/Core/5/QtCore.dll" << true; QTest::newRow("addon1") << "QtCoreAddon.dll" << false; QTest::newRow("addon2") << "Qt5CoredAddon.so" << false; //QTest::newRow("addon3") << "QtCore_Addon.dll" << false; QTest::newRow("QT") << "QTCore" << false; QTest::newRow("prefix") << "libFooQtCore.so" << false; QTest::newRow("libQt") << "libQt.dylib" << false; } void testContainsQtCore() { QFETCH(QString, line); QFETCH(bool, isQtCore); QCOMPARE(ProbeABIDetector::containsQtCore(line.toUtf8()), isQtCore); } }; QTEST_MAIN(ProbeABIDetectorTest) #include "probeabidetectortest.moc" gammaray-2.3.0/tests/probeabitest.cpp000066400000000000000000000154631255003167400176570ustar00rootroot00000000000000/* probeabitest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include using namespace GammaRay; class ProbeABITest : public QObject { Q_OBJECT private slots: void testIsValid() { ProbeABI abi; QVERIFY(!abi.isValid()); abi.setQtVersion(5, 2); QVERIFY(!abi.isValid()); abi.setArchitecture("x86_64"); #ifndef Q_OS_WIN QVERIFY(abi.isValid()); #else QVERIFY(!abi.isValid()); #endif abi.setCompiler("MSVC"); QVERIFY(abi.isValid()); } void testToString_data() { QTest::addColumn("id"); QTest::addColumn("majorVersion"); QTest::addColumn("minorVersion"); QTest::addColumn("isDebug"); QTest::addColumn("arch"); QTest::addColumn("compiler"); QTest::newRow("invalid") << QString() << -1 << -1 << false << QString() << QString(); #ifndef Q_OS_WIN QTest::newRow("unix") << "qt5.2-x86_64" << 5 << 2 << true << "x86_64" << "GCC"; #else QTest::newRow("msvc") << "qt5.2-MSVC-debug-x86_64" << 5 << 2 << true << "x86_64" << "MSVC"; QTest::newRow("mingw") << "qt5.2-GNU-i686" << 5 << 2 << false << "i686" << "GNU"; #endif } void testToString() { QFETCH(QString, id); QFETCH(int, majorVersion); QFETCH(int, minorVersion); QFETCH(bool, isDebug); QFETCH(QString, arch); QFETCH(QString, compiler); ProbeABI abi; abi.setQtVersion(majorVersion, minorVersion); abi.setIsDebug(isDebug); abi.setArchitecture(arch); abi.setCompiler(compiler); QCOMPARE(abi.id(), id); } void testFromString_data() { QTest::addColumn("id"); QTest::addColumn("valid"); QTest::addColumn("majorVersion"); QTest::addColumn("minorVersion"); QTest::addColumn("isDebug"); QTest::addColumn("arch"); QTest::addColumn("compiler"); QTest::newRow("invalid") << QString() << false << -1 << -1 << false << QString() << QString(); QTest::newRow("only version") << "qt5.2" << false << -1 << -1 << false << QString() << QString(); QTest::newRow("too many items") << "qt5.2-some-random-stuff-with-too-many-dashs" << false << -1 << -1 << false << QString() << QString(); QTest::newRow("missing debug/release") << "qt5.2-MSVC-i686" << false << -1 << -1 << false << QString() << QString(); QTest::newRow("extra debug/release") << "qt5.2-GNU-debug-arm" << false << -1 << -1 << false << QString() << QString(); #ifndef Q_OS_WIN QTest::newRow("unix") << "qt5.2-x86_64" << true << 5 << 2 << true << "x86_64" << "GCC"; #else QTest::newRow("msvc") << "qt5.2-MSVC-debug-x86_64" << true << 5 << 2 << true << "x86_64" << "MSVC"; QTest::newRow("mingw") << "qt5.2-GNU-i686" << true << 5 << 2 << true << "i686" << "GNU"; #endif } void testFromString() { QFETCH(QString, id); QFETCH(bool, valid); QFETCH(int, majorVersion); QFETCH(int, minorVersion); QFETCH(bool, isDebug); QFETCH(QString, arch); QFETCH(QString, compiler); const ProbeABI abi = ProbeABI::fromString(id); QCOMPARE(abi.isValid(), valid); if (!valid) return; QCOMPARE(abi.majorQtVersion(), majorVersion); QCOMPARE(abi.minorQtVersion(), minorVersion); QCOMPARE(abi.architecture(), arch); if (abi.isDebugRelevant()) QCOMPARE(abi.isDebug(), isDebug); #ifdef Q_OS_WIN QCOMPARE(abi.compiler(), compiler); #else Q_UNUSED(compiler); #endif } void testDisplayString_data() { QTest::addColumn("id"); QTest::addColumn("display"); QTest::newRow("invalid") << QString() << QString(); #ifndef Q_OS_WIN QTest::newRow("unix") << "qt5.2-x86_64" << "Qt 5.2 (x86_64)"; #else QTest::newRow("msvc") << "qt5.2-MSVC-debug-x86_64" << "Qt 5.2 (MSVC, debug, x86_64)"; QTest::newRow("mingw") << "qt5.2-GNU-i686" << "Qt 5.2 (GNU, i686)"; #endif } void testDisplayString() { QFETCH(QString, id); QFETCH(QString, display); const ProbeABI abi = ProbeABI::fromString(id); QCOMPARE(abi.displayString(), display); } void testProbeABICompat() { #ifndef Q_OS_WIN const ProbeABI targetABI = ProbeABI::fromString("qt5.2-x86_64"); const ProbeABI probeABI = ProbeABI::fromString("qt5.1-x86_64"); const bool compilerAbiMatters = false; #else const ProbeABI targetABI = ProbeABI::fromString("qt5.2-MSVC-release-x86_64"); const ProbeABI probeABI = ProbeABI::fromString("qt5.1-MSVC-release-x86_64"); const bool compilerAbiMatters = true; #endif // full match, or same major version and older probe QVERIFY(targetABI.isCompatible(targetABI)); QVERIFY(targetABI.isCompatible(probeABI)); // incompatible // newer minor version probe QVERIFY(!probeABI.isCompatible(targetABI)); // different major version ProbeABI incompatABI(probeABI); incompatABI.setQtVersion(4, 8); QVERIFY(!targetABI.isCompatible(incompatABI)); QVERIFY(!incompatABI.isCompatible(targetABI)); // different architecture incompatABI = targetABI; incompatABI.setArchitecture("i686"); QVERIFY(!targetABI.isCompatible(incompatABI)); // different debug/release mode incompatABI = targetABI; incompatABI.setIsDebug(true); QCOMPARE(targetABI.isCompatible(incompatABI), !compilerAbiMatters); // different compiler incompatABI = targetABI; incompatABI.setCompiler("Clang"); QCOMPARE(targetABI.isCompatible(incompatABI), !compilerAbiMatters); } void testProbeABISort() { ProbeABI qt52; qt52.setQtVersion(5, 2); ProbeABI qt51; qt51.setQtVersion(5, 1); ProbeABI qt48; qt48.setQtVersion(4, 8); QVERIFY(qt51 < qt52); QVERIFY(qt48 < qt52); QVERIFY(!(qt52 < qt51)); QVERIFY(!(qt51 < qt48)); QVERIFY(!(qt52 < qt52)); } }; QTEST_MAIN(ProbeABITest) #include "probeabitest.moc" gammaray-2.3.0/tests/propertybindertest.cpp000066400000000000000000000047341255003167400211430ustar00rootroot00000000000000/* propertybindertest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include class MyObject : public QObject { Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) Q_OBJECT public: explicit MyObject(QObject *parent = 0) : QObject(parent), p1(0) {} int intProp() { return p1; } void setIntProp(int i) { if (p1 == i) return; p1 = i; emit intPropChanged(); } signals: void intPropChanged(); private: int p1; }; using namespace GammaRay; class PropertyBinderTest : public QObject { Q_OBJECT private slots: void testBinding() { MyObject *obj1 = new MyObject(this); MyObject *obj2 = new MyObject(this); new PropertyBinder(obj1, "intProp", obj2, "intProp"); obj1->setIntProp(5); QCOMPARE(obj2->intProp(), 5); obj2->setIntProp(9); QCOMPARE(obj1->intProp(), 9); delete obj2; obj1->setIntProp(42); // don't crash } void testInitialBinding() { MyObject *obj1 = new MyObject(this); obj1->setIntProp(18); MyObject *obj2 = new MyObject(this); QVERIFY(obj1->intProp() != obj2->intProp()); new PropertyBinder(obj1, "intProp", obj2, "intProp"); QCOMPARE(obj2->intProp(), 18); } }; QTEST_MAIN(PropertyBinderTest) #include "propertybindertest.moc" gammaray-2.3.0/tests/propertysyncertest.cpp000066400000000000000000000106721255003167400212010ustar00rootroot00000000000000/* propertysyncertest.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include using namespace GammaRay; class MyObject : public QObject { Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) Q_OBJECT public: explicit MyObject(QObject *parent = 0) : QObject(parent), p1(0) {} int intProp() { return p1; } void setIntProp(int i) { if (p1 == i) return; p1 = i; emit intPropChanged(); } signals: void intPropChanged(); private: int p1; }; class PropertySyncerTest : public QObject { Q_OBJECT public: explicit PropertySyncerTest(QObject *parent = 0) : QObject(parent), m_server2ClientCount(0), m_client2ServerCount(0), m_client(0), m_server(0) { } public slots: void server2client(const GammaRay::Message &msg) { ++m_server2ClientCount; if (!m_client) return; QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::ReadWrite); msg.write(&buffer); buffer.seek(0); m_client->handleMessage(Message::readMessage(&buffer)); } void client2server(const GammaRay::Message &msg) { ++m_client2ServerCount; Q_ASSERT(m_server); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::ReadWrite); msg.write(&buffer); buffer.seek(0); m_server->handleMessage(Message::readMessage(&buffer)); } private slots: void testSync() { // server setup MyObject serverObj; serverObj.setIntProp(14); m_server = new PropertySyncer(this); connect(m_server, SIGNAL(message(GammaRay::Message)), this, SLOT(server2client(GammaRay::Message))); m_server->setAddress(1); m_server->addObject(42, &serverObj); // client setup MyObject *clientObj = new MyObject(this); m_client = new PropertySyncer(this); m_client->setRequestInitialSync(true); connect(m_client, SIGNAL(message(GammaRay::Message)), this, SLOT(client2server(GammaRay::Message))); m_client->setAddress(1); m_client->addObject(42, clientObj); m_server->setObjectEnabled(42, true); QCOMPARE(clientObj->intProp(), 0); QCOMPARE(m_client2ServerCount, 0); QCOMPARE(m_server2ClientCount, 0); // initial sync request m_client->setObjectEnabled(42, true); QCOMPARE(m_client2ServerCount, 1); QCOMPARE(m_server2ClientCount, 1); QCOMPARE(clientObj->intProp(), 14); // regular sync on changes on one side serverObj.setIntProp(42); QCOMPARE(m_server2ClientCount, 2); QCOMPARE(clientObj->intProp(), 42); QCOMPARE(m_client2ServerCount, 1); clientObj->setIntProp(23); QCOMPARE(serverObj.intProp(), 23); QCOMPARE(m_client2ServerCount, 2); QCOMPARE(m_server2ClientCount, 2); // client destroyed m_server->setObjectEnabled(42, false); delete clientObj; serverObj.setIntProp(26); QCOMPARE(m_server2ClientCount, 2); } private: int m_server2ClientCount, m_client2ServerCount; PropertySyncer *m_client; PropertySyncer *m_server; }; QTEST_MAIN(PropertySyncerTest) #include "propertysyncertest.moc" gammaray-2.3.0/tests/remotemodeltest.cpp000066400000000000000000000232611255003167400204030ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include <3rdparty/qt/modeltest.h> #include #include #include #include #include #include #include #include #include using namespace GammaRay; static void fakeRegisterServer() {} namespace GammaRay { class FakeRemoteModelServer : public RemoteModelServer { Q_OBJECT public: explicit FakeRemoteModelServer(const QString& objectName, QObject* parent = 0) : RemoteModelServer(objectName, parent) { m_myAddress = 42; } static void setup() { FakeRemoteModelServer::s_registerServerCallback = &fakeRegisterServer; } signals: void message(const GammaRay::Message &msg); private: bool isConnected() const Q_DECL_OVERRIDE { return true; } void sendMessage(const Message& msg) const Q_DECL_OVERRIDE { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::ReadWrite); msg.write(&buffer); buffer.seek(0); emit const_cast(this)->message(Message::readMessage(&buffer)); } }; class FakeRemoteModel : public RemoteModel { Q_OBJECT public: explicit FakeRemoteModel(const QString& serverObject, QObject* parent = 0) : RemoteModel(serverObject, parent) { m_myAddress = 42; } static void setup() { FakeRemoteModel::s_registerClientCallback = &fakeRegisterServer; } signals: void message(const GammaRay::Message &msg); private: virtual void sendMessage(const Message& msg) const Q_DECL_OVERRIDE { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::ReadWrite); msg.write(&buffer); buffer.seek(0); emit const_cast(this)->message(Message::readMessage(&buffer)); } }; } class RemoteModelTest : public QObject { Q_OBJECT private slots: void initTestCases() { FakeRemoteModelServer::setup(); FakeRemoteModel::setup(); } void testEmptyRemoteModel() { auto emptyModel = new QStandardItemModel(this); FakeRemoteModelServer server("com.kdab.GammaRay.UnitTest.EmptyModel", this); server.setModel(emptyModel); server.modelMonitored(true); FakeRemoteModel client("com.kdab.GammaRay.UnitTest.EmptyModel", this); connect(&server, SIGNAL(message(GammaRay::Message)), &client, SLOT(newMessage(GammaRay::Message))); connect(&client, SIGNAL(message(GammaRay::Message)), &server, SLOT(newRequest(GammaRay::Message))); ModelTest modelTest(&client); QCOMPARE(client.rowCount(), 0); QTest::qWait(10); QCOMPARE(client.rowCount(), 0); QCOMPARE(client.hasChildren(), false); } void testListRemoteModel() { auto listModel = new QStandardItemModel(this); listModel->appendRow(new QStandardItem("entry0")); listModel->appendRow(new QStandardItem("entry2")); listModel->appendRow(new QStandardItem("entry3")); listModel->appendRow(new QStandardItem("entry4")); FakeRemoteModelServer server("com.kdab.GammaRay.UnitTest.ListModel", this); server.setModel(listModel); server.modelMonitored(true); FakeRemoteModel client("com.kdab.GammaRay.UnitTest.ListModel", this); connect(&server, SIGNAL(message(GammaRay::Message)), &client, SLOT(newMessage(GammaRay::Message))); connect(&client, SIGNAL(message(GammaRay::Message)), &server, SLOT(newRequest(GammaRay::Message))); ModelTest modelTest(&client); QTest::qWait(10); // ModelTest is going to fetch stuff for us already QCOMPARE(client.rowCount(), 4); QCOMPARE(client.hasChildren(), true); auto index = client.index(1, 0); index.data(); // need an event loop entry for the data retrieval QTest::qWait(1); QCOMPARE(index.data().toString(), QString("entry2")); QCOMPARE(client.rowCount(index), 0); listModel->insertRow(1, new QStandardItem("entry1")); QCOMPARE(client.rowCount(), 5); index = client.index(1, 0); index.data(); // need an event loop entry for the data retrieval QTest::qWait(1); QCOMPARE(index.data().toString(), QString("entry1")); listModel->takeRow(3); QCOMPARE(client.rowCount(), 4); } void testTreeRemoteModel() { auto treeModel = new QStandardItemModel(this); auto e0 = new QStandardItem("entry0"); e0->appendRow(new QStandardItem("entry00")); e0->appendRow(new QStandardItem("entry01")); treeModel->appendRow(e0); auto e1 = new QStandardItem("entry1"); e1->appendRow(new QStandardItem("entry10")); e1->appendRow(new QStandardItem("entry12")); treeModel->appendRow(e1); FakeRemoteModelServer server("com.kdab.GammaRay.UnitTest.TreeModel", this); server.setModel(treeModel); server.modelMonitored(true); FakeRemoteModel client("com.kdab.GammaRay.UnitTest.TreeModel", this); connect(&server, SIGNAL(message(GammaRay::Message)), &client, SLOT(newMessage(GammaRay::Message))); connect(&client, SIGNAL(message(GammaRay::Message)), &server, SLOT(newRequest(GammaRay::Message))); ModelTest modelTest(&client); QTest::qWait(10); // ModelTest is going to fetch stuff for us already QCOMPARE(client.rowCount(), 2); QCOMPARE(client.hasChildren(), true); auto i1 = client.index(1, 0); i1.data(); // need an event loop entry for the data retrieval QTest::qWait(1); QCOMPARE(i1.data().toString(), QString("entry1")); QCOMPARE(client.rowCount(i1), 2); auto i12 = client.index(1, 0, i1); i12.data(); // need an event loop entry for the data retrieval QTest::qWait(1); QCOMPARE(i12.data().toString(), QString("entry12")); QCOMPARE(client.rowCount(i12), 0); e1->insertRow(1, new QStandardItem("entry11")); QCOMPARE(client.rowCount(i1), 3); auto i11 = client.index(1, 0, i1); i11.data(); // need an event loop entry for the data retrieval QTest::qWait(1); QCOMPARE(i11.data().toString(), QString("entry11")); QCOMPARE(client.rowCount(i11), 0); e1->takeRow(0); QCOMPARE(client.rowCount(i1), 2); i11 = client.index(0, 0, i1); QCOMPARE(i11.data().toString(), QString("entry11")); } // this should not make a difference if the above works, however it broke massively with Qt 5.4... void testSortProxy() { auto treeModel = new QStandardItemModel(this); auto e0 = new QStandardItem("entry1"); e0->appendRow(new QStandardItem("entry10")); e0->appendRow(new QStandardItem("entry11")); treeModel->appendRow(e0); auto e1 = new QStandardItem("entry0"); e1->appendRow(new QStandardItem("entry00")); e1->appendRow(new QStandardItem("entry01")); e1->appendRow(new QStandardItem("entry02")); e1->appendRow(new QStandardItem("entry03")); treeModel->appendRow(e1); FakeRemoteModelServer server("com.kdab.GammaRay.UnitTest.TreeModel2", this); server.setModel(treeModel); server.modelMonitored(true); FakeRemoteModel client("com.kdab.GammaRay.UnitTest.TreeModel2", this); connect(&server, SIGNAL(message(GammaRay::Message)), &client, SLOT(newMessage(GammaRay::Message))); connect(&client, SIGNAL(message(GammaRay::Message)), &server, SLOT(newRequest(GammaRay::Message))); QSortFilterProxyModel proxy; proxy.setDynamicSortFilter(true); proxy.sort(0); proxy.setSourceModel(&client); ModelTest modelTest(&proxy); QTest::qWait(10); // ModelTest is going to fetch stuff for us already QCOMPARE(client.rowCount(), 2); QCOMPARE(proxy.rowCount(), 2); auto pi0 = proxy.index(0, 0); QCOMPARE(pi0.data().toString(), QString("entry0")); QCOMPARE(proxy.rowCount(pi0), 4); auto pi03 = proxy.index(3, 0, pi0); QCOMPARE(pi03.data().toString(), QString("entry03")); auto ci0 = client.index(0, 0); QCOMPARE(ci0.data().toString(), QString("entry1")); QCOMPARE(client.rowCount(ci0), 2); auto pi1 = proxy.index(1, 0); QCOMPARE(pi1.data().toString(), QString("entry1")); // this fails with data() call batching sizes close to 1 // QEXPECT_FAIL("", "QSFPM misbehavior, no idea yet where this is coming from", Continue); QCOMPARE(proxy.rowCount(pi1), 2); } }; QTEST_MAIN(RemoteModelTest) #include "remotemodeltest.moc" gammaray-2.3.0/tests/signalspycallbacktest.cpp000066400000000000000000000046211255003167400215540ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include using namespace GammaRay; class Sender : public QObject { Q_OBJECT public: void emitSignal() { emit mySignal(); } signals: void mySignal(); }; class Receiver : public QObject { Q_OBJECT public slots: void senderDeletingSlot() { delete sender(); } }; class SignalSpyCallbackTest : public QObject { Q_OBJECT private: void createProbe() { qputenv("GAMMARAY_ProbePath", QCoreApplication::applicationDirPath().toUtf8()); new ProbeCreator(ProbeCreator::CreateOnly); QTest::qWait(1); // event loop re-entry } private slots: void testSenderDeletion() { createProbe(); QPointer s1 = new Sender; QPointer s2 = new Sender; Receiver r; connect(s1, SIGNAL(mySignal()), &r, SLOT(senderDeletingSlot())); s1->emitSignal(); // must not crash QVERIFY(s1.isNull()); // give the probe time to process s and r2 (needs one event loop re-entry) QTest::qWait(1); connect(s2, SIGNAL(mySignal()), &r, SLOT(senderDeletingSlot())); s2->emitSignal(); // must not crash QVERIFY(s2.isNull()); } }; QTEST_MAIN(SignalSpyCallbackTest) #include "signalspycallbacktest.moc" gammaray-2.3.0/tests/test_connections.cpp000066400000000000000000000174671255003167400205630ustar00rootroot00000000000000/* test_connections.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "test_connections.h" #include #include #include #include #include const int TIMEOUTINTERVAL = 10; const int OBJECTS = 50; const int TIMEOUTS = 100; //BEGIN TestObject TestObject::TestObject(QObject *parent) : QObject(parent) // test object creation in ctor , child(new QObject(this)) { setObjectName("TestObject"); child->setObjectName("TestObjectChild"); // test connect/disconnect in ctor connect(child, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); disconnect(child, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); // now connect again for dtor connect(child, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); } TestObject::~TestObject() { // test disconnect disconnect(child, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); // test connect, and leave it around to test disconnect-on-delete connect(child, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); } //END TestObject //BEGIN TestConnections TestConnections::TestConnections(TestConnections::Type type, int timeOuts, int timeoutInterval) : m_type(type), m_timeOuts(timeOuts), m_numTimeout(0), m_timer(new QTimer(this)) { m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), SLOT(timeout())); m_timer->start(timeoutInterval == -1 ? TIMEOUTINTERVAL : timeoutInterval); } TestConnections::~TestConnections() { } void TestConnections::timeout() { if (m_numTimeout == m_timeOuts) { qDeleteAll(m_objects); m_objects.clear(); emit done(); delete m_timer; m_timer = 0; return; } m_numTimeout++; if (m_type == NoEventLoop) { // directly create and delete objects without eventloop in between QObject *obj = new TestObject(this); connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); delete obj; } else if (m_type == Stack) { QObject obj; connect(&obj, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); disconnect(&obj, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); } else if (m_type == SetParent) { TestObject *obj = new TestObject; obj->setParent(this); obj->child->setParent(0); obj->child->setParent(obj); obj->deleteLater(); } else { // delete last objects for (int i = 0; i < m_objects.count(); ++i) { QObject *obj = m_objects.at(i); switch(m_type) { case Delete: delete obj; break; case DeleteLater: obj->deleteLater(); break; default: break; } } m_objects.clear(); // create some new objects for (int i = 0; i < OBJECTS; ++i) { QObject *obj = new TestObject(this); m_objects << obj; connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(dummySlot())); } } } //END TestConnections //BEGIN TestThread TestThread::TestThread(TestConnections::Type type, int timeOuts, int timeoutInterval, QObject *parent) : QThread(parent), m_type(type), m_timeOuts(timeOuts), m_timeoutInterval(timeoutInterval) { } TestThread::~TestThread() { } void TestThread::run() { TestConnections tester(m_type, m_timeOuts, m_timeoutInterval == -1 ? TIMEOUTS : m_timeoutInterval); QEventLoop *loop = new QEventLoop; connect(&tester, SIGNAL(done()), loop, SLOT(quit())); loop->exec(); delete loop; } //END TestThread //BEGIN TestWaiter void TestWaiter::addTester(TestConnections *tester) { connect(tester, SIGNAL(done()), SLOT(testerDone())); m_tester << tester; } void TestWaiter::testerDone() { TestConnections* tester = qobject_cast(sender()); QVERIFY(tester); QVERIFY(m_tester.removeOne(tester)); checkFinished(); } void TestWaiter::addThread(TestThread *thread) { connect(thread, SIGNAL(finished()), SLOT(threadFinished())); m_threads << thread; } void TestWaiter::threadFinished() { TestThread* thread = qobject_cast(sender()); QVERIFY(thread); QVERIFY(m_threads.removeOne(thread)); checkFinished(); } void TestWaiter::checkFinished() { if (!m_loop) { return; } if (m_threads.isEmpty() && m_tester.isEmpty()) { m_loop->quit(); } } void TestWaiter::startThreadsAndWaitForFinished() { if (m_threads.isEmpty() && m_tester.isEmpty()) { return; } foreach (TestThread *thread, m_threads) { thread->start(); } m_loop = new QEventLoop; m_loop->exec(); delete m_loop; m_loop = 0; } //END TestWaiter //BEGIN TestMain TestMain::TestMain(int argc, char **argv) : m_argc(argc), m_argv(argv) { QMetaObject::invokeMethod(this, "startTests", Qt::QueuedConnection); } void TestMain::startTests() { qApp->exit(QTest::qExec(this, m_argc, m_argv)); } void TestMain::run_data() { QTest::addColumn("type"); QTest::newRow("delete") << static_cast(TestConnections::Delete); QTest::newRow("deleteLater") << static_cast(TestConnections::DeleteLater); QTest::newRow("noEventLoop") << static_cast(TestConnections::NoEventLoop); QTest::newRow("stack") << static_cast(TestConnections::Stack); QTest::newRow("setParent") << static_cast(TestConnections::SetParent); } void TestMain::run() { QFETCH(int, type); bool manual = QProcessEnvironment::systemEnvironment().value("GAMMARAY_TEST_MANUAL").toInt(); TestConnections tester(static_cast(type), manual ? -1 : TIMEOUTS); TestWaiter waiter; waiter.addTester(&tester); waiter.startThreadsAndWaitForFinished(); } void TestMain::threading() { TestWaiter waiter; const int timeouts = 10; // some testers to be run in the main thread // with varying timouts TestConnections tester1(TestConnections::NoEventLoop, timeouts, 10); waiter.addTester(&tester1); TestConnections tester2(TestConnections::Delete, timeouts, 11); waiter.addTester(&tester2); TestConnections tester3(TestConnections::DeleteLater, timeouts, 12); waiter.addTester(&tester3); TestConnections tester4(TestConnections::Stack, timeouts, 13); waiter.addTester(&tester4); TestConnections tester5(TestConnections::SetParent, timeouts, 14); waiter.addTester(&tester5); // now some threads TestThread thread1(TestConnections::NoEventLoop, timeouts, 10); waiter.addThread(&thread1); TestThread thread2(TestConnections::Delete, timeouts, 11); waiter.addThread(&thread2); TestThread thread3(TestConnections::DeleteLater, timeouts, 12); waiter.addThread(&thread3); TestThread thread4(TestConnections::Stack, timeouts, 13); waiter.addThread(&thread4); TestThread thread5(TestConnections::SetParent, timeouts, 13); waiter.addThread(&thread5); waiter.startThreadsAndWaitForFinished(); } //END TestMain int main(int argc, char *argv[]) { QApplication app(argc, argv); TestMain tc(argc, argv); return app.exec(); } gammaray-2.3.0/tests/test_connections.h000066400000000000000000000057101255003167400202140ustar00rootroot00000000000000/* test_connections.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEST_CONNECTIONS_H #define GAMMARAY_TEST_CONNECTIONS_H #include #include class QTimer; class QEventLoop; class TestObject : public QObject { Q_OBJECT public: explicit TestObject(QObject *parent = 0); ~TestObject(); private slots: void dummySlot() { } public: QObject *child; }; class TestConnections : public QObject { Q_OBJECT public: enum Type { DeleteLater, Delete, NoEventLoop, Stack, SetParent }; TestConnections(Type type, int timeOuts, int timeoutInterval = -1); ~TestConnections(); public slots: void timeout(); private slots: void dummySlot() { } signals: void done(); private: const Type m_type; const int m_timeOuts; int m_numTimeout; QList m_objects; QTimer *m_timer; }; class TestThread : public QThread { Q_OBJECT public: TestThread(TestConnections::Type type, int timeOuts, int timeoutInterval = -1, QObject *parent = 0); ~TestThread(); void run() Q_DECL_OVERRIDE; private: TestConnections::Type m_type; int m_timeOuts; int m_timeoutInterval; }; class TestMain : public QObject { Q_OBJECT public: TestMain(int argc, char **m_argv); public slots: void startTests(); private slots: void run_data(); void run(); void threading(); private: int m_argc; char **m_argv; }; class TestWaiter : public QObject { Q_OBJECT public: void addThread(TestThread *thread); void addTester(TestConnections *tester); void startThreadsAndWaitForFinished(); private slots: void testerDone(); void threadFinished(); private: void checkFinished(); QList m_threads; QList m_tester; QEventLoop *m_loop; }; #endif // TEST_CONNECTIONS_H gammaray-2.3.0/ui/000077500000000000000000000000001255003167400137325ustar00rootroot00000000000000gammaray-2.3.0/ui/CMakeLists.txt000066400000000000000000000111761255003167400165000ustar00rootroot00000000000000# # Shared code between in-process and out-of-process UI # set(gammaray_ui_srcs ${CMAKE_SOURCE_DIR}/3rdparty/kde/krecursivefilterproxymodel.cpp ${CMAKE_SOURCE_DIR}/3rdparty/kde/kfilterproxysearchline.cpp aboutdata.cpp clienttoolmodel.cpp deferredresizemodesetter.cpp deferredtreeviewconfiguration.cpp editabletypesmodel.cpp methodinvocationdialog.cpp palettemodel.cpp propertybinder.cpp propertywidget.cpp proxytooluifactory.cpp splashscreen.cpp propertyeditor/propertycoloreditor.cpp propertyeditor/propertydoublepaireditor.cpp propertyeditor/propertyeditorfactory.cpp propertyeditor/propertyextendededitor.cpp propertyeditor/propertyfonteditor.cpp propertyeditor/propertyintpaireditor.cpp propertyeditor/propertypaletteeditor.cpp propertyeditor/palettedialog.cpp propertyeditor/propertyeditordelegate.cpp tools/connectioninspector/connectioninspectorwidget.cpp tools/localeinspector/localeinspectorwidget.cpp tools/messagehandler/messagehandlerwidget.cpp tools/messagehandler/messagehandlerclient.cpp ../core/tools/messagehandler/messagehandlerinterface.cpp tools/metaobjectbrowser/metaobjectbrowserwidget.cpp tools/metatypebrowser/metatypebrowserwidget.cpp tools/mimetypes/mimetypeswidget.cpp tools/modelinspector/modelinspectorwidget.cpp tools/modelinspector/modelinspectorclient.cpp tools/objectinspector/objectinspectorwidget.cpp tools/objectinspector/propertiestab.cpp tools/objectinspector/propertiesextensionclient.cpp tools/objectinspector/methodsextensionclient.cpp tools/objectinspector/methodstab.cpp tools/objectinspector/connectionstab.cpp tools/objectinspector/connectionsclientproxymodel.cpp tools/objectinspector/connectionsextensionclient.cpp tools/objectinspector/enumstab.cpp tools/objectinspector/classinfotab.cpp tools/objectinspector/methodstab.cpp tools/resourcebrowser/clientresourcemodel.cpp tools/resourcebrowser/resourcebrowserwidget.cpp tools/resourcebrowser/resourcebrowserclient.cpp tools/standardpaths/standardpathswidget.cpp tools/textdocumentinspector/textdocumentinspectorwidget.cpp tools/textdocumentinspector/textdocumentcontentview.cpp ) qt4_wrap_ui(gammaray_ui_srcs methodinvocationdialog.ui propertyeditor/propertydoublepaireditor.ui propertyeditor/propertyextendededitor.ui propertyeditor/propertyintpaireditor.ui propertyeditor/palettedialog.ui tools/connectioninspector/connectioninspectorwidget.ui tools/localeinspector/localeinspectorwidget.ui tools/messagehandler/messagehandlerwidget.ui tools/metatypebrowser/metatypebrowserwidget.ui tools/mimetypes/mimetypeswidget.ui tools/modelinspector/modelinspectorwidget.ui tools/objectinspector/objectinspectorwidget.ui tools/objectinspector/propertiestab.ui tools/objectinspector/methodstab.ui tools/objectinspector/connectionstab.ui tools/objectinspector/enumstab.ui tools/objectinspector/classinfotab.ui tools/objectinspector/methodstab.ui tools/resourcebrowser/resourcebrowserwidget.ui tools/standardpaths/standardpathswidget.ui tools/textdocumentinspector/textdocumentinspectorwidget.ui ) if(NOT Qt5Core_VERSION VERSION_LESS 5.2.0) list(APPEND gammaray_ui_srcs variantcontainermodel.cpp ) endif() add_library(gammaray_ui SHARED ${gammaray_ui_srcs}) set_target_properties(gammaray_ui PROPERTIES ${GAMMARAY_DEFAULT_LIBRARY_PROPERTIES} DEFINE_SYMBOL MAKE_GAMMARAY_UI_LIB OUTPUT_NAME gammaray_ui-${GAMMARAY_PROBE_ABI} ) target_link_libraries(gammaray_ui LINK_PUBLIC ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common LINK_PRIVATE gammaray_common_internal ) install(TARGETS gammaray_ui EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) set(gammaray_ui_internal_srcs sidepane.cpp aboutpluginsdialog.cpp mainwindow.cpp aboutdialog.cpp ) qt4_wrap_ui(gammaray_ui_internal_srcs mainwindow.ui aboutdialog.ui ) add_library(gammaray_ui_internal STATIC ${gammaray_ui_internal_srcs}) set_target_properties(gammaray_ui_internal PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(gammaray_ui_internal ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES} gammaray_common_internal gammaray_ui ) gammaray_install_headers( gammaray_ui_export.h clienttoolmodel.h deferredresizemodesetter.h deferredtreeviewconfiguration.h propertywidget.h propertywidgettab.h tooluifactory.h ) ecm_generate_pri_file(BASE_NAME GammaRayUi LIB_NAME gammaray_ui-${GAMMARAY_PROBE_ABI} DEPS "core gui widgets GammaRayCommon" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/.. ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) gammaray-2.3.0/ui/aboutdata.cpp000066400000000000000000000054251255003167400164100ustar00rootroot00000000000000/* aboutdata.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "aboutdata.h" #include #include #include #include using namespace GammaRay; QStringList AboutData::authors() { QFile f(":/gammaray/authors"); if (f.open(QFile::ReadOnly)) { return QString::fromUtf8(f.readAll()).split('\n', QString::SkipEmptyParts); } else { Q_ASSERT_X(0, "AboutData::authors()", "cannot open the authors resource file"); qWarning() << "Failed to open the authors resource file"; return QStringList(QObject::tr("Unable to read the Authors list")); } } QStringList AboutData::authorsAsHtml() { const auto plainAuthors = authors(); QStringList a; a.reserve(plainAuthors.size()); foreach (const QString &author, plainAuthors) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) a.push_back(Qt::escape(author)); #else a.push_back(author.toHtmlEscaped()); #endif } return a; } QString AboutData::aboutTitle() { return QObject::trUtf8("GammaRay %1").arg(GAMMARAY_VERSION_STRING); } QString AboutData::aboutBody() { return QObject::trUtf8( "

The Qt application inspection and manipulation tool." "Learn more at http://www.kdab.com/gammaray/.

" "

Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, " "a KDAB Group company, info@kdab.com

" "

Authors:
%1

" "

StackWalker code Copyright (c) 2005-2009, Jochen Kalmbach, All rights reserved

") .arg(authorsAsHtml().join("
")); } QString AboutData::aboutText() { return aboutTitle() + aboutBody(); } gammaray-2.3.0/ui/aboutdata.h000066400000000000000000000027651255003167400160610ustar00rootroot00000000000000/* aboutdata.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ABOUTDATA_H #define GAMMARAY_ABOUTDATA_H #include "gammaray_ui_export.h" #include namespace GammaRay { namespace AboutData { QStringList authors(); QStringList authorsAsHtml(); GAMMARAY_UI_EXPORT QString aboutTitle(); GAMMARAY_UI_EXPORT QString aboutBody(); GAMMARAY_UI_EXPORT QString aboutText(); } } #endif // GAMMARAY_ABOUTDATA_H gammaray-2.3.0/ui/aboutdialog.cpp000066400000000000000000000031471255003167400167350ustar00rootroot00000000000000/* aboutdialog.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "aboutdialog.h" #include "ui_aboutdialog.h" using namespace GammaRay; AboutDialog::AboutDialog(QWidget* parent): QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); } AboutDialog::~AboutDialog() { } void AboutDialog::setTitle(const QString& title) { ui->titleLabel->setText(title); } void AboutDialog::setText(const QString& text) { ui->textLabel->setText(text); } void AboutDialog::setLogo(const QString& iconFileName) { ui->logoLabel->setPixmap(iconFileName); } gammaray-2.3.0/ui/aboutdialog.h000066400000000000000000000031251255003167400163760ustar00rootroot00000000000000/* aboutdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ABOUTDIALOG_H #define GAMMARAY_ABOUTDIALOG_H #include namespace GammaRay { namespace Ui { class AboutDialog; } class AboutDialog : public QDialog { Q_OBJECT public: explicit AboutDialog(QWidget* parent = 0); ~AboutDialog(); void setTitle(const QString &title); void setText(const QString &text); void setLogo(const QString &iconFileName); private: QScopedPointer ui; }; } #endif // GAMMARAY_ABOUTDIALOG_H gammaray-2.3.0/ui/aboutdialog.ui000066400000000000000000000041221255003167400165620ustar00rootroot00000000000000 GammaRay::AboutDialog 75 true 0 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true true Qt::TextBrowserInteraction Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop QDialogButtonBox::Close buttonBox rejected() GammaRay::AboutDialog close() 261 302 310 98 gammaray-2.3.0/ui/aboutpluginsdialog.cpp000066400000000000000000000051541255003167400203370ustar00rootroot00000000000000/* aboutpluginsdialog.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "aboutpluginsdialog.h" #include #include #include #include #include #include #include using namespace GammaRay; AboutPluginsDialog::AboutPluginsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { QLayout *layout = 0; QVBoxLayout *vbox = new QVBoxLayout(this); { QTableView *toolView = new QTableView(this); toolView->setShowGrid(false); toolView->setSelectionBehavior(QAbstractItemView::SelectRows); toolView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); toolView->verticalHeader()->hide(); toolView->setModel(ObjectBroker::model("com.kdab.GammaRay.ToolPluginModel")); QGroupBox *toolBox = new QGroupBox(tr("Loaded Plugins"), this); layout = new QHBoxLayout(toolBox); layout->addWidget(toolView); vbox->addWidget(toolBox); } { QTableView *errorView = new QTableView(this); errorView->setShowGrid(false); errorView->setSelectionBehavior(QAbstractItemView::SelectRows); errorView->setModel(ObjectBroker::model("com.kdab.GammaRay.ToolPluginErrorModel")); errorView->verticalHeader()->hide(); errorView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); QGroupBox *errorBox = new QGroupBox(tr("Failed Plugins"), this); layout = new QHBoxLayout(errorBox); layout->addWidget(errorView); vbox->addWidget(errorBox); } setWindowTitle(tr("GammaRay: Plugin Info")); } gammaray-2.3.0/ui/aboutpluginsdialog.h000066400000000000000000000026471255003167400200100ustar00rootroot00000000000000/* aboutpluginsdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_ABOUTPLUGINSDIALOG_H #define GAMMARAY_ABOUTPLUGINSDIALOG_H #include namespace GammaRay { class AboutPluginsDialog : public QDialog { Q_OBJECT public: explicit AboutPluginsDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); }; } #endif // GAMMARAY_ABOUTPLUGINSDIALOG_H gammaray-2.3.0/ui/clienttoolmodel.cpp000066400000000000000000000166641255003167400176500ustar00rootroot00000000000000/* clienttoolmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "clienttoolmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; #define MAKE_FACTORY(type, remote) \ class type ## Factory : public ToolUiFactory { \ public: \ virtual inline QString id() const { return "GammaRay::" #type; } \ virtual inline QWidget *createWidget(QWidget *parentWidget) { return new type ## Widget(parentWidget); } \ virtual inline bool remotingSupported() const { return remote; } \ } MAKE_FACTORY(ConnectionInspector, true); MAKE_FACTORY(LocaleInspector, true); MAKE_FACTORY(MessageHandler, true); MAKE_FACTORY(MetaObjectBrowser, true); MAKE_FACTORY(MetaTypeBrowser, true); MAKE_FACTORY(MimeTypes, true); MAKE_FACTORY(ModelInspector, true); MAKE_FACTORY(ResourceBrowser, true); MAKE_FACTORY(StandardPaths, true); MAKE_FACTORY(TextDocumentInspector, true); struct PluginRepository { ~PluginRepository() { qDeleteAll(factories.values()); } // ToolId -> ToolUiFactory QHash factories; // so far unused tools that yet have to be loaded/initialized QSet inactiveTools; }; Q_GLOBAL_STATIC(PluginRepository, s_pluginRepository) static void insertFactory(ToolUiFactory* factory) { s_pluginRepository()->factories.insert(factory->id(), factory); s_pluginRepository()->inactiveTools.insert(factory); } static void initPluginRepository() { if (!s_pluginRepository()->factories.isEmpty()) return; insertFactory(new ConnectionInspectorFactory); insertFactory(new LocaleInspectorFactory); insertFactory(new MessageHandlerFactory); insertFactory(new MetaObjectBrowserFactory); insertFactory(new MetaTypeBrowserFactory); insertFactory(new MimeTypesFactory); insertFactory(new ModelInspectorFactory); insertFactory(new ObjectInspectorFactory); insertFactory(new ResourceBrowserFactory); insertFactory(new StandardPathsFactory); insertFactory(new TextDocumentInspectorFactory); PluginManager pm; foreach(ToolUiFactory* factory, pm.plugins()) insertFactory(factory); } ClientToolModel::ClientToolModel(QObject* parent) : QSortFilterProxyModel(parent) { initPluginRepository(); connect(this, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateToolInitialization(QModelIndex,QModelIndex))); } ClientToolModel::~ClientToolModel() { } QVariant ClientToolModel::data(const QModelIndex& index, int role) const { if (role == ToolModelRole::ToolFactory || role == ToolModelRole::ToolWidget || role == Qt::ToolTipRole) { const QString toolId = QSortFilterProxyModel::data(index, ToolModelRole::ToolId).toString(); if (toolId.isEmpty()) return QVariant(); if (role == ToolModelRole::ToolFactory) return QVariant::fromValue(s_pluginRepository()->factories.value(toolId)); if (role == ToolModelRole::ToolWidget) { const WidgetsHash::const_iterator it = m_widgets.constFind(toolId); if (it != m_widgets.constEnd() && it.value()) return QVariant::fromValue(it.value()); ToolUiFactory *factory = s_pluginRepository()->factories.value(toolId); if (!factory) return QVariant(); if (s_pluginRepository()->inactiveTools.contains(factory)) { factory->initUi(); s_pluginRepository()->inactiveTools.remove(factory); } QWidget *widget = factory->createWidget(m_parentWidget); m_widgets.insert(toolId, widget); return QVariant::fromValue(widget); } if (role == Qt::ToolTipRole) { ToolUiFactory *factory = s_pluginRepository()->factories.value(toolId); if (factory && (!factory->remotingSupported() && Endpoint::instance()->isRemoteClient())) return tr("This tool does not work in out-of-process mode."); } } return QSortFilterProxyModel::data(index, role); } bool ClientToolModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (index.isValid() && role == ToolModelRole::ToolWidget) { const QString toolId = QSortFilterProxyModel::data(index, ToolModelRole::ToolId).toString(); Q_ASSERT(!toolId.isEmpty()); Q_ASSERT(!m_widgets.contains(toolId)); m_widgets.insert(toolId, value.value()); return true; } else if (role == ToolModelRole::ToolWidgetParent) { m_parentWidget = value.value(); return true; } return QSortFilterProxyModel::setData(index, value, role); } Qt::ItemFlags ClientToolModel::flags(const QModelIndex &index) const { Qt::ItemFlags ret = QSortFilterProxyModel::flags(index); const QString toolId = QSortFilterProxyModel::data(index, ToolModelRole::ToolId).toString(); ToolUiFactory *factory = s_pluginRepository()->factories.value(toolId); if (!factory || (!factory->remotingSupported() && Endpoint::instance()->isRemoteClient())) { ret &= ~Qt::ItemIsEnabled; } return ret; } void ClientToolModel::updateToolInitialization(const QModelIndex& topLeft, const QModelIndex& bottomRight) { for (int i = topLeft.row(); i <= bottomRight.row(); i++) { QModelIndex index = QSortFilterProxyModel::index(i, 0); if (QSortFilterProxyModel::data(index, ToolModelRole::ToolEnabled).toBool()) { const QString toolId = QSortFilterProxyModel::data(index, ToolModelRole::ToolId).toString(); ToolUiFactory *factory = s_pluginRepository()->factories.value(toolId); if (factory && (factory->remotingSupported() || !Endpoint::instance()->isRemoteClient()) && s_pluginRepository()->inactiveTools.contains(factory)) { factory->initUi(); s_pluginRepository()->inactiveTools.remove(factory); } } } } gammaray-2.3.0/ui/clienttoolmodel.h000066400000000000000000000044311255003167400173020ustar00rootroot00000000000000/* clienttoolmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENTTOOLMODEL_H #define GAMMARAY_CLIENTTOOLMODEL_H #include "gammaray_ui_export.h" #include #include #include #include class QWidget; namespace GammaRay { class ToolUiFactory; /** @brief Tool model for the client that implements the custom roles that return widget/factory pointers. * * This is needed when implementing your own client UI embedded into a different application. */ class GAMMARAY_UI_EXPORT ClientToolModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ClientToolModel(QObject* parent = 0); ~ClientToolModel(); QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; private slots: void updateToolInitialization(const QModelIndex & topLeft, const QModelIndex & bottomRight); private: typedef QHash> WidgetsHash; mutable WidgetsHash m_widgets; // ToolId -> Widget QPointer m_parentWidget; }; } #endif // GAMMARAY_CLIENTTOOLMODEL_H gammaray-2.3.0/ui/deferredresizemodesetter.cpp000066400000000000000000000034071255003167400215400ustar00rootroot00000000000000/* deferredresizemodesetter.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "deferredresizemodesetter.h" using namespace GammaRay; DeferredResizeModeSetter::DeferredResizeModeSetter(QHeaderView* headerView, int section, QHeaderView::ResizeMode resizeMode): QObject(headerView), m_view(headerView), m_section(section), m_resizeMode(resizeMode) { connect(m_view, SIGNAL(sectionCountChanged(int,int)), SLOT(setSectionResizeMode())); setSectionResizeMode(); } DeferredResizeModeSetter::~DeferredResizeModeSetter() { } void DeferredResizeModeSetter::setSectionResizeMode() { if (m_view->count() <= m_section) return; // section not loaded yet m_view->setResizeMode(m_section, m_resizeMode); } gammaray-2.3.0/ui/deferredresizemodesetter.h000066400000000000000000000040621255003167400212030ustar00rootroot00000000000000/* deferredresizemodesetter.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_DEFERREDRESIZEMODESETTER_H #define GAMMARAY_DEFERREDRESIZEMODESETTER_H #include "gammaray_ui_export.h" #include #include namespace GammaRay { /** @brief Sets the resize mode on a QHeaderView section once that section is actually available. * * This is a workaround for QHeaderView asserting when manipulating if the corresponding section * hasn't been loaded yet by the corresponding model, as well as forgetting the setting if the * model reports a columnCount of 0 again inbetween. */ class GAMMARAY_UI_EXPORT DeferredResizeModeSetter : public QObject { Q_OBJECT public: DeferredResizeModeSetter(QHeaderView *headerView, int section, QHeaderView::ResizeMode resizeMode); ~DeferredResizeModeSetter(); private slots: void setSectionResizeMode(); private: QHeaderView *m_view; int m_section; QHeaderView::ResizeMode m_resizeMode; }; } #endif // GAMMARAY_DEFERREDRESIZEMODESETTER_H gammaray-2.3.0/ui/deferredtreeviewconfiguration.cpp000066400000000000000000000053411255003167400225640ustar00rootroot00000000000000/* deferredtreeviewconfiguration.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "deferredtreeviewconfiguration.h" #include #include using namespace GammaRay; using namespace std; DeferredTreeViewConfiguration::DeferredTreeViewConfiguration(QTreeView *view, bool expandNewContent, bool selectNewContent, QObject *parent) : QObject(parent ? parent : view) , m_view(view) , m_expand(expandNewContent) , m_select(selectNewContent) { Q_ASSERT(view); Q_ASSERT(view->model()); Q_ASSERT(view->selectionModel()); connect(view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex))); connect(view->model(), SIGNAL(columnsInserted(QModelIndex,int,int)), SLOT(columnsInserted(QModelIndex))); if (view->model()->rowCount() > 0) { rowsInserted(QModelIndex()); if (m_expand) { view->expandAll(); } } columnsInserted(QModelIndex()); } void DeferredTreeViewConfiguration::hideColumn(int column) { m_hiddenColumns << column; columnsInserted(QModelIndex()); } void DeferredTreeViewConfiguration::rowsInserted(const QModelIndex &parent) { if (m_expand) { m_view->expand(parent); } if (m_select && !m_view->currentIndex().isValid()) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index(0, 0), QItemSelectionModel::ClearAndSelect); } } void DeferredTreeViewConfiguration::columnsInserted(const QModelIndex &parent) { if (m_hiddenColumns.isEmpty() || parent.isValid()) { return; } const int columns = m_view->model()->columnCount(parent); foreach(int column, m_hiddenColumns) { if (column < columns) { m_view->hideColumn(column); } } } gammaray-2.3.0/ui/deferredtreeviewconfiguration.h000066400000000000000000000046321255003167400222330ustar00rootroot00000000000000/* deferredtreeviewconfiguration.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_DEFERREDTREEVIEWCONFIGURATION_H #define GAMMARAY_DEFERREDTREEVIEWCONFIGURATION_H #include "gammaray_ui_export.h" #include #include class QModelIndex; class QTreeView; namespace GammaRay { /** * @brief A utility helper to configure views for remote content. * * When @p expandNewContent is set to true, the tree view will stay expanded * when new content is added to the model. * * When @p selectNewContent is set to true, the tree view will select new content, * if no selection is already present. * * @note The tree view's model and selectionModel must be set beforehand and not * be changed afterwards! */ class GAMMARAY_UI_EXPORT DeferredTreeViewConfiguration : public QObject { Q_OBJECT public: explicit DeferredTreeViewConfiguration(QTreeView *view, bool expandNewContent = true, bool selectNewContent = true, QObject *parent = 0); void hideColumn(int column); private slots: void rowsInserted(const QModelIndex &parent); void columnsInserted(const QModelIndex &parent); private: QTreeView *m_view; bool m_expand; bool m_select; QVector m_hiddenColumns; }; } #endif // GAMMARAY_DEFERREDTREEVIEWCONFIGURATION_H gammaray-2.3.0/ui/editabletypesmodel.cpp000066400000000000000000000035561255003167400203260ustar00rootroot00000000000000/* editabletypesmodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "editabletypesmodel.h" #include "propertyeditor/propertyeditorfactory.h" using namespace GammaRay; EditableTypesModel::EditableTypesModel(QObject* parent): QAbstractListModel(parent) { m_types = PropertyEditorFactory::supportedTypes(); } EditableTypesModel::~EditableTypesModel() { } int EditableTypesModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_types.size(); } QVariant EditableTypesModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); const int type = m_types.at(index.row()); if (role == Qt::DisplayRole) { return QMetaType::typeName(type); } else if (role == Qt::UserRole) { return type; } return QVariant(); } gammaray-2.3.0/ui/editabletypesmodel.h000066400000000000000000000033371255003167400177700ustar00rootroot00000000000000/* editabletypesmodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_EDITABLETYPESMODEL_H #define GAMMARAY_EDITABLETYPESMODEL_H #include #include namespace GammaRay { /** All types we have edit widgets for. */ class EditableTypesModel : public QAbstractListModel { Q_OBJECT public: explicit EditableTypesModel(QObject *parent = 0); ~EditableTypesModel(); int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QVector m_types; }; } #endif // GAMMARAY_EDITABLETYPESMODEL_H gammaray-2.3.0/ui/gammaray_ui_export.h000066400000000000000000000027341255003167400200050ustar00rootroot00000000000000/* gammaray_ui_export.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_UI_EXPORT_H #define GAMMARAY_UI_EXPORT_H #include #ifdef GAMMARAY_UI_STATICLIB # undef GAMMARAY_UI_SHAREDLIB # define GAMMARAY_UI_EXPORT #else # ifdef MAKE_GAMMARAY_UI_LIB # define GAMMARAY_UI_EXPORT Q_DECL_EXPORT # else # define GAMMARAY_UI_EXPORT Q_DECL_IMPORT # endif #endif #endif /* GAMMARAY_UI_EXPORT_H */ gammaray-2.3.0/ui/mainwindow.cpp000066400000000000000000000206231255003167400166150ustar00rootroot00000000000000/* mainwindow.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mainwindow.h" #include "ui_mainwindow.h" #include "aboutpluginsdialog.h" #include "aboutdialog.h" #include "clienttoolmodel.h" #include "aboutdata.h" #include "common/objectbroker.h" #include "common/modelroles.h" #include "common/endpoint.h" #include "common/probecontrollerinterface.h" #include "kde/krecursivefilterproxymodel.h" #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #else #include //krazy:exclude=camelcase #include #endif #include #include #include #include using namespace GammaRay; MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) { if (!Endpoint::instance()->isRemoteClient()) { // we don't want application styles to propagate to the GammaRay window, // so set the platform default one. // unfortunately, that's not recursive by default, unless we have a style sheet set setStyleSheet(QLatin1String("I_DONT_EXIST {}")); QStyle *defaultStyle = 0; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QGuiPlatformPlugin defaultGuiPlatform; defaultStyle = QStyleFactory::create(defaultGuiPlatform.styleName()); #else foreach (const QString &styleName, QGuiApplicationPrivate::platform_theme->themeHint(QPlatformTheme::StyleNames).toStringList()) { if ((defaultStyle = QStyleFactory::create(styleName))) { break; } } #endif if (defaultStyle) { // do not set parent of default style // this will cause the style being deleted too early through ~QObject() // other objects (e.g. the script engine debugger) still might have a // reference on the style during destruction setStyle(defaultStyle); } } ui->setupUi(this); connect(ui->actionRetractProbe, SIGNAL(triggered(bool)), SLOT(detachProbe())); connect(QApplication::instance(), SIGNAL(aboutToQuit()), SLOT(close())); connect(ui->actionQuit, SIGNAL(triggered(bool)), this, SLOT(quitHost())); ui->actionQuit->setIcon(QIcon::fromTheme("application-exit")); connect(ui->actionPlugins, SIGNAL(triggered(bool)), this, SLOT(aboutPlugins())); connect(ui->actionAboutQt, SIGNAL(triggered(bool)), QApplication::instance(), SLOT(aboutQt())); connect(ui->actionAboutGammaRay, SIGNAL(triggered(bool)), SLOT(about())); connect(ui->actionAboutKDAB, SIGNAL(triggered(bool)), SLOT(aboutKDAB())); setWindowIcon(QIcon(":gammaray/GammaRay-128x128.png")); QAbstractItemModel *model = ObjectBroker::model("com.kdab.GammaRay.ToolModel"); ClientToolModel *toolModel = new ClientToolModel(this); toolModel->setData(QModelIndex(), QVariant::fromValue(this), ToolModelRole::ToolWidgetParent); toolModel->setSourceModel(model); ui->toolSelector->setModel(toolModel); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(toolModel); ui->toolSelector->setSelectionModel(selectionModel); ui->toolSelector->resize(ui->toolSelector->minimumSize()); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(toolSelected())); // hide unused tool bar for now ui->mainToolBar->setHidden(true); setWindowTitle(tr("GammaRay (%1)").arg(Endpoint::instance()->label())); selectInitialTool(); connect(ui->toolSelector->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectInitialTool())); connect(ui->toolSelector->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(selectInitialTool())); #ifdef Q_OS_MAC ui->groupBox->setFlat(true); ui->horizontalLayout->setContentsMargins(0, 0, 0, 0); #endif // get some sane size on startup resize(1024, 768); } MainWindow::~MainWindow() { } void MainWindow::about() { AboutDialog dialog(this); dialog.setWindowTitle(tr("About GammaRay")); dialog.setTitle(AboutData::aboutTitle()); dialog.setText(AboutData::aboutBody()); dialog.setLogo(":gammaray/GammaRay-128x128.png"); dialog.setWindowIcon(QPixmap(":gammaray/GammaRay-128x128.png")); dialog.exec(); } void MainWindow::aboutPlugins() { AboutPluginsDialog dlg(this); dlg.setFixedSize(800, 600); dlg.exec(); } void MainWindow::aboutKDAB() { AboutDialog dialog(this); dialog.setWindowTitle(tr("About KDAB")); dialog.setTitle(trUtf8("Klarälvdalens Datakonsult AB (KDAB)")); dialog.setText( tr("

GammaRay is supported and maintained by KDAB

" "KDAB, the Qt experts, provide consulting and mentoring for developing " "Qt applications from scratch and in porting from all popular and legacy " "frameworks to Qt. We continue to help develop parts of Qt and are one " "of the major contributors to the Qt Project. We can give advanced or " "standard trainings anywhere around the globe.

" "

Please visit http://www.kdab.com " "to meet the people who write code like this." "

")); dialog.setLogo(":gammaray/kdablogo160.png"); dialog.setWindowIcon(QPixmap(":gammaray/kdablogo160.png")); dialog.exec(); } void MainWindow::selectInitialTool() { static const QString initialTool("GammaRay::ObjectInspector"); QAbstractItemModel *model = ui->toolSelector->model(); QModelIndexList matches = model->match(model->index(0, 0), ToolModelRole::ToolId, initialTool); if (matches.isEmpty()) { return; } disconnect(ui->toolSelector->model(), 0, this, SLOT(selectInitialTool())); ui->toolSelector->setCurrentIndex(matches.first()); toolSelected(); } void MainWindow::toolSelected() { ui->actionsMenu->clear(); QModelIndexList list = ui->toolSelector->selectionModel()->selectedRows(); int row = -1; if (list.count()) { row = list[0].row(); } if (row == -1) { return; } const QModelIndex mi = ui->toolSelector->model()->index(row, 0); QWidget *toolWidget = mi.data(ToolModelRole::ToolWidget).value(); if (!toolWidget) { toolWidget = createErrorPage(mi); ui->toolSelector->model()->setData(mi, QVariant::fromValue(toolWidget), ToolModelRole::ToolWidget); } Q_ASSERT(toolWidget); if (ui->toolStack->indexOf(toolWidget) < 0) { // newly created if (toolWidget->layout()) { #ifndef Q_OS_MAC toolWidget->layout()->setContentsMargins(11, 0, 0, 0); #else QMargins margins = toolWidget->layout()->contentsMargins(); margins.setLeft(0); toolWidget->layout()->setContentsMargins(margins); #endif } ui->toolStack->addWidget(toolWidget); } ui->toolStack->setCurrentIndex(ui->toolStack->indexOf(toolWidget)); foreach (QAction *action, toolWidget->actions()) { ui->actionsMenu->addAction(action); } ui->actionsMenu->setEnabled(!ui->actionsMenu->isEmpty()); } QWidget *MainWindow::createErrorPage(const QModelIndex &index) { QLabel *page = new QLabel(this); page->setAlignment(Qt::AlignCenter); // TODO show the actual plugin error message as well as any other useful information (eg. file name) we have, once the tool model has those page->setText(tr("Tool %1 failed to load.").arg(index.data(ToolModelRole::ToolId).toString())); return page; } void MainWindow::quitHost() { emit targetQuitRequested(); ObjectBroker::object()->quitHost(); } void MainWindow::detachProbe() { emit targetQuitRequested(); ObjectBroker::object()->detachProbe(); } gammaray-2.3.0/ui/mainwindow.h000066400000000000000000000034001255003167400162540ustar00rootroot00000000000000/* mainwindow.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MAINWINDOW_H #define GAMMARAY_MAINWINDOW_H #include class QModelIndex; namespace GammaRay { namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); signals: void targetQuitRequested(); private slots: void about(); void aboutPlugins(); void aboutKDAB(); void toolSelected(); void selectInitialTool(); void quitHost(); void detachProbe(); private: QWidget* createErrorPage(const QModelIndex &index); QScopedPointer ui; }; } #endif // MAINWINDOW_H gammaray-2.3.0/ui/mainwindow.ui000066400000000000000000000140031255003167400164430ustar00rootroot00000000000000 GammaRay::MainWindow 0 0 829 600 0 0 0 0 180 0 background-image: url(:/gammaray/kdab-gammaray-logo.png); background-repeat: no-repeat; background-attachment:fixed; background-position:bottom right; QFrame::NoFrame QFrame::Plain Qt::ElideRight QListView::TopToBottom false QListView::Fixed QListView::ListMode true false true 0 0 0 0 829 21 &GammaRay &Help &Actions Main Toolbar false Qt::BottomToolBarArea|Qt::TopToolBarArea false TopToolBarArea false &Detach Retract probe from application. QAction::ApplicationSpecificRole &Quit Quit probed application. QAction::QuitRole :/gammaray/GammaRay-32x32.png:/gammaray/GammaRay-32x32.png About &GammaRay QAction::AboutRole About &Qt QAction::AboutQtRole About &KDAB QAction::NoRole &Plugins... SidePane QListView
sidepane.h
gammaray-2.3.0/ui/methodinvocationdialog.cpp000066400000000000000000000044051255003167400211730ustar00rootroot00000000000000/* methodinvocationdialog.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodinvocationdialog.h" #include "ui_methodinvocationdialog.h" #include #include using namespace GammaRay; MethodInvocationDialog::MethodInvocationDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MethodInvocationDialog) { ui->setupUi(this); ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Invoke")); connect(ui->buttonBox, SIGNAL(accepted()), SLOT(accept())); connect(ui->buttonBox, SIGNAL(rejected()), SLOT(reject())); ui->connectionTypeComboBox->addItem(tr("Auto"), QVariant::fromValue(Qt::AutoConnection)); ui->connectionTypeComboBox->addItem(tr("Direct"), QVariant::fromValue(Qt::DirectConnection)); ui->connectionTypeComboBox->addItem(tr("Queued"), QVariant::fromValue(Qt::QueuedConnection)); } MethodInvocationDialog::~MethodInvocationDialog() { } Qt::ConnectionType MethodInvocationDialog::connectionType() const { return ui->connectionTypeComboBox->itemData(ui->connectionTypeComboBox->currentIndex()).value(); } void MethodInvocationDialog::setArgumentModel(QAbstractItemModel* model) { ui->argumentView->setModel(model); } gammaray-2.3.0/ui/methodinvocationdialog.h000066400000000000000000000032741255003167400206430ustar00rootroot00000000000000/* methodinvocationdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METHODINVOCATIONDIALOG_H #define GAMMARAY_METHODINVOCATIONDIALOG_H #include class QAbstractItemModel; namespace GammaRay { namespace Ui { class MethodInvocationDialog; } class MethodInvocationDialog : public QDialog { Q_OBJECT public: explicit MethodInvocationDialog(QWidget *parent = 0); ~MethodInvocationDialog(); Qt::ConnectionType connectionType() const; void setArgumentModel(QAbstractItemModel *model); private: QScopedPointer ui; }; } #endif // GAMMARAY_METHODINVOCATIONDIALOG_H gammaray-2.3.0/ui/methodinvocationdialog.ui000066400000000000000000000025001255003167400210200ustar00rootroot00000000000000 GammaRay::MethodInvocationDialog 0 0 400 300 &Connection type: connectionTypeComboBox false true QDialogButtonBox::Cancel|QDialogButtonBox::Ok gammaray-2.3.0/ui/palettemodel.cpp000066400000000000000000000124571255003167400171260ustar00rootroot00000000000000/* palettemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "palettemodel.h" #include #include using namespace GammaRay; struct role_t { const char *name; QPalette::ColorRole role; }; static const role_t paletteRoles[] = { { "Window", QPalette::Window }, { "WindowText", QPalette::WindowText }, { "Base", QPalette::Base }, { "AlternateBase", QPalette::AlternateBase }, { "Text", QPalette::Text }, { "ToolTipBase", QPalette::ToolTipBase }, { "ToolTipText", QPalette::ToolTipText }, { "Button", QPalette::Button }, { "ButtonText", QPalette::ButtonText }, { "BrightText", QPalette::BrightText }, { "Light", QPalette::Light }, { "Midlight", QPalette::Midlight }, { "Dark", QPalette::Dark }, { "Mid", QPalette::Mid }, { "Shadow", QPalette::Shadow }, { "Highlight", QPalette::Highlight }, { "HighlightedText", QPalette::HighlightedText }, { "Link", QPalette::Link }, { "LinkVisited", QPalette::LinkVisited } }; struct group_t { const char *name; QPalette::ColorGroup group; }; static const group_t paletteGroups[] = { { "Active", QPalette::Active }, { "Inactive", QPalette::Inactive }, { "Disabled", QPalette::Disabled }, }; PaletteModel::PaletteModel(QObject *parent) : QAbstractTableModel(parent), m_editable(false) { } QPalette PaletteModel::palette() const { return m_palette; } void PaletteModel::setPalette(const QPalette &palette) { beginResetModel(); m_palette = palette; endResetModel(); } void PaletteModel::setEditable(bool editable) { m_editable = editable; } QVariant PaletteModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DisplayRole) { if (index.column() == 0) { return paletteRoles[index.row()].name; } return m_palette.color(paletteGroups[index.column()-1].group, paletteRoles[index.row()].role).name(); } else if (role == Qt::EditRole) { // TODO return QBrush once we have an editor for that return m_palette.color(paletteGroups[index.column()-1].group, paletteRoles[index.row()].role); } else if (role == Qt::DecorationRole && index.column() != 0) { const QBrush brush = m_palette.brush(paletteGroups[index.column()-1].group, paletteRoles[index.row()].role); QPixmap pixmap(32, 32); QPainter painter(&pixmap); painter.fillRect(pixmap.rect(), Qt::black); painter.fillRect(pixmap.rect().adjusted(1, 1, -1, -1), brush); return QIcon(pixmap); } return QVariant(); } bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!m_editable) { return false; } if (index.isValid() && role == Qt::EditRole) { if (value.type() == QVariant::Color) { m_palette.setColor(paletteGroups[index.column()-1].group, paletteRoles[index.row()].role, value.value()); } else if (value.type() == QVariant::Brush) { m_palette.setBrush(paletteGroups[index.column()-1].group, paletteRoles[index.row()].role, value.value()); } } return QAbstractItemModel::setData(index, value, role); } int PaletteModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1 + sizeof(paletteGroups) / sizeof(paletteGroups[0]); } int PaletteModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return sizeof(paletteRoles) / sizeof(paletteRoles[0]); } QVariant PaletteModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return tr("Role"); } return paletteGroups[section-1].name; } return QAbstractItemModel::headerData(section, orientation, role); } Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const { const Qt::ItemFlags baseFlags = QAbstractItemModel::flags(index); if (m_editable && index.column() > 0) { return baseFlags | Qt::ItemIsEditable; } return baseFlags; } gammaray-2.3.0/ui/palettemodel.h000066400000000000000000000044001255003167400165600ustar00rootroot00000000000000/* palettemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PALETTEMODEL_H #define GAMMARAY_PALETTEMODEL_H #include #include namespace GammaRay { /** * @brief Model showing the content of a QPalette. */ class PaletteModel : public QAbstractTableModel { Q_OBJECT public: explicit PaletteModel(QObject *parent = 0); QPalette palette() const; void setPalette(const QPalette &palette); void setEditable(bool editable); ///@cond override QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; ///@endcond private: QPalette m_palette; bool m_editable; }; } #endif // GAMMARAY_PALETTEMODEL_H gammaray-2.3.0/ui/propertybinder.cpp000066400000000000000000000063541255003167400175160ustar00rootroot00000000000000/* propertybinder.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertybinder.h" #include #include using namespace GammaRay; PropertyBinder::PropertyBinder(QObject* source, const char* sourceProp, QObject* destination, const char* destProp): QObject(source), m_source(source), m_destination(destination), m_lock(false) { Q_ASSERT(source); Q_ASSERT(sourceProp); Q_ASSERT(destination); Q_ASSERT(destProp); const auto sourceIndex = source->metaObject()->indexOfProperty(sourceProp); m_sourceProperty = source->metaObject()->property(sourceIndex); Q_ASSERT(m_sourceProperty.isValid()); Q_ASSERT(m_sourceProperty.hasNotifySignal()); connect(source, QByteArray("2") + #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) m_sourceProperty.notifySignal().signature() #else m_sourceProperty.notifySignal().methodSignature() #endif , this, SLOT(sourceChanged())); const auto destIndex = destination->metaObject()->indexOfProperty(destProp); m_destinationProperty = destination->metaObject()->property(destIndex); Q_ASSERT(m_destinationProperty.isValid()); Q_ASSERT(m_destinationProperty.isWritable()); // initial sync const auto value = m_sourceProperty.read(source); m_destinationProperty.write(destination, m_sourceProperty.read(source)); // notification for reverse direction changes if (!m_destinationProperty.hasNotifySignal() || !m_sourceProperty.isWritable()) return; connect(destination, QByteArray("2") + #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) m_destinationProperty.notifySignal().signature() #else m_destinationProperty.notifySignal().methodSignature() #endif , this, SLOT(destinationChanged())); } PropertyBinder::~PropertyBinder() { } void PropertyBinder::sourceChanged() { if (!m_destination || m_lock) return; m_lock = true; m_destinationProperty.write(m_destination, m_sourceProperty.read(m_source)); m_lock = false; } void PropertyBinder::destinationChanged() { if (m_lock) return; m_lock = true; m_sourceProperty.write(m_source, m_destinationProperty.read(m_destination)); m_lock = false; } gammaray-2.3.0/ui/propertybinder.h000066400000000000000000000040041255003167400171510ustar00rootroot00000000000000/* propertybinder.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYBINDER_H #define GAMMARAY_PROPERTYBINDER_H #include "gammaray_ui_export.h" #include #include #include namespace GammaRay { /** Helper class to bind two properties together, similar to QML. */ class GAMMARAY_UI_EXPORT PropertyBinder : public QObject { Q_OBJECT public: /** Keeps @p sourceProp of @p source in sync with @p destProp of @p destination. * At least one property must have a change notification signal. */ explicit PropertyBinder(QObject *source, const char *sourceProp, QObject *destination, const char *destProp); ~PropertyBinder(); private slots: void sourceChanged(); void destinationChanged(); private: QObject* m_source; QPointer m_destination; QMetaProperty m_sourceProperty; QMetaProperty m_destinationProperty; bool m_lock; }; } #endif // GAMMARAY_PROPERTYBINDER_H gammaray-2.3.0/ui/propertyeditor/000077500000000000000000000000001255003167400170255ustar00rootroot00000000000000gammaray-2.3.0/ui/propertyeditor/palettedialog.cpp000066400000000000000000000034641255003167400223560ustar00rootroot00000000000000/* palettedialog.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "palettedialog.h" #include "ui_palettedialog.h" #include "palettemodel.h" #include "propertyeditor/propertyeditordelegate.h" #include #include using namespace GammaRay; PaletteDialog::PaletteDialog(const QPalette &palette, QWidget *parent) : QDialog(parent), ui(new Ui::PaletteDialog), m_model(new PaletteModel(this)) { ui->setupUi(this); m_model->setPalette(palette); m_model->setEditable(true); ui->paletteView->setModel(m_model); ui->paletteView->setItemDelegate(new PropertyEditorDelegate(this)); } PaletteDialog::~PaletteDialog() { delete ui; } QPalette PaletteDialog::editedPalette() const { return m_model->palette(); } gammaray-2.3.0/ui/propertyeditor/palettedialog.h000066400000000000000000000031611255003167400220150ustar00rootroot00000000000000/* palettedialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PALETTEDIALOG_H #define GAMMARAY_PALETTEDIALOG_H #include namespace GammaRay { class PropertyEditorFactory; class PaletteModel; namespace Ui { class PaletteDialog; } class PaletteDialog : public QDialog { Q_OBJECT public: explicit PaletteDialog(const QPalette &palette, QWidget *parent = 0); virtual ~PaletteDialog(); QPalette editedPalette() const; private: Ui::PaletteDialog *ui; PaletteModel *m_model; }; } #endif // GAMMARAY_PALETTEDIALOG_H gammaray-2.3.0/ui/propertyeditor/palettedialog.ui000066400000000000000000000032671255003167400222120ustar00rootroot00000000000000 GammaRay::PaletteDialog 0 0 400 300 Dialog false true Qt::Horizontal QDialogButtonBox::Close|QDialogButtonBox::Save buttonBox accepted() GammaRay::PaletteDialog accept() 248 254 157 274 buttonBox rejected() GammaRay::PaletteDialog reject() 316 260 286 274 gammaray-2.3.0/ui/propertyeditor/propertycoloreditor.cpp000066400000000000000000000027561255003167400236750ustar00rootroot00000000000000/* propertycoloreditor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertycoloreditor.h" #include using namespace GammaRay; PropertyColorEditor::PropertyColorEditor(QWidget *parent) : PropertyExtendedEditor(parent) { } void PropertyColorEditor::edit() { const QColor color = QColorDialog::getColor(value().value(), this); if (color.isValid()) { setValue(QVariant::fromValue(color)); } } gammaray-2.3.0/ui/propertyeditor/propertycoloreditor.h000066400000000000000000000030151255003167400233270ustar00rootroot00000000000000/* propertycoloreditor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYCOLOREDITOR_H #define GAMMARAY_PROPERTYCOLOREDITOR_H #include "propertyextendededitor.h" namespace GammaRay { /** Property editor for QColor. */ class PropertyColorEditor : public PropertyExtendedEditor { Q_OBJECT public: explicit PropertyColorEditor(QWidget *parent = 0); protected: void edit() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROPERTYCOLOREDITOR_H gammaray-2.3.0/ui/propertyeditor/propertydoublepaireditor.cpp000066400000000000000000000041361255003167400246770ustar00rootroot00000000000000/* propertydoublepaireditor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertydoublepaireditor.h" #include "ui_propertydoublepaireditor.h" using namespace GammaRay; PropertyDoublePairEditor::PropertyDoublePairEditor(QWidget *parent) : QWidget(parent), ui(new Ui::PropertyDoublePairEditor) { ui->setupUi(this); } PropertyDoublePairEditor::~PropertyDoublePairEditor() { } PropertyPointFEditor::PropertyPointFEditor(QWidget *parent) : PropertyDoublePairEditor(parent) { } QPointF PropertyPointFEditor::pointF() const { return QPointF(ui->xBox->value(), ui->yBox->value()); } void PropertyPointFEditor::setPointF(const QPointF &point) { ui->xBox->setValue(point.x()); ui->yBox->setValue(point.y()); } PropertySizeFEditor::PropertySizeFEditor(QWidget *parent) : PropertyDoublePairEditor(parent) { } QSizeF PropertySizeFEditor::sizeF() const { return QSizeF(ui->xBox->value(), ui->yBox->value()); } void PropertySizeFEditor::setSizeF(const QSizeF &size) { ui->xBox->setValue(size.width()); ui->yBox->setValue(size.height()); } gammaray-2.3.0/ui/propertyeditor/propertydoublepaireditor.h000066400000000000000000000042771255003167400243520ustar00rootroot00000000000000/* propertydoublepaireditor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYDOUBLEPAIREDITOR_H #define GAMMARAY_PROPERTYDOUBLEPAIREDITOR_H #include namespace GammaRay { namespace Ui { class PropertyDoublePairEditor; } /** Property editor for pairs of doubles, such as PointF and SizeF. */ class PropertyDoublePairEditor : public QWidget { Q_OBJECT public: explicit PropertyDoublePairEditor(QWidget *parent = 0); ~PropertyDoublePairEditor(); protected: QScopedPointer ui; }; class PropertyPointFEditor : public PropertyDoublePairEditor { Q_OBJECT Q_PROPERTY(QPointF pointF READ pointF WRITE setPointF USER true) public: explicit PropertyPointFEditor(QWidget *parent = 0); QPointF pointF() const; void setPointF(const QPointF &point); }; class PropertySizeFEditor : public PropertyDoublePairEditor { Q_OBJECT Q_PROPERTY(QSizeF sizeF READ sizeF WRITE setSizeF USER true) public: explicit PropertySizeFEditor(QWidget *parent = 0); QSizeF sizeF() const; void setSizeF(const QSizeF &size); }; } #endif // GAMMARAY_PROPERTYDOUBLEPAIREDITOR_H gammaray-2.3.0/ui/propertyeditor/propertydoublepaireditor.ui000066400000000000000000000026361255003167400245350ustar00rootroot00000000000000 GammaRay::PropertyDoublePairEditor 0 0 400 300 0 false -999999999.000000000000000 999999999.000000000000000 x Qt::AlignCenter false -999999999.000000000000000 999999999.000000000000000 gammaray-2.3.0/ui/propertyeditor/propertyeditordelegate.cpp000066400000000000000000000172341255003167400243260ustar00rootroot00000000000000/* propertyeditordelegate.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertyeditordelegate.h" #include "propertyeditorfactory.h" #include #include #include #include #include #include #include using namespace GammaRay; namespace { template struct matrix_trait {}; template <> struct matrix_trait { static const int rows = 4; static const int columns = 4; static qreal value(const QMatrix4x4 &matrix, int r, int c) { return matrix(r, c); } }; #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) template <> struct matrix_trait { static const int rows = 2; static const int columns = 1; static qreal value(const QVector2D &vec, int r, int) { return vec[r]; } }; template <> struct matrix_trait { static const int rows = 3; static const int columns = 1; static qreal value(const QVector3D &vec, int r, int) { return vec[r]; } }; template <> struct matrix_trait { static const int rows = 4; static const int columns = 1; static qreal value(const QVector4D &vec, int r, int) { return vec[r]; } }; #endif } PropertyEditorDelegate::PropertyEditorDelegate(QObject* parent): QStyledItemDelegate(parent) { setItemEditorFactory(PropertyEditorFactory::instance()); } PropertyEditorDelegate::~PropertyEditorDelegate() { } void PropertyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { editor->setProperty("displayString", index.data(Qt::DisplayRole)); QStyledItemDelegate::setEditorData(editor, index); } void PropertyEditorDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { const QVariant value = index.data(Qt::EditRole); if (value.canConvert()) { paint(painter, option, index, value.value()); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) } else if (value.canConvert()) { paint(painter, option, index, value.value()); } else if (value.canConvert()) { paint(painter, option, index, value.value()); } else if (value.canConvert()) { paint(painter, option, index, value.value()); #endif } else { QStyledItemDelegate::paint(painter, option, index); } } QSize PropertyEditorDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { const QVariant value = index.data(Qt::EditRole); if (value.canConvert()) { return sizeHint(option, index, value.value()); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) } else if (value.canConvert()) { return sizeHint(option, index, value.value()); } else if (value.canConvert()) { return sizeHint(option, index, value.value()); } else if (value.canConvert()) { return sizeHint(option, index, value.value()); #endif } return QStyledItemDelegate::sizeHint(option, index); } template void PropertyEditorDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index, const Matrix& matrix) const { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QStyleOptionViewItem opt = option; #else QStyleOptionViewItemV4 opt = option; #endif initStyleOption(&opt, index); opt.text.clear(); QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); QRect textRect = QApplication::style()->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget); const int textHMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; static const int textVMargin = 1; textRect = textRect.adjusted(textHMargin, textVMargin, -textHMargin, -textVMargin); static const int parenthesisLineWidth = 1; const int matrixSpacing = opt.fontMetrics.width("x"); const int matrixHMargin = matrixSpacing / 2; const int parenthesisWidth = qMax(matrixHMargin, 3); painter->save(); painter->setClipRect(textRect); painter->translate(textRect.topLeft()); painter->setPen(opt.palette.color(opt.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); int xOffset = 0; painter->drawLine(xOffset, 0, xOffset, textRect.height()); painter->drawLine(xOffset, 0, xOffset + parenthesisWidth, 0); painter->drawLine(xOffset, textRect.height() - 1, xOffset + parenthesisWidth, textRect.height() - 1); xOffset += matrixHMargin + parenthesisLineWidth; for (int col = 0; col < matrix_trait::columns; ++col) { const int colWidth = columnWidth(opt, matrix, col); for (int row = 0; row < matrix_trait::rows; ++row) { const QRect r(xOffset, row * opt.fontMetrics.lineSpacing(), colWidth, opt.fontMetrics.lineSpacing()); painter->drawText(r, Qt::AlignHCenter | Qt::AlignRight, QString::number(matrix_trait::value(matrix, row, col))); } xOffset += colWidth + matrixSpacing; } xOffset += -matrixSpacing + matrixHMargin; painter->drawLine(xOffset, 0, xOffset, textRect.height()); painter->drawLine(xOffset, 0, xOffset - parenthesisWidth, 0); painter->drawLine(xOffset, textRect.height() - 1, xOffset - parenthesisWidth, textRect.height() - 1); painter->restore(); } template QSize PropertyEditorDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex &index, const Matrix& matrix) const { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QStyleOptionViewItem opt = option; #else QStyleOptionViewItemV4 opt = option; #endif initStyleOption(&opt, index); static const int parenthesisLineWidth = 1; const int textHMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; static const int textVMargin = 1; int width = 0; for (int col = 0; col < matrix_trait::columns; ++col) width += columnWidth(opt, matrix, col); width += opt.fontMetrics.width("x") * matrix_trait::columns + 2 * parenthesisLineWidth + 2 * textHMargin; const int height = opt.fontMetrics.lineSpacing() * matrix_trait::rows + 2* textVMargin; return QSize(width, height); } template int PropertyEditorDelegate::columnWidth(const QStyleOptionViewItem& option, const Matrix &matrix, int column) const { int width = 0; for (int row = 0; row < matrix_trait::rows; ++row) width = qMax(width, option.fontMetrics.width(QString::number(matrix_trait::value(matrix, row, column)))); return width; } gammaray-2.3.0/ui/propertyeditor/propertyeditordelegate.h000066400000000000000000000044221255003167400237660ustar00rootroot00000000000000/* propertyeditordelegate.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYEDITORDELEGATE_H #define GAMMARAY_PROPERTYEDITORDELEGATE_H #include "gammaray_ui_export.h" #include class QMatrix4x4; namespace GammaRay { class GAMMARAY_UI_EXPORT PropertyEditorDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit PropertyEditorDelegate(QObject *parent); ~PropertyEditorDelegate(); void setEditorData(QWidget* editor, const QModelIndex& index) const Q_DECL_OVERRIDE; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const Q_DECL_OVERRIDE; private: template void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index, const Matrix &matrix) const; template QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex &index, const Matrix &matrix) const; template int columnWidth(const QStyleOptionViewItem& option, const Matrix& matrix, int column) const; }; } #endif // GAMMARAY_PROPERTYEDITORDELEGATE_H gammaray-2.3.0/ui/propertyeditor/propertyeditorfactory.cpp000066400000000000000000000063611255003167400242220ustar00rootroot00000000000000/* propertyeditorfactory.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertyeditorfactory.h" #include "propertycoloreditor.h" #include "propertyfonteditor.h" #include "propertyintpaireditor.h" #include "propertydoublepaireditor.h" #include "propertypaletteeditor.h" #include using namespace GammaRay; PropertyEditorFactory::PropertyEditorFactory() { initBuiltInTypes(); addEditor(QVariant::Color, new QStandardItemEditorCreator()); addEditor(QVariant::Font, new QStandardItemEditorCreator()); addEditor(QVariant::Palette, new QStandardItemEditorCreator()); addEditor(QVariant::Point, new QStandardItemEditorCreator()); addEditor(QVariant::PointF, new QStandardItemEditorCreator()); addEditor(QVariant::Size, new QStandardItemEditorCreator()); addEditor(QVariant::SizeF, new QStandardItemEditorCreator()); } PropertyEditorFactory* PropertyEditorFactory::instance() { static PropertyEditorFactory *s_instance = new PropertyEditorFactory; return s_instance; } QWidget *PropertyEditorFactory::createEditor(TypeId type, QWidget *parent) const { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) if (type == QMetaType::Float) type = QVariant::Double; #endif QWidget *w = QItemEditorFactory::createEditor(type, parent); if (!w) { return 0; } // the read-only view is still in the background usually, so transparency is not a good choice here w->setAutoFillBackground(true); return w; } QVector< int > PropertyEditorFactory::supportedTypes() { return instance()->m_supportedTypes; } void PropertyEditorFactory::initBuiltInTypes() { m_supportedTypes << QVariant::Bool << QVariant::Double << QVariant::Int << QVariant::UInt << QVariant::Date << QVariant::DateTime << QVariant::String << QVariant::Time; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_supportedTypes << QMetaType::Float; #endif } void PropertyEditorFactory::addEditor(PropertyEditorFactory::TypeId type, QItemEditorCreatorBase* creator) { registerEditor(type, creator); m_supportedTypes.push_back(type); } gammaray-2.3.0/ui/propertyeditor/propertyeditorfactory.h000066400000000000000000000037741255003167400236740ustar00rootroot00000000000000/* propertyeditorfactory.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYEDITORFACTORY_H #define GAMMARAY_PROPERTYEDITORFACTORY_H #include "gammaray_ui_export.h" #include #include namespace GammaRay { /** Item editor factory with support for extra types while keeping support for the built-in ones. */ class GAMMARAY_UI_EXPORT PropertyEditorFactory : public QItemEditorFactory { public: static PropertyEditorFactory *instance(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) typedef QVariant::Type TypeId; #else typedef int TypeId; #endif QWidget *createEditor(TypeId type, QWidget *parent) const Q_DECL_OVERRIDE; static QVector supportedTypes(); protected: PropertyEditorFactory(); private: void initBuiltInTypes(); void addEditor(TypeId type, QItemEditorCreatorBase *creator); QVector m_supportedTypes; }; } #endif // GAMMARAY_PROPERTYEDITORFACTORY_H gammaray-2.3.0/ui/propertyeditor/propertyextendededitor.cpp000066400000000000000000000035771255003167400243610ustar00rootroot00000000000000/* propertyextendededitor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertyextendededitor.h" #include "ui_propertyextendededitor.h" #include using namespace GammaRay; PropertyExtendedEditor::PropertyExtendedEditor(QWidget *parent) : QWidget(parent), ui(new Ui::PropertyExtendedEditor) { ui->setupUi(this); // TODO: make button content smaller by using a tiny icon connect(ui->editButton, SIGNAL(clicked()),SLOT(edit())); } PropertyExtendedEditor::~PropertyExtendedEditor() { delete ui; } QVariant PropertyExtendedEditor::value() const { return m_value; } void PropertyExtendedEditor::setValue(const QVariant &value) { m_value = value; const QString displayValue = property("displayString").toString(); ui->valueLabel->setText(displayValue.isEmpty() ? value.toString() : displayValue); } gammaray-2.3.0/ui/propertyeditor/propertyextendededitor.h000066400000000000000000000035351255003167400240200ustar00rootroot00000000000000/* propertyextendededitor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYEXTENDEDEDITOR_H #define GAMMARAY_PROPERTYEXTENDEDEDITOR_H #include #include namespace GammaRay { namespace Ui { class PropertyExtendedEditor; } /** Base class for property editors that open a separate dialog. */ class PropertyExtendedEditor : public QWidget { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue USER true) public: explicit PropertyExtendedEditor(QWidget *parent = 0); virtual ~PropertyExtendedEditor(); QVariant value() const; void setValue(const QVariant &value); protected slots: virtual void edit() = 0; private: Ui::PropertyExtendedEditor *ui; QVariant m_value; }; } #endif // GAMMARAY_PROPERTYEXTENDEDEDITOR_H gammaray-2.3.0/ui/propertyeditor/propertyextendededitor.ui000066400000000000000000000014351255003167400242030ustar00rootroot00000000000000 GammaRay::PropertyExtendedEditor 0 0 392 23 0 0 ... gammaray-2.3.0/ui/propertyeditor/propertyfonteditor.cpp000066400000000000000000000027301255003167400235150ustar00rootroot00000000000000/* propertyfonteditor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertyfonteditor.h" #include using namespace GammaRay; PropertyFontEditor::PropertyFontEditor(QWidget *parent) : PropertyExtendedEditor(parent) { } void PropertyFontEditor::edit() { bool ok = false; const QFont font = QFontDialog::getFont(&ok, value().value(), this); if (ok) { setValue(font); } } gammaray-2.3.0/ui/propertyeditor/propertyfonteditor.h000066400000000000000000000027441255003167400231670ustar00rootroot00000000000000/* propertyfonteditor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYFONTEDITOR_H #define GAMMARAY_PROPERTYFONTEDITOR_H #include "propertyextendededitor.h" namespace GammaRay { class PropertyFontEditor : public PropertyExtendedEditor { Q_OBJECT public: explicit PropertyFontEditor(QWidget *parent = 0); protected: void edit() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROPERTYFONTEDITOR_H gammaray-2.3.0/ui/propertyeditor/propertyintpaireditor.cpp000066400000000000000000000045031255003167400242150ustar00rootroot00000000000000/* propertyintpaireditor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertyintpaireditor.h" #include "ui_propertyintpaireditor.h" #include #include using namespace GammaRay; PropertyIntPairEditor::PropertyIntPairEditor(QWidget *parent) : QWidget(parent), ui(new Ui::PropertyIntPairEditor) { ui->setupUi(this); ui->xBox->setMinimum(std::numeric_limits::min()); ui->xBox->setMaximum(std::numeric_limits::max()); ui->yBox->setMinimum(std::numeric_limits::min()); ui->yBox->setMaximum(std::numeric_limits::max()); } PropertyIntPairEditor::~PropertyIntPairEditor() { } PropertyPointEditor::PropertyPointEditor(QWidget *parent) : PropertyIntPairEditor(parent) { } QPoint PropertyPointEditor::point() const { return QPoint(ui->xBox->value(), ui->yBox->value()); } void PropertyPointEditor::setPoint(const QPoint &point) { ui->xBox->setValue(point.x()); ui->yBox->setValue(point.y()); } PropertySizeEditor::PropertySizeEditor(QWidget *parent) : PropertyIntPairEditor(parent) { } QSize PropertySizeEditor::sizeValue() const { return QSize(ui->xBox->value(), ui->yBox->value()); } void PropertySizeEditor::setSizeValue(const QSize &size) { ui->xBox->setValue(size.width()); ui->yBox->setValue(size.height()); } gammaray-2.3.0/ui/propertyeditor/propertyintpaireditor.h000066400000000000000000000046021255003167400236620ustar00rootroot00000000000000/* propertyintpaireditor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYINTPAIREDITOR_H #define GAMMARAY_PROPERTYINTPAIREDITOR_H #include class QPoint; namespace GammaRay { namespace Ui { class PropertyIntPairEditor; } /** Property editor for QPoint, QSize and anything else consisting of two integer values. */ class PropertyIntPairEditor : public QWidget { Q_OBJECT public: explicit PropertyIntPairEditor(QWidget *parent = 0); ~PropertyIntPairEditor(); protected: QScopedPointer ui; }; /** Property editor for points. Since QStyledItemDelegate ignore valuePropertyName and insists on * USER properties we need one class per type here... */ class PropertyPointEditor : public PropertyIntPairEditor { Q_OBJECT Q_PROPERTY(QPoint point READ point WRITE setPoint USER true) public: explicit PropertyPointEditor(QWidget *parent = 0); QPoint point() const; void setPoint(const QPoint &point); }; /** Same again for size. */ class PropertySizeEditor : public PropertyIntPairEditor { Q_OBJECT Q_PROPERTY(QSize sizeValue READ sizeValue WRITE setSizeValue USER true) public: explicit PropertySizeEditor(QWidget *parent = 0); QSize sizeValue() const; void setSizeValue(const QSize &size); }; } #endif // GAMMARAY_PROPERTYINTPAIREDITOR_H gammaray-2.3.0/ui/propertyeditor/propertyintpaireditor.ui000066400000000000000000000022401255003167400240440ustar00rootroot00000000000000 GammaRay::PropertyIntPairEditor 0 0 145 22 0 false -99999 99999 x Qt::AlignCenter false gammaray-2.3.0/ui/propertyeditor/propertypaletteeditor.cpp000066400000000000000000000027531255003167400242120ustar00rootroot00000000000000/* propertypaletteeditor.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertypaletteeditor.h" #include "palettedialog.h" using namespace GammaRay; PropertyPaletteEditor::PropertyPaletteEditor(QWidget *parent) : PropertyExtendedEditor(parent) { } void PropertyPaletteEditor::edit() { PaletteDialog dlg(value().value(), this); if (dlg.exec() == QDialog::Accepted) { setValue(dlg.editedPalette()); } } gammaray-2.3.0/ui/propertyeditor/propertypaletteeditor.h000066400000000000000000000027661255003167400236630ustar00rootroot00000000000000/* propertypaletteeditor.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYPALETTEEDITOR_H #define GAMMARAY_PROPERTYPALETTEEDITOR_H #include "propertyextendededitor.h" namespace GammaRay { class PropertyPaletteEditor : public PropertyExtendedEditor { Q_OBJECT public: explicit PropertyPaletteEditor(QWidget *parent = 0); protected: void edit() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROPERTYPALETTEEDITOR_H gammaray-2.3.0/ui/propertywidget.cpp000066400000000000000000000073151255003167400175340ustar00rootroot00000000000000/* propertywidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertywidget.h" #include "common/endpoint.h" #include "common/objectbroker.h" #include "common/propertycontrollerinterface.h" using namespace GammaRay; QVector PropertyWidget::s_tabFactories = QVector(); QVector PropertyWidget::s_propertyWidgets; PropertyWidget::PropertyWidget(QWidget *parent) : QTabWidget(parent), m_controller(0) { s_propertyWidgets.push_back(this); } PropertyWidget::~PropertyWidget() { const int index = s_propertyWidgets.indexOf(this); if (index >= 0) s_propertyWidgets.remove(index); } QString PropertyWidget::objectBaseName() const { Q_ASSERT(!m_objectBaseName.isEmpty()); return m_objectBaseName; } void PropertyWidget::setObjectBaseName(const QString &baseName) { Q_ASSERT(m_objectBaseName.isEmpty()); // ideally the object base name would be a ctor argument, but then this doesn't work in Designer anymore m_objectBaseName = baseName; if (Endpoint::instance()->objectAddress(baseName + ".controller") == Protocol::InvalidObjectAddress) return; // unknown property controller, likely disabled/not supported on the server if (m_controller) { disconnect(m_controller, SIGNAL(availableExtensionsChanged()), this, SLOT(updateShownTabs())); } m_controller = ObjectBroker::object(m_objectBaseName + ".controller"); connect(m_controller, SIGNAL(availableExtensionsChanged()), this, SLOT(updateShownTabs())); updateShownTabs(); } void PropertyWidget::createWidgets() { if (m_objectBaseName.isEmpty()) return; foreach (PropertyWidgetTabFactoryBase *factory, s_tabFactories) { if (!m_usedFactories.contains(factory) && extensionAvailable(factory)) { QWidget *widget = factory->createWidget(this); m_usedFactories.push_back(factory); m_tabWidgets.push_back(widget); addTab(widget, factory->label()); } } } void PropertyWidget::updateShownTabs() { setUpdatesEnabled(false); createWidgets(); Q_ASSERT(m_tabWidgets.size() == m_usedFactories.size()); for (int i = 0; i < m_tabWidgets.size(); ++i) { QWidget *widget = m_tabWidgets.at(i); const int index = indexOf(widget); auto factory = m_usedFactories.at(i); if (extensionAvailable(factory)) { if (index == -1) addTab(widget, factory->label()); } else if (index != -1) { removeTab(index); } } setUpdatesEnabled(true); } bool PropertyWidget::extensionAvailable(PropertyWidgetTabFactoryBase* factory) const { return m_controller->availableExtensions().contains(m_objectBaseName + '.' + factory->name()); } gammaray-2.3.0/ui/propertywidget.h000066400000000000000000000053161255003167400172000ustar00rootroot00000000000000/* propertywidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTYWIDGET_H #define GAMMARAY_PROPERTYWIDGET_H #include #include #include #include "gammaray_ui_export.h" #include #include "propertywidgettab.h" class QAbstractItemModel; class QAbstractItemView; class QModelIndex; namespace GammaRay { class Ui_PropertyWidget; class PropertyControllerInterface; /** @brief Client-side counter-part GammaRay::PropertyController. */ class GAMMARAY_UI_EXPORT PropertyWidget : public QTabWidget { Q_OBJECT public: explicit PropertyWidget(QWidget *parent = 0); virtual ~PropertyWidget(); QString objectBaseName() const; void setObjectBaseName(const QString &baseName); template static void registerTab(QString name, QString label) { s_tabFactories << new PropertyWidgetTabFactory(name, label); foreach (PropertyWidget *widget, s_propertyWidgets) widget->createWidgets(); } private: void createWidgets(); bool extensionAvailable(PropertyWidgetTabFactoryBase *factory) const; private slots: void updateShownTabs(); private: QString m_objectBaseName; // Contains all tab widgets we have instantiated and their corresponding factories // order matters, therefore these are two vectors rather than a hash or map QVector m_usedFactories; QVector m_tabWidgets; PropertyControllerInterface *m_controller; static QVector s_tabFactories; static QVector s_propertyWidgets; }; } #endif // GAMMARAY_PROPERTYWIDGET_H gammaray-2.3.0/ui/propertywidgettab.h000066400000000000000000000042521255003167400176650ustar00rootroot00000000000000/* propertywidgettab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PROPERTYWIDGETTAB_H #define PROPERTYWIDGETTAB_H #include #include namespace GammaRay { class PropertyWidget; /** @brief Interface for tabs in the property widget. */ class PropertyWidgetTabFactoryBase { public: explicit PropertyWidgetTabFactoryBase() {} virtual QWidget *createWidget(PropertyWidget *parent) = 0; virtual const QString &name() const = 0; virtual const QString &label() const = 0; }; /** @brief Template implementation of PropertyWidgetTabFactoryBase. */ template class PropertyWidgetTabFactory : public PropertyWidgetTabFactoryBase { public: explicit PropertyWidgetTabFactory(const QString &name, const QString &label) : m_name(name), m_label(label) { } QWidget *createWidget(PropertyWidget *parent) { return new T(parent); } const QString &name() const { return m_name; } const QString &label() const { return m_label; } private: QString m_name; QString m_label; }; } #endif // PROPERTYWIDGETTAB_H gammaray-2.3.0/ui/proxytooluifactory.cpp000066400000000000000000000036371255003167400204540ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "proxytooluifactory.h" #include using namespace GammaRay; ProxyToolUiFactory::ProxyToolUiFactory(const PluginInfo &pluginInfo, QObject *parent) : ProxyFactory(pluginInfo, parent) { } bool ProxyToolUiFactory::isValid() const { return pluginInfo().isValid(); } bool ProxyToolUiFactory::remotingSupported() const { return pluginInfo().remoteSupport(); } QWidget *ProxyToolUiFactory::createWidget(QWidget *parentWidget) { loadPlugin(); ToolUiFactory *fac = factory(); if (!fac) { return new QLabel(tr("Plugin '%1' could not be loaded.").arg(pluginInfo().path()), parentWidget); } Q_ASSERT(fac); return fac->createWidget(parentWidget); } void ProxyToolUiFactory::initUi() { loadPlugin(); ToolUiFactory *fac = factory(); if (!fac) return; return fac->initUi(); } gammaray-2.3.0/ui/proxytooluifactory.h000066400000000000000000000037221255003167400201140ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROXYTOOLUIFACTORY_H #define GAMMARAY_PROXYTOOLUIFACTORY_H #include #include namespace GammaRay { /** * A wrapper around a plugin ToolUiFactory that only loads the actual plugin once really needed. * Until then, meta-data is provided based on a plugin spec file. */ class ProxyToolUiFactory : public ProxyFactory { public: /** * @param path Path to the plugin spec file */ explicit ProxyToolUiFactory(const PluginInfo &pluginInfo, QObject *parent = 0); /** Returns @c true if the plugin seems valid from all the information we have so far. */ bool isValid() const; bool remotingSupported() const Q_DECL_OVERRIDE; QWidget *createWidget(QWidget *parentWidget) Q_DECL_OVERRIDE; void initUi() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROXYTOOLUIFACTORY_H gammaray-2.3.0/ui/sidepane.cpp000066400000000000000000000050731255003167400162330ustar00rootroot00000000000000/* sidepane.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sidepane.h" #include #include using namespace GammaRay; class Delegate : public QStyledItemDelegate { public: explicit Delegate(QObject *parent = 0) : QStyledItemDelegate(parent) { } virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { static const int heightMargin = 10; QSize size = QStyledItemDelegate::sizeHint(option, index); size.setHeight(size.height() + heightMargin); return size; } }; SidePane::SidePane(QWidget *parent) : QListView(parent) { viewport()->setAutoFillBackground(false); setAttribute(Qt::WA_MacShowFocusRect, false); setItemDelegate(new Delegate(this)); } SidePane::~SidePane() { } QSize SidePane::sizeHint() const { static const int widthMargin = 10; if (!model()) { return QSize(0, 0); } const int width = sizeHintForColumn(0) + widthMargin; const int height = QListView::sizeHint().height(); return QSize(width, height); } void SidePane::setModel(QAbstractItemModel *model) { if (model) { connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(updateSizeHint())); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(updateSizeHint())); } QAbstractItemView::setModel(model); } void SidePane::resizeEvent(QResizeEvent *e) { updateSizeHint(); QListView::resizeEvent(e); } void SidePane::updateSizeHint() { setMinimumWidth(sizeHint().width()); } gammaray-2.3.0/ui/sidepane.h000066400000000000000000000031051255003167400156720ustar00rootroot00000000000000/* sidepane.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SIDEPANE_H #define GAMMARAY_SIDEPANE_H #include namespace GammaRay { class SidePane : public QListView { Q_OBJECT public: explicit SidePane(QWidget *parent = 0); ~SidePane(); QSize sizeHint() const Q_DECL_OVERRIDE; void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE; protected: void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE; private slots: void updateSizeHint(); }; } #endif // GAMMARAY_SIDEPANE_H gammaray-2.3.0/ui/splashscreen.cpp000066400000000000000000000030031255003167400171240ustar00rootroot00000000000000/* attachdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "splashscreen.h" #include #include QSplashScreen *splash = 0; namespace GammaRay { void showSplashScreen() { if (!splash) { QPixmap pixmap(QLatin1String(":gammaray/splashscreen.png")); splash = new QSplashScreen(pixmap); splash->setMask(pixmap.mask()); } splash->show(); } void hideSplashScreen() { if (splash) { splash->hide(); } } } gammaray-2.3.0/ui/splashscreen.h000066400000000000000000000025351255003167400166020ustar00rootroot00000000000000/* attachdialog.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_SPLASHSCREEN_H #define GAMMARAY_SPLASHSCREEN_H #include "gammaray_ui_export.h" namespace GammaRay { GAMMARAY_UI_EXPORT void showSplashScreen(); GAMMARAY_UI_EXPORT void hideSplashScreen(); } #endif // SPLASHSCREEN_H gammaray-2.3.0/ui/tools/000077500000000000000000000000001255003167400150725ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/connectioninspector/000077500000000000000000000000001255003167400211605ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/connectioninspector/connectioninspectorwidget.cpp000066400000000000000000000041201255003167400271530ustar00rootroot00000000000000/* connectioninspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectioninspectorwidget.h" #include "ui_connectioninspectorwidget.h" #include #include #include using namespace GammaRay; ConnectionInspectorWidget::ConnectionInspectorWidget(QWidget* parent) : QWidget(parent), ui(new Ui::ConnectionInspectorWidget) { ui->setupUi(this); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); // TODO: 1.3 had a proxy detacher here, to improve performance proxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.ConnectionModel")); ui->connectionSearchLine->setProxy(proxy); ui->connectionView->setModel(proxy); if (qgetenv("GAMMARAY_TEST_FILTER") == "1") { QMetaObject::invokeMethod(ui->connectionSearchLine->lineEdit(), "setText", Qt::QueuedConnection, Q_ARG(QString, QLatin1String("destroyed"))); } } ConnectionInspectorWidget::~ConnectionInspectorWidget() { } gammaray-2.3.0/ui/tools/connectioninspector/connectioninspectorwidget.h000066400000000000000000000031301255003167400266200ustar00rootroot00000000000000/* connectioninspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONINSPECTORWIDGET_H #define GAMMARAY_CONNECTIONINSPECTORWIDGET_H #include namespace GammaRay { namespace Ui { class ConnectionInspectorWidget; } class ConnectionInspectorWidget : public QWidget { Q_OBJECT public: explicit ConnectionInspectorWidget(QWidget *parent = 0); ~ConnectionInspectorWidget(); private: QScopedPointer ui; }; } #endif // GAMMARAY_CONNECTIONINSPECTORWIDGET_H gammaray-2.3.0/ui/tools/connectioninspector/connectioninspectorwidget.ui000066400000000000000000000016631255003167400270170ustar00rootroot00000000000000 GammaRay::ConnectionInspectorWidget 0 0 400 300 true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/localeinspector/000077500000000000000000000000001255003167400202605ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/localeinspector/localeinspectorwidget.cpp000066400000000000000000000052611255003167400253620ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "localeinspectorwidget.h" #include "ui_localeinspectorwidget.h" #include #include using namespace GammaRay; LocaleInspectorWidget::LocaleInspectorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::LocaleInspectorWidget) { QAbstractItemModel *localeModel = ObjectBroker::model("com.kdab.GammaRay.LocaleModel"); QAbstractItemModel *accessorModel = ObjectBroker::model("com.kdab.GammaRay.LocaleAccessorModel"); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setSourceModel(localeModel); ui->setupUi(this); ui->localeTable->setModel(proxy); ui->accessorTable->setModel(accessorModel); ui->localeSearchLine->setProxy(proxy); ui->accessorTable->resizeColumnsToContents(); ui->localeTable->resizeColumnsToContents(); connect(localeModel, SIGNAL(modelReset()), ui->localeTable, SLOT(resizeColumnsToContents())); connect(accessorModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), ui->accessorTable, SLOT(resizeColumnsToContents())); QMetaObject::invokeMethod(this, "initSplitterPosition", Qt::QueuedConnection); connect(accessorModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(initSplitterPosition())); } LocaleInspectorWidget::~LocaleInspectorWidget() { } void LocaleInspectorWidget::initSplitterPosition() { const int accessorHeight = ui->accessorTable->model()->rowCount() * (ui->accessorTable->rowHeight(0) + 1) // + grid line + 2 * ui->accessorTable->frameWidth(); ui->splitter->setSizes(QList() << accessorHeight << height() - accessorHeight); } gammaray-2.3.0/ui/tools/localeinspector/localeinspectorwidget.h000066400000000000000000000031541255003167400250260ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2011-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_LOCALEINSPECTOR_LOCALEINSPECTORWIDGET_H #define GAMMARAY_LOCALEINSPECTOR_LOCALEINSPECTORWIDGET_H #include namespace GammaRay { namespace Ui { class LocaleInspectorWidget; } class LocaleInspectorWidget : public QWidget { Q_OBJECT public: explicit LocaleInspectorWidget(QWidget *parent = 0); ~LocaleInspectorWidget(); private slots: void initSplitterPosition(); private: QScopedPointer ui; }; } #endif // GAMMARAY_LOCALEINSPECTORWIDGET_H gammaray-2.3.0/ui/tools/localeinspector/localeinspectorwidget.ui000066400000000000000000000035471255003167400252220ustar00rootroot00000000000000 GammaRay::LocaleInspectorWidget 0 0 654 506 0 Qt::Vertical QAbstractItemView::NoSelection false false false 0 true false KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/messagehandler/000077500000000000000000000000001255003167400200545ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/messagehandler/messagehandlerclient.cpp000066400000000000000000000024361255003167400247460ustar00rootroot00000000000000/* messagehandlerclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagehandlerclient.h" using namespace GammaRay; MessageHandlerClient::MessageHandlerClient(QObject *parent) : MessageHandlerInterface(parent) { } gammaray-2.3.0/ui/tools/messagehandler/messagehandlerclient.h000066400000000000000000000030151255003167400244050ustar00rootroot00000000000000/* messagehandlerclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEHANDLERCLIENT_H #define GAMMARAY_MESSAGEHANDLERCLIENT_H #include namespace GammaRay { class MessageHandlerClient : public MessageHandlerInterface { Q_OBJECT Q_INTERFACES(GammaRay::MessageHandlerInterface) public: explicit MessageHandlerClient(QObject *parent = 0); }; } #endif // GAMMARAY_MESSAGEHANDLERCLIENT_H gammaray-2.3.0/ui/tools/messagehandler/messagehandlerwidget.cpp000066400000000000000000000114061255003167400247500ustar00rootroot00000000000000/* messagehandlerwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "messagehandlerwidget.h" #include "ui_messagehandlerwidget.h" #include #include #include "messagehandlerclient.h" #include #include #include #include #include #include #include #include #include #include using namespace GammaRay; static QObject *createClientMessageHandler(const QString &/*name*/, QObject *parent) { return new MessageHandlerClient(parent); } MessageHandlerWidget::MessageHandlerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MessageHandlerWidget) { ObjectBroker::registerClientObjectFactoryCallback(createClientMessageHandler); MessageHandlerInterface *handler = ObjectBroker::object(); connect(handler, SIGNAL(fatalMessageReceived(QString,QString,QTime,QStringList)), this, SLOT(fatalMessageReceived(QString,QString,QTime,QStringList))); ui->setupUi(this); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.MessageModel")); ui->messageSearchLine->setProxy(proxy); ui->messageView->setModel(proxy); ui->messageView->setIndentation(0); ui->messageView->setSortingEnabled(true); ///FIXME: implement this ui->backtraceView->hide(); } MessageHandlerWidget::~MessageHandlerWidget() { } void MessageHandlerWidget::fatalMessageReceived(const QString &app, const QString &message, const QTime &time, const QStringList &backtrace) { if (Endpoint::isConnected() && !qobject_cast(ObjectBroker::object())) { // only show on remote side return; } QDialog dlg; dlg.setWindowTitle(QObject::tr("QFatal in %1 at %2").arg(app).arg(time.toString())); QGridLayout *layout = new QGridLayout; QLabel *iconLabel = new QLabel; QIcon icon = dlg.style()->standardIcon(QStyle::SP_MessageBoxCritical, 0, &dlg); int iconSize = dlg.style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, &dlg); iconLabel->setPixmap(icon.pixmap(iconSize, iconSize)); iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); layout->addWidget(iconLabel, 0, 0); QLabel *errorLabel = new QLabel; errorLabel->setTextFormat(Qt::PlainText); errorLabel->setWordWrap(true); errorLabel->setText(message); layout->addWidget(errorLabel, 0, 1); QDialogButtonBox *buttons = new QDialogButtonBox; if (!backtrace.isEmpty()) { QListWidget *backtraceWidget = new QListWidget; foreach (const QString &frame, backtrace) { backtraceWidget->addItem(frame); } layout->addWidget(backtraceWidget, 1, 0, 1, 2); QPushButton *copyBacktraceButton = new QPushButton(tr("Copy Backtrace")); buttons->addButton(copyBacktraceButton, QDialogButtonBox::ActionRole); QSignalMapper *mapper = new QSignalMapper(this); mapper->setMapping(copyBacktraceButton, backtrace.join(QLatin1String("\n"))); connect(copyBacktraceButton, SIGNAL(clicked()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(QString)), this, SLOT(copyToClipboard(QString))); } buttons->addButton(QDialogButtonBox::Close); QObject::connect(buttons, SIGNAL(accepted()), &dlg, SLOT(accept())); QObject::connect(buttons, SIGNAL(rejected()), &dlg, SLOT(reject())); layout->addWidget(buttons, 2, 0, 1, 2); dlg.setLayout(layout); dlg.adjustSize(); dlg.exec(); } void MessageHandlerWidget::copyToClipboard(const QString &message) { QApplication::clipboard()->setText(message); } gammaray-2.3.0/ui/tools/messagehandler/messagehandlerwidget.h000066400000000000000000000034151255003167400244160ustar00rootroot00000000000000/* messagehandlerwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MESSAGEHANDLERWIDGET_H #define GAMMARAY_MESSAGEHANDLERWIDGET_H #include class QTime; namespace GammaRay { namespace Ui { class MessageHandlerWidget; } class MessageHandlerWidget : public QWidget { Q_OBJECT public: explicit MessageHandlerWidget(QWidget *parent = 0); ~MessageHandlerWidget(); private slots: void fatalMessageReceived(const QString &app, const QString &message, const QTime &time, const QStringList &backtrace); void copyToClipboard(const QString &message); private: QScopedPointer ui; }; } #endif // MESSAGEHANDLERWIDGET_H gammaray-2.3.0/ui/tools/messagehandler/messagehandlerwidget.ui000066400000000000000000000022601255003167400246010ustar00rootroot00000000000000 GammaRay::MessageHandlerWidget 0 0 400 300 Qt::Horizontal KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
1
gammaray-2.3.0/ui/tools/metaobjectbrowser/000077500000000000000000000000001255003167400206135ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/metaobjectbrowser/metaobjectbrowserwidget.cpp000066400000000000000000000054231255003167400262500ustar00rootroot00000000000000/* metaobjectbrowserwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metaobjectbrowserwidget.h" #include "propertywidget.h" #include "deferredresizemodesetter.h" #include #include "kde/kfilterproxysearchline.h" #include "kde/krecursivefilterproxymodel.h" #include #include #include #include #include using namespace GammaRay; MetaObjectBrowserWidget::MetaObjectBrowserWidget(QWidget *parent) : QWidget(parent) { QAbstractItemModel *model = ObjectBroker::model("com.kdab.GammaRay.MetaObjectModel"); QSortFilterProxyModel *objectFilter = new KRecursiveFilterProxyModel(this); objectFilter->setSourceModel(model); objectFilter->setDynamicSortFilter(true); QTreeView *treeView = new QTreeView(this); treeView->setIndentation(10); treeView->setUniformRowHeights(true); treeView->setModel(objectFilter); new DeferredResizeModeSetter(treeView->header(), 0, QHeaderView::Stretch); treeView->setSortingEnabled(true); treeView->setSelectionModel(ObjectBroker::selectionModel(objectFilter)); KFilterProxySearchLine *objectSearchLine = new KFilterProxySearchLine(this); objectSearchLine->setProxy(objectFilter); PropertyWidget *propertyWidget = new PropertyWidget(this); m_propertyWidget = propertyWidget; m_propertyWidget->setObjectBaseName("com.kdab.GammaRay.MetaObjectBrowser"); QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(objectSearchLine); vbox->addWidget(treeView); QHBoxLayout *hbox = new QHBoxLayout(this); hbox->addLayout(vbox); hbox->addWidget(propertyWidget); // init widget new DeferredTreeViewConfiguration(treeView); treeView->sortByColumn(0, Qt::AscendingOrder); } gammaray-2.3.0/ui/tools/metaobjectbrowser/metaobjectbrowserwidget.h000066400000000000000000000027701255003167400257170ustar00rootroot00000000000000/* metaobjectbrowserwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Kevin Funk Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METAOBJECTBROWSERWIDGET_H #define GAMMARAY_METAOBJECTBROWSERWIDGET_H #include namespace GammaRay { class PropertyWidget; class MetaObjectBrowserWidget : public QWidget { Q_OBJECT public: explicit MetaObjectBrowserWidget(QWidget *parent = 0); private: PropertyWidget *m_propertyWidget; }; } #endif // GAMMARAY_METAOBJECTBROWSERWIDGET_H gammaray-2.3.0/ui/tools/metatypebrowser/000077500000000000000000000000001255003167400203265ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/metatypebrowser/metatypebrowserwidget.cpp000066400000000000000000000037421255003167400255000ustar00rootroot00000000000000/* metatypebrowserwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "metatypebrowserwidget.h" #include #include "ui_metatypebrowserwidget.h" #include #include using namespace GammaRay; MetaTypeBrowserWidget::MetaTypeBrowserWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MetaTypeBrowserWidget) { ui->setupUi(this); QAbstractItemModel *mtm = ObjectBroker::model("com.kdab.GammaRay.MetaTypeModel"); Q_ASSERT(mtm); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setSourceModel(mtm); ui->metaTypeView->setModel(proxy); new DeferredResizeModeSetter(ui->metaTypeView->header(), 0, QHeaderView::ResizeToContents); ui->metaTypeSearchLine->setProxy(proxy); ui->metaTypeView->header()->setSortIndicator(1, Qt::AscendingOrder); // sort by type id } MetaTypeBrowserWidget::~MetaTypeBrowserWidget() { } gammaray-2.3.0/ui/tools/metatypebrowser/metatypebrowserwidget.h000066400000000000000000000030641255003167400251420ustar00rootroot00000000000000/* metatypebrowserwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METATYPEBROWSERWIDGET_H #define GAMMARAY_METATYPEBROWSERWIDGET_H #include namespace GammaRay { namespace Ui { class MetaTypeBrowserWidget; } class MetaTypeBrowserWidget : public QWidget { Q_OBJECT public: explicit MetaTypeBrowserWidget(QWidget *parent = 0); ~MetaTypeBrowserWidget(); private: QScopedPointer ui; }; } #endif // GAMMARAY_METATYPEBROWSERWIDGET_H gammaray-2.3.0/ui/tools/metatypebrowser/metatypebrowserwidget.ui000066400000000000000000000021111255003167400253200ustar00rootroot00000000000000 GammaRay::MetaTypeBrowserWidget 0 0 400 300 0 false true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/mimetypes/000077500000000000000000000000001255003167400171065ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/mimetypes/mimetypeswidget.cpp000066400000000000000000000037511255003167400230400ustar00rootroot00000000000000/* mimetypeswidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mimetypeswidget.h" #include "ui_mimetypeswidget.h" #include #include #include using namespace GammaRay; MimeTypesWidget::MimeTypesWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MimeTypesWidget) { ui->setupUi(this); QSortFilterProxyModel *proxy = new KRecursiveFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.MimeTypeModel")); ui->mimeTypeView->setModel(proxy); new DeferredResizeModeSetter(ui->mimeTypeView->header(), 0, QHeaderView::ResizeToContents); new DeferredResizeModeSetter(ui->mimeTypeView->header(), 1, QHeaderView::ResizeToContents); ui->mimeTypeView->sortByColumn(0, Qt::AscendingOrder); ui->searchLine->setProxy(proxy); } MimeTypesWidget::~MimeTypesWidget() { } gammaray-2.3.0/ui/tools/mimetypes/mimetypeswidget.h000066400000000000000000000027761255003167400225130ustar00rootroot00000000000000/* mimetypeswidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MIMETYPESWIDGET_H #define GAMMARAY_MIMETYPESWIDGET_H #include namespace GammaRay { namespace Ui { class MimeTypesWidget; } class MimeTypesWidget : public QWidget { Q_OBJECT public: explicit MimeTypesWidget(QWidget *parent = 0); ~MimeTypesWidget(); private: QScopedPointer ui; }; } #endif // GAMMARAY_MIMETYPESWIDGET_H gammaray-2.3.0/ui/tools/mimetypes/mimetypeswidget.ui000066400000000000000000000016221255003167400226660ustar00rootroot00000000000000 GammaRay::MimeTypesWidget 0 0 400 300 0 true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/modelinspector/000077500000000000000000000000001255003167400201215ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/modelinspector/modelinspectorclient.cpp000066400000000000000000000025201255003167400250520ustar00rootroot00000000000000/* modelinspectorclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelinspectorclient.h" using namespace GammaRay; ModelInspectorClient::ModelInspectorClient(QObject *parent) : ModelInspectorInterface(parent) { } ModelInspectorClient::~ModelInspectorClient() { } gammaray-2.3.0/ui/tools/modelinspector/modelinspectorclient.h000066400000000000000000000030371255003167400245230ustar00rootroot00000000000000/* modelinspectorclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTORCLIENT_H #define GAMMARAY_MODELINSPECTORCLIENT_H #include namespace GammaRay { class ModelInspectorClient : public ModelInspectorInterface { Q_OBJECT Q_INTERFACES(GammaRay::ModelInspectorInterface) public: explicit ModelInspectorClient(QObject *parent = 0); virtual ~ModelInspectorClient(); }; } #endif // GAMMARAY_MODELINSPECTORCLIENT_H gammaray-2.3.0/ui/tools/modelinspector/modelinspectorwidget.cpp000066400000000000000000000114631255003167400250650ustar00rootroot00000000000000/* modelinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelinspectorwidget.h" #include "ui_modelinspectorwidget.h" #include "modelinspectorclient.h" #include #include #include #include #include #include using namespace GammaRay; static QObject* createModelInspectorClient(const QString & /*name*/, QObject *parent) { return new ModelInspectorClient(parent); } ModelInspectorWidget::ModelInspectorWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::ModelInspectorWidget) , m_interface(0) { ui->setupUi(this); ObjectBroker::registerClientObjectFactoryCallback(createModelInspectorClient); m_interface = ObjectBroker::object(); connect(m_interface, SIGNAL(cellSelected(int,int,QString,QString)), SLOT(cellSelected(int,int,QString,QString))); KRecursiveFilterProxyModel *modelFilterProxy = new KRecursiveFilterProxyModel(this); modelFilterProxy->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.ModelModel")); ui->modelView->setModel(modelFilterProxy); ui->modelView->setSelectionModel(ObjectBroker::selectionModel(modelFilterProxy)); ui->modelSearchLine->setProxy(modelFilterProxy); connect(ui->modelView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(modelSelected(QItemSelection))); new DeferredResizeModeSetter(ui->modelView->header(), 0, QHeaderView::ResizeToContents); ui->modelCellView->setModel(ObjectBroker::model("com.kdab.GammaRay.ModelCellModel")); cellSelected(-1, -1, QString(), QString()); } ModelInspectorWidget::~ModelInspectorWidget() { } void ModelInspectorWidget::modelSelected(const QItemSelection& selected) { QModelIndex index; if (selected.size() >= 1) index = selected.first().topLeft(); if (index.isValid()) { QObject *obj = index.data(ObjectModel::ObjectRole).value(); QAbstractItemModel *model = qobject_cast(obj); if (model) { // we are on the server side ui->modelContentView->setModel(model); if (ObjectBroker::hasSelectionModel(ui->modelContentView->model())) setupModelContentSelectionModel(); connect(Endpoint::instance(), SIGNAL(objectRegistered(QString,Protocol::ObjectAddress)), this, SLOT(objectRegistered(QString)), Qt::UniqueConnection); } else { // we are on the client side model = ObjectBroker::model("com.kdab.GammaRay.ModelContent"); ui->modelContentView->setModel(model); setupModelContentSelectionModel(); } // in case selection is not directly triggered by the user ui->modelView->scrollTo(index, QAbstractItemView::EnsureVisible); } else { ui->modelContentView->setModel(0); } // clear the cell info box cellSelected(-1, -1, QString(), QString()); } void ModelInspectorWidget::cellSelected(int row, int column, const QString &internalId, const QString &internalPtr) { ui->indexLabel->setText(row != -1 ? tr("Row: %1 Column: %2").arg(row).arg(column) : tr("Invalid")); ui->internalIdLabel->setText(internalId); ui->internalPtrLabel->setText(internalPtr); } void ModelInspectorWidget::objectRegistered(const QString& objectName) { if (objectName == "com.kdab.GammaRay.ModelContent.selection") // delay, since it's not registered yet when the signal is emitted QMetaObject::invokeMethod(this, "setupModelContentSelectionModel", Qt::QueuedConnection); } void ModelInspectorWidget::setupModelContentSelectionModel() { if (!ui->modelContentView->model()) return; ui->modelContentView->setSelectionModel(ObjectBroker::selectionModel(ui->modelContentView->model())); } gammaray-2.3.0/ui/tools/modelinspector/modelinspectorwidget.h000066400000000000000000000037141255003167400245320ustar00rootroot00000000000000/* modelinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_MODELINSPECTOR_MODELINSPECTORWIDGET_H #define GAMMARAY_MODELINSPECTOR_MODELINSPECTORWIDGET_H #include class QItemSelection; class QModelIndex; namespace GammaRay { class ModelInspectorInterface; namespace Ui { class ModelInspectorWidget; } class ModelInspectorWidget : public QWidget { Q_OBJECT public: explicit ModelInspectorWidget(QWidget *parent = 0); ~ModelInspectorWidget(); private slots: void cellSelected(int row, int column, const QString &internalId, const QString &internalPtr); void objectRegistered(const QString &objectName); void modelSelected(const QItemSelection& selected); void setupModelContentSelectionModel(); private: QScopedPointer ui; ModelInspectorInterface *m_interface; }; } #endif // GAMMARAY_MODELINSPECTORWIDGET_H gammaray-2.3.0/ui/tools/modelinspector/modelinspectorwidget.ui000066400000000000000000000072751255003167400247260ustar00rootroot00000000000000 GammaRay::ModelInspectorWidget 0 0 788 479 Qt::Horizontal true true Model Content true Cell Info Model Index: Invalid Internal Id: Internal Pointer: false true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/objectinspector/000077500000000000000000000000001255003167400202675ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/objectinspector/classinfotab.cpp000066400000000000000000000037121255003167400234460ustar00rootroot00000000000000/* classinfotab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "classinfotab.h" #include "ui_classinfotab.h" #include "propertywidget.h" #include "common/objectbroker.h" #include using namespace GammaRay; ClassInfoTab::ClassInfoTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_ClassInfoTab) { m_ui->setupUi(this); setObjectBaseName(parent->objectBaseName()); } ClassInfoTab::~ClassInfoTab() { } void ClassInfoTab::setObjectBaseName(const QString &baseName) { QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model(baseName + '.' + "classInfo")); m_ui->classInfoView->setModel(proxy); m_ui->classInfoView->sortByColumn(0, Qt::AscendingOrder); m_ui->classInfoView->header()->setResizeMode(QHeaderView::ResizeToContents); m_ui->classInfoSearchLine->setProxy(proxy); } gammaray-2.3.0/ui/tools/objectinspector/classinfotab.h000066400000000000000000000030021255003167400231030ustar00rootroot00000000000000/* classinfotab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef CLASSINFOTAB_H #define CLASSINFOTAB_H #include namespace GammaRay { class Ui_ClassInfoTab; class PropertyWidget; class ClassInfoTab : public QWidget { Q_OBJECT public: explicit ClassInfoTab(PropertyWidget *parent); virtual ~ClassInfoTab(); private: void setObjectBaseName(const QString &baseName); private: Ui_ClassInfoTab *m_ui; }; } #endif // CLASSINFOTAB_H gammaray-2.3.0/ui/tools/objectinspector/classinfotab.ui000066400000000000000000000021031255003167400232720ustar00rootroot00000000000000 GammaRay::ClassInfoTab 0 0 400 300 false true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/objectinspector/connectionsclientproxymodel.cpp000066400000000000000000000035361255003167400266460ustar00rootroot00000000000000/* connectionsclientproxymodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionsclientproxymodel.h" #include #include #include using namespace GammaRay; ConnectionsClientProxyModel::ConnectionsClientProxyModel(QObject* parent): QSortFilterProxyModel(parent) { } ConnectionsClientProxyModel::~ConnectionsClientProxyModel() { } QVariant ConnectionsClientProxyModel::data(const QModelIndex& index, int role) const { if (role == Qt::DecorationRole && index.column() == 0) { const bool warning = data(index, ConnectionsModelRoles::WarningFlagRole).toBool(); if (warning) return qApp->style()->standardIcon(QStyle::SP_MessageBoxWarning); } return QSortFilterProxyModel::data(index, role); } gammaray-2.3.0/ui/tools/objectinspector/connectionsclientproxymodel.h000066400000000000000000000032451255003167400263100ustar00rootroot00000000000000/* connectionsclientproxymodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONSCLIENTPROXYMODEL_H #define GAMMARAY_CONNECTIONSCLIENTPROXYMODEL_H #include namespace GammaRay { /** Client-side part of the connections model. */ class ConnectionsClientProxyModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ConnectionsClientProxyModel(QObject* parent = 0); virtual ~ConnectionsClientProxyModel(); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_CONNECTIONSCLIENTPROXYMODEL_H gammaray-2.3.0/ui/tools/objectinspector/connectionsextensionclient.cpp000066400000000000000000000035121255003167400264520ustar00rootroot00000000000000/* connectionsextensionclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionsextensionclient.h" #include #include using namespace GammaRay; ConnectionsExtensionClient::ConnectionsExtensionClient(const QString& name, QObject* parent): ConnectionsExtensionInterface(name, parent) { } ConnectionsExtensionClient::~ConnectionsExtensionClient() { } void ConnectionsExtensionClient::navigateToSender(int modelRow) { Endpoint::instance()->invokeObject(name(), "navigateToSender", QVariantList() << QVariant::fromValue(modelRow)); } void ConnectionsExtensionClient::navigateToReceiver(int modelRow) { Endpoint::instance()->invokeObject(name(), "navigateToReceiver", QVariantList() << QVariant::fromValue(modelRow)); } gammaray-2.3.0/ui/tools/objectinspector/connectionsextensionclient.h000066400000000000000000000034151255003167400261210ustar00rootroot00000000000000/* connectionsextensionclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONSEXTENSIONCLIENT_H #define GAMMARAY_CONNECTIONSEXTENSIONCLIENT_H #include namespace GammaRay { class ConnectionsExtensionClient : public ConnectionsExtensionInterface { Q_OBJECT Q_INTERFACES(GammaRay::ConnectionsExtensionInterface) public: explicit ConnectionsExtensionClient(const QString &name, QObject *parent = 0); virtual ~ConnectionsExtensionClient(); public slots: void navigateToReceiver(int modelRow) Q_DECL_OVERRIDE; void navigateToSender(int modelRow) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_CONNECTIONSEXTENSIONCLIENT_H gammaray-2.3.0/ui/tools/objectinspector/connectionstab.cpp000066400000000000000000000072131255003167400240070ustar00rootroot00000000000000/* connectionstab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "connectionstab.h" #include "ui_connectionstab.h" #include "connectionsclientproxymodel.h" #include #include #include #include #include #include using namespace GammaRay; ConnectionsTab::ConnectionsTab(PropertyWidget* parent): QWidget(parent), ui(new Ui::ConnectionsTab) { m_interface = ObjectBroker::object(parent->objectBaseName() + ".connectionsExtension"); ui->setupUi(this); QSortFilterProxyModel *proxy = new ConnectionsClientProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model(parent->objectBaseName() + ".inboundConnections")); ui->inboundView->setModel(proxy); ui->inboundView->sortByColumn(0, Qt::AscendingOrder); ui->inboundSearchLine->setProxy(proxy); connect(ui->inboundView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(inboundContextMenu(QPoint))); proxy = new ConnectionsClientProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model(parent->objectBaseName() + ".outboundConnections")); ui->outboundView->setModel(proxy); ui->outboundView->sortByColumn(0, Qt::AscendingOrder); ui->outboundSearchLine->setProxy(proxy); connect(ui->outboundView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(outboundContextMenu(QPoint))); } ConnectionsTab::~ConnectionsTab() { } static int mapToSourceRow(const QModelIndex &index) { QModelIndex i = index; while (const QAbstractProxyModel *proxy = qobject_cast(i.model())) { i = proxy->mapToSource(i); } return i.row(); } void ConnectionsTab::inboundContextMenu(const QPoint& pos) { const QModelIndex index = ui->inboundView->currentIndex(); if (!index.isValid() || index.data(ConnectionsModelRoles::ActionRole).toInt() == 0) return; QMenu menu; menu.addAction(tr("Go to sender")); if (menu.exec(ui->inboundView->viewport()->mapToGlobal(pos))) { m_interface->navigateToSender(mapToSourceRow(index)); } } void ConnectionsTab::outboundContextMenu(const QPoint& pos) { const QModelIndex index = ui->outboundView->currentIndex(); if (!index.isValid() || index.data(ConnectionsModelRoles::ActionRole).toInt() == 0) return; QMenu menu; menu.addAction(tr("Go to receiver")); if (menu.exec(ui->outboundView->viewport()->mapToGlobal(pos))) { m_interface->navigateToReceiver(mapToSourceRow(index)); } } gammaray-2.3.0/ui/tools/objectinspector/connectionstab.h000066400000000000000000000033271255003167400234560ustar00rootroot00000000000000/* connectionstab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CONNECTIONSTAB_H #define GAMMARAY_CONNECTIONSTAB_H #include namespace GammaRay { class ConnectionsExtensionInterface; class PropertyWidget; namespace Ui { class ConnectionsTab; } class ConnectionsTab : public QWidget { Q_OBJECT public: explicit ConnectionsTab(PropertyWidget *parent = 0); ~ConnectionsTab(); private slots: void inboundContextMenu(const QPoint &pos); void outboundContextMenu(const QPoint &pos); private: QScopedPointer ui; ConnectionsExtensionInterface *m_interface; }; } #endif // GAMMARAY_CONNECTIONSTAB_H gammaray-2.3.0/ui/tools/objectinspector/connectionstab.ui000066400000000000000000000055301255003167400236420ustar00rootroot00000000000000 GammaRay::ConnectionsTab 0 0 410 506 Form Qt::Vertical &Inbound Connections: inboundView Qt::CustomContextMenu false true true &Outbound Connections: outboundView Qt::CustomContextMenu false true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/objectinspector/enumstab.cpp000066400000000000000000000037071255003167400226200ustar00rootroot00000000000000/* enumstab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "enumstab.h" #include "ui_enumstab.h" #include "propertywidget.h" #include "common/objectbroker.h" #include "kde/krecursivefilterproxymodel.h" #include using namespace GammaRay; EnumsTab::EnumsTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_EnumsTab) { m_ui->setupUi(this); setObjectBaseName(parent->objectBaseName()); } EnumsTab::~EnumsTab() { } void EnumsTab::setObjectBaseName(const QString &baseName) { QSortFilterProxyModel *proxy = new KRecursiveFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model(baseName + '.' + "enums")); m_ui->enumView->setModel(proxy); m_ui->enumView->sortByColumn(0, Qt::AscendingOrder); m_ui->enumView->header()->setResizeMode(QHeaderView::ResizeToContents); m_ui->enumSearchLine->setProxy(proxy); } gammaray-2.3.0/ui/tools/objectinspector/enumstab.h000066400000000000000000000027361255003167400222660ustar00rootroot00000000000000/* enumstab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef ENUMSTAB_H #define ENUMSTAB_H #include namespace GammaRay { class Ui_EnumsTab; class PropertyWidget; class EnumsTab : public QWidget { Q_OBJECT public: explicit EnumsTab(PropertyWidget *parent); virtual ~EnumsTab(); private: void setObjectBaseName(const QString &baseName); private: Ui_EnumsTab *m_ui; }; } #endif // ENUMSTAB_H gammaray-2.3.0/ui/tools/objectinspector/enumstab.ui000066400000000000000000000015641255003167400224520ustar00rootroot00000000000000 GammaRay::EnumsTab 0 0 400 300 true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/objectinspector/methodsextensionclient.cpp000066400000000000000000000035771255003167400256060ustar00rootroot00000000000000/* methodsextensionclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodsextensionclient.h" #include #include #include using namespace GammaRay; MethodsExtensionClient::MethodsExtensionClient(const QString &name, QObject *parent) : MethodsExtensionInterface(name, parent) { } MethodsExtensionClient::~MethodsExtensionClient() { } void MethodsExtensionClient::activateMethod() { Endpoint::instance()->invokeObject(name(), "activateMethod"); } void MethodsExtensionClient::invokeMethod(Qt::ConnectionType type) { Endpoint::instance()->invokeObject(name(), "invokeMethod", QVariantList() << QVariant::fromValue(type)); } void MethodsExtensionClient::connectToSignal() { Endpoint::instance()->invokeObject(name(), "connectToSignal"); } gammaray-2.3.0/ui/tools/objectinspector/methodsextensionclient.h000066400000000000000000000034041255003167400252400ustar00rootroot00000000000000/* methodsextensionclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_METHODSEXTENSIONCLIENT_H #define GAMMARAY_METHODSEXTENSIONCLIENT_H #include namespace GammaRay { class MethodsExtensionClient : public MethodsExtensionInterface { Q_OBJECT Q_INTERFACES(GammaRay::MethodsExtensionInterface) public: explicit MethodsExtensionClient(const QString &name, QObject *parent = 0); ~MethodsExtensionClient(); public slots: void activateMethod() Q_DECL_OVERRIDE; void invokeMethod(Qt::ConnectionType type) Q_DECL_OVERRIDE; void connectToSignal() Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_METHODSEXTENSIONCLIENT_H gammaray-2.3.0/ui/tools/objectinspector/methodstab.cpp000066400000000000000000000103601255003167400231250ustar00rootroot00000000000000/* methodstab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "methodstab.h" #include "ui_methodstab.h" #include "propertywidget.h" #include #include #include "common/objectbroker.h" #include "common/metatypedeclarations.h" #include "common/modelroles.h" #include "common/tools/objectinspector/methodsextensioninterface.h" #include #include #include using namespace GammaRay; MethodsTab::MethodsTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_MethodsTab), m_interface(0) { m_ui->setupUi(this); setObjectBaseName(parent->objectBaseName()); } MethodsTab::~MethodsTab() { } void MethodsTab::setObjectBaseName(const QString &baseName) { m_objectBaseName = baseName; QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setDynamicSortFilter(true); proxy->setSourceModel(ObjectBroker::model(baseName + '.' + "methods")); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); proxy->setSortRole(ObjectMethodModelRole::MethodSignature); m_ui->methodView->setModel(proxy); m_ui->methodView->sortByColumn(0, Qt::AscendingOrder); m_ui->methodView->setSelectionModel(ObjectBroker::selectionModel(proxy)); m_ui->methodView->header()->setResizeMode(QHeaderView::ResizeToContents); m_ui->methodSearchLine->setProxy(proxy); connect(m_ui->methodView, SIGNAL(doubleClicked(QModelIndex)), SLOT(methodActivated(QModelIndex))); connect(m_ui->methodView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(methodContextMenu(QPoint))); m_ui->methodLog->setModel(ObjectBroker::model(baseName + '.' + "methodLog")); m_interface = ObjectBroker::object(baseName + ".methodsExtension"); new PropertyBinder(m_interface, "hasObject", m_ui->methodLog, "visible"); } void MethodsTab::methodActivated(const QModelIndex &index) { if (!index.isValid() || !m_interface->hasObject()) { return; } m_interface->activateMethod(); MethodInvocationDialog dlg(this); dlg.setArgumentModel(ObjectBroker::model(m_objectBaseName + '.' + "methodArguments")); if (dlg.exec()) { m_interface->invokeMethod(dlg.connectionType()); } } void MethodsTab::methodContextMenu(const QPoint &pos) { const QModelIndex index = m_ui->methodView->indexAt(pos); if (!index.isValid() || !m_interface->hasObject()) { return; } const QMetaMethod::MethodType methodType = index.data(ObjectMethodModelRole::MetaMethodType).value(); QMenu contextMenu; QAction *invokeAction = 0, *connectToAction = 0; if (methodType == QMetaMethod::Slot || methodType == QMetaMethod::Method) { invokeAction = contextMenu.addAction(tr("Invoke")); } else if (methodType == QMetaMethod::Signal) { connectToAction = contextMenu.addAction(tr("Connect to")); invokeAction = contextMenu.addAction(tr("Emit")); } else { return; // Can't do any action, so don't try to show an empty context menu. } QAction *action = contextMenu.exec(m_ui->methodView->viewport()->mapToGlobal(pos)); if (action == invokeAction) { methodActivated(index); } else if (action == connectToAction) { m_interface->connectToSignal(); } } gammaray-2.3.0/ui/tools/objectinspector/methodstab.h000066400000000000000000000033641255003167400226000ustar00rootroot00000000000000/* methodstab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef METHODSTAB_H #define METHODSTAB_H #include class QModelIndex; namespace GammaRay { class MethodsExtensionInterface; class Ui_MethodsTab; class PropertyWidget; class MethodsTab : public QWidget { Q_OBJECT public: explicit MethodsTab(PropertyWidget *parent); virtual ~MethodsTab(); private: void setObjectBaseName(const QString &baseName); private slots: void methodActivated(const QModelIndex &index); void methodContextMenu(const QPoint &pos); private: Ui_MethodsTab *m_ui; MethodsExtensionInterface *m_interface; QString m_objectBaseName; }; } #endif // METHODSTAB_H gammaray-2.3.0/ui/tools/objectinspector/methodstab.ui000066400000000000000000000030631255003167400227620ustar00rootroot00000000000000 GammaRay::MethodsTab 0 0 400 300 Qt::CustomContextMenu false true true false true false KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/objectinspector/objectinspectorwidget.cpp000066400000000000000000000056201255003167400253770ustar00rootroot00000000000000/* objectinspector.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objectinspectorwidget.h" #include "ui_objectinspectorwidget.h" #include #include #include #include #include using namespace GammaRay; ObjectInspectorWidget::ObjectInspectorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ObjectInspectorWidget) { ui->setupUi(this); ui->objectPropertyWidget->setObjectBaseName("com.kdab.GammaRay.ObjectInspector"); QSortFilterProxyModel *objectFilter = new KRecursiveFilterProxyModel(this); objectFilter->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.ObjectTree")); objectFilter->setDynamicSortFilter(true); ui->objectTreeView->setModel(objectFilter); new DeferredResizeModeSetter(ui->objectTreeView->header(), 0, QHeaderView::Stretch); new DeferredResizeModeSetter(ui->objectTreeView->header(), 1, QHeaderView::Interactive); ui->objectSearchLine->setProxy(objectFilter); QItemSelectionModel* selectionModel = ObjectBroker::selectionModel(ui->objectTreeView->model()); ui->objectTreeView->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(objectSelectionChanged(QItemSelection))); if (qgetenv("GAMMARAY_TEST_FILTER") == "1") { QMetaObject::invokeMethod(ui->objectSearchLine->lineEdit(), "setText", Qt::QueuedConnection, Q_ARG(QString, QLatin1String("Object"))); } } ObjectInspectorWidget::~ObjectInspectorWidget() { } void ObjectInspectorWidget::objectSelectionChanged(const QItemSelection& selection) { if (selection.isEmpty()) return; const QModelIndex index = selection.first().topLeft(); ui->objectTreeView->scrollTo(index); } gammaray-2.3.0/ui/tools/objectinspector/objectinspectorwidget.h000066400000000000000000000064061255003167400250470ustar00rootroot00000000000000/* objectinspector.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_OBJECTINSPECTOR_OBJECTINSPECTORWIDGET_H #define GAMMARAY_OBJECTINSPECTOR_OBJECTINSPECTORWIDGET_H #include #include "tooluifactory.h" #include "propertywidget.h" #include "propertiestab.h" #include "methodstab.h" #include "connectionstab.h" #include "enumstab.h" #include "classinfotab.h" #include "propertiesextensionclient.h" #include "methodsextensionclient.h" #include "connectionsextensionclient.h" #include class QItemSelection; namespace GammaRay { namespace Ui { class ObjectInspectorWidget; } template static QObject* createExtension(const QString &name, QObject *parent) { return new T(name, parent); } class ObjectInspectorWidget : public QWidget { Q_OBJECT public: explicit ObjectInspectorWidget(QWidget *parent = 0); ~ObjectInspectorWidget(); private slots: void objectSelectionChanged(const QItemSelection &selection); private: QScopedPointer ui; }; class ObjectInspectorFactory : public ToolUiFactory { public: virtual inline QString id() const { return "GammaRay::ObjectInspector"; } virtual inline QWidget *createWidget(QWidget *parentWidget) { return new ObjectInspectorWidget(parentWidget); } virtual inline bool remotingSupported() const { return true; } virtual void initUi() { PropertyWidget::registerTab("properties", QObject::tr("Properties")); ObjectBroker::registerClientObjectFactoryCallback(createExtension); PropertyWidget::registerTab("methods", QObject::tr("Methods")); ObjectBroker::registerClientObjectFactoryCallback(createExtension); PropertyWidget::registerTab("connections", QObject::tr("Connections")); ObjectBroker::registerClientObjectFactoryCallback(createExtension); PropertyWidget::registerTab("enums", QObject::tr("Enums")); PropertyWidget::registerTab("classInfo", QObject::tr("Class Info")); } }; } #endif // GAMMARAY_OBJECTINSPECTOR_H gammaray-2.3.0/ui/tools/objectinspector/objectinspectorwidget.ui000066400000000000000000000032371255003167400252340ustar00rootroot00000000000000 GammaRay::ObjectInspectorWidget 0 0 400 300 Qt::Horizontal true true true KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
GammaRay::PropertyWidget QWidget
propertywidget.h
1
gammaray-2.3.0/ui/tools/objectinspector/propertiesextensionclient.cpp000066400000000000000000000041421255003167400263240ustar00rootroot00000000000000/* propertiesextensionclient.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Milian Wolff Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertiesextensionclient.h" #include #include #include using namespace GammaRay; PropertiesExtensionClient::PropertiesExtensionClient(const QString &name, QObject *parent) : PropertiesExtensionInterface(name, parent) { } PropertiesExtensionClient::~PropertiesExtensionClient() { } void PropertiesExtensionClient::navigateToValue(int modelRow) { Endpoint::instance()->invokeObject(name(), "navigateToValue", QVariantList() << QVariant::fromValue(modelRow)); } void PropertiesExtensionClient::setProperty(const QString& propertyName, const QVariant& value) { Endpoint::instance()->invokeObject(name(), "setProperty", QVariantList() << QVariant::fromValue(propertyName) << VariantWrapper(value)); } void PropertiesExtensionClient::resetProperty(const QString& propertyName) { Endpoint::instance()->invokeObject(name(), "resetProperty", QVariantList() << QVariant::fromValue(propertyName)); } gammaray-2.3.0/ui/tools/objectinspector/propertiesextensionclient.h000066400000000000000000000036631255003167400260000ustar00rootroot00000000000000/* propertiesextensionclient.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_PROPERTIESEXTENSIONCLIENT_H #define GAMMARAY_PROPERTIESEXTENSIONCLIENT_H #include namespace GammaRay { class PropertiesExtensionClient : public PropertiesExtensionInterface { Q_OBJECT Q_INTERFACES(GammaRay::PropertiesExtensionInterface) public: explicit PropertiesExtensionClient(const QString &name, QObject *parent = 0); ~PropertiesExtensionClient(); public slots: // virtual void activateMethod(); // virtual void invokeMethod(Qt::ConnectionType type); void navigateToValue(int modelRow) Q_DECL_OVERRIDE; void setProperty(const QString& name, const QVariant& value) Q_DECL_OVERRIDE; void resetProperty(const QString& name) Q_DECL_OVERRIDE; }; } #endif // GAMMARAY_PROPERTIESEXTENSIONCLIENT_H gammaray-2.3.0/ui/tools/objectinspector/propertiestab.cpp000066400000000000000000000160421255003167400236610ustar00rootroot00000000000000/* propertiestab.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "propertiestab.h" #include "ui_propertiestab.h" #include "propertywidget.h" #include "editabletypesmodel.h" #include "variantcontainermodel.h" #include "ui/propertyeditor/propertyeditordelegate.h" #include "ui/propertyeditor/propertyeditorfactory.h" #include "ui/deferredresizemodesetter.h" #include #include "common/objectbroker.h" #include #include "common/tools/objectinspector/propertiesextensioninterface.h" #include #include #include using namespace GammaRay; PropertiesTab::PropertiesTab(PropertyWidget *parent) : QWidget(parent), m_ui(new Ui_PropertiesTab), m_interface(0), m_newPropertyValue(0) { m_ui->setupUi(this); m_ui->newPropertyButton->setIcon(QIcon::fromTheme("list-add")); setObjectBaseName(parent->objectBaseName()); } PropertiesTab::~PropertiesTab() { } void PropertiesTab::setObjectBaseName(const QString &baseName) { QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); proxy->setDynamicSortFilter(true); QAbstractItemModel *model = ObjectBroker::model(baseName + '.' + "properties"); proxy->setSourceModel(model); m_ui->propertyView->setModel(proxy); m_ui->propertyView->sortByColumn(0, Qt::AscendingOrder); new DeferredResizeModeSetter( m_ui->propertyView->header(), 0, QHeaderView::ResizeToContents); m_ui->propertySearchLine->setProxy(proxy); m_ui->propertyView->setItemDelegate(new PropertyEditorDelegate(this)); connect(m_ui->propertyView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(propertyContextMenu(QPoint))); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) connect(m_ui->propertyView, SIGNAL(doubleClicked(QModelIndex)), SLOT(onDoubleClick(QModelIndex))); #endif EditableTypesModel *typesModel = new EditableTypesModel(this); proxy = new QSortFilterProxyModel(this); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); proxy->setSourceModel(typesModel); proxy->sort(0); m_ui->newPropertyType->setModel(proxy); connect(m_ui->newPropertyType, SIGNAL(currentIndexChanged(int)), this, SLOT(updateNewPropertyValueEditor())); updateNewPropertyValueEditor(); connect(m_ui->newPropertyName, SIGNAL(textChanged(QString)), this, SLOT(validateNewProperty())); validateNewProperty(); connect(m_ui->newPropertyButton, SIGNAL(clicked()), this, SLOT(addNewProperty())); m_interface = ObjectBroker::object(baseName + ".propertiesExtension"); new PropertyBinder(m_interface, "canAddProperty", m_ui->newPropertyBar, "visible"); } static PropertyEditorFactory::TypeId selectedTypeId(QComboBox *box) { return static_cast( box->itemData(box->currentIndex(), Qt::UserRole).toInt()); } void PropertiesTab::updateNewPropertyValueEditor() { delete m_newPropertyValue; const PropertyEditorFactory::TypeId type = selectedTypeId(m_ui->newPropertyType); m_newPropertyValue = PropertyEditorFactory::instance()->createEditor(type, this); static_cast(m_ui->newPropertyBar->layout())->insertWidget(5, m_newPropertyValue); m_ui->newPropertyValueLabel->setBuddy(m_newPropertyValue); } void PropertiesTab::validateNewProperty() { Q_ASSERT(m_newPropertyValue); m_ui->newPropertyButton->setEnabled(!m_ui->newPropertyName->text().isEmpty()); } void PropertiesTab::propertyContextMenu(const QPoint &pos) { const QModelIndex index = m_ui->propertyView->indexAt(pos); if (!index.isValid()) { return; } const int actions = index.data(PropertyModel::ActionRole).toInt(); if (actions == PropertyModel::NoAction) { return; } QMenu contextMenu; if (actions & PropertyModel::Delete) { QAction *action = contextMenu.addAction(tr("Remove")); action->setData(PropertyModel::Delete); } if (actions & PropertyModel::Reset) { QAction *action = contextMenu.addAction(tr("Reset")); action->setData(PropertyModel::Reset); } if (actions & PropertyModel::NavigateTo) { QAction *action = contextMenu.addAction(tr("Show in %1"). arg(index.data(PropertyModel::AppropriateToolRole).toString())); action->setData(PropertyModel::NavigateTo); } if (QAction *action = contextMenu.exec(m_ui->propertyView->viewport()->mapToGlobal(pos))) { const QString propertyName = index.sibling(index.row(), 0).data(Qt::DisplayRole).toString(); switch (action->data().toInt()) { case PropertyModel::Delete: m_interface->setProperty(propertyName, QVariant()); break; case PropertyModel::Reset: m_interface->resetProperty(propertyName); break; case PropertyModel::NavigateTo: QSortFilterProxyModel *proxy = qobject_cast(m_ui->propertyView->model()); QModelIndex sourceIndex = index; while (proxy) { sourceIndex = proxy->mapToSource(sourceIndex); proxy = qobject_cast(proxy->sourceModel()); } m_interface->navigateToValue(sourceIndex.row()); break; } } } void PropertiesTab::onDoubleClick(const QModelIndex &index) { if (index.column() != 0) { return; } #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) QVariant var = index.sibling(index.row(), 1).data(Qt::EditRole); if (!var.canConvert() && !var.canConvert()) { return; } QTreeView *v = new QTreeView; VariantContainerModel *m = new VariantContainerModel(v); m->setVariant(var); v->setModel(m); v->show(); #endif } void PropertiesTab::addNewProperty() { Q_ASSERT(m_interface->canAddProperty()); const PropertyEditorFactory::TypeId type = selectedTypeId(m_ui->newPropertyType); const QByteArray editorPropertyName = PropertyEditorFactory::instance()->valuePropertyName(type); const QVariant value = m_newPropertyValue->property(editorPropertyName); m_interface->setProperty(m_ui->newPropertyName->text(), value); m_ui->newPropertyName->clear(); updateNewPropertyValueEditor(); } gammaray-2.3.0/ui/tools/objectinspector/propertiestab.h000066400000000000000000000035741255003167400233340ustar00rootroot00000000000000/* propertiestab.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2014-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Anton Kreuzkamp Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PROPERTIESTAB_H #define PROPERTIESTAB_H #include class QModelIndex; namespace GammaRay { class PropertiesExtensionInterface; class Ui_PropertiesTab; class PropertyWidget; class PropertiesTab : public QWidget { Q_OBJECT public: explicit PropertiesTab(PropertyWidget *parent); virtual ~PropertiesTab(); private: void setObjectBaseName(const QString &baseName); private slots: void updateNewPropertyValueEditor(); void validateNewProperty(); void propertyContextMenu(const QPoint &pos); void onDoubleClick(const QModelIndex &index); void addNewProperty(); private: Ui_PropertiesTab *m_ui; PropertiesExtensionInterface *m_interface; QWidget *m_newPropertyValue; }; } #endif // PROPERTIESTAB_H gammaray-2.3.0/ui/tools/objectinspector/propertiestab.ui000066400000000000000000000050301255003167400235070ustar00rootroot00000000000000 GammaRay::PropertiesTab 0 0 400 300 Qt::CustomContextMenu false true true 0 &New Dynamic Property: newPropertyName Name &Type: newPropertyType &Value: Add KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/resourcebrowser/000077500000000000000000000000001255003167400203255ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/resourcebrowser/clientresourcemodel.cpp000066400000000000000000000042441255003167400251040ustar00rootroot00000000000000/* clientresourcemodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "clientresourcemodel.h" #include using namespace GammaRay; ClientResourceModel::ClientResourceModel(QObject* parent): KRecursiveFilterProxyModel(parent) { } ClientResourceModel::~ClientResourceModel() { } QVariant ClientResourceModel::data(const QModelIndex& index, int role) const { if (role == Qt::DecorationRole && index.column() == 0) { if (!index.parent().isValid()) return m_iconProvider.icon(QFileIconProvider::Drive); if (hasChildren(index)) return m_iconProvider.icon(QFileIconProvider::Folder); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QList types = m_mimeDb.mimeTypesForFileName(index.data(Qt::DisplayRole).toString()); foreach( const QMimeType &mt, types) { QIcon icon = QIcon::fromTheme(mt.iconName()); if (!icon.isNull()) return icon; icon = QIcon::fromTheme(mt.genericIconName()); if (!icon.isNull()) return icon; } #endif return m_iconProvider.icon(QFileIconProvider::File); } return QSortFilterProxyModel::data(index, role); } gammaray-2.3.0/ui/tools/resourcebrowser/clientresourcemodel.h000066400000000000000000000036711255003167400245540ustar00rootroot00000000000000/* clientresourcemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_CLIENTRESOURCEMODEL_H #define GAMMARAY_CLIENTRESOURCEMODEL_H #include "kde/krecursivefilterproxymodel.h" #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0 ,0) #include #endif namespace GammaRay { /** * Adds file icons for the resource model. * This can't be done server-side since the icon stuff might not exist in a pure QtCore application. */ class ClientResourceModel : public KRecursiveFilterProxyModel { Q_OBJECT public: explicit ClientResourceModel(QObject *parent = 0); ~ClientResourceModel(); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QFileIconProvider m_iconProvider; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QMimeDatabase m_mimeDb; #endif }; } #endif // GAMMARAY_CLIENTRESOURCEMODEL_H gammaray-2.3.0/ui/tools/resourcebrowser/resourcebrowserclient.cpp000066400000000000000000000031621255003167400254650ustar00rootroot00000000000000/* * * * This file is part of GammaRay, the Qt application inspection and * manipulation tool. * * Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * Author: Milian Wolff * * Licensees holding valid commercial KDAB GammaRay licenses may use this file in * accordance with GammaRay Commercial License Agreement provided with the Software. * * Contact info@kdab.com if any conditions of this licensing are not clear to you. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "resourcebrowserclient.h" #include using namespace GammaRay; ResourceBrowserClient::ResourceBrowserClient(QObject *parent) : ResourceBrowserInterface(parent) { } ResourceBrowserClient::~ResourceBrowserClient() { } void ResourceBrowserClient::downloadResource(const QString &sourceFilePath, const QString &targetFilePath) { Endpoint::instance()->invokeObject(objectName(), "downloadResource", QVariantList() << sourceFilePath << targetFilePath); } gammaray-2.3.0/ui/tools/resourcebrowser/resourcebrowserclient.h000066400000000000000000000032071255003167400251320ustar00rootroot00000000000000/* * * * This file is part of GammaRay, the Qt application inspection and * manipulation tool. * * Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * Author: Milian Wolff * * Licensees holding valid commercial KDAB GammaRay licenses may use this file in * accordance with GammaRay Commercial License Agreement provided with the Software. * * Contact info@kdab.com if any conditions of this licensing are not clear to you. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef RESOURCEBROWSERCLIENT_H #define RESOURCEBROWSERCLIENT_H #include namespace GammaRay { class ResourceBrowserClient : public ResourceBrowserInterface { Q_OBJECT Q_INTERFACES(GammaRay::ResourceBrowserInterface) public: explicit ResourceBrowserClient(QObject *parent); virtual ~ResourceBrowserClient(); void downloadResource(const QString &sourceFilePath, const QString &targetFilePath) Q_DECL_OVERRIDE; }; } #endif // RESOURCEBROWSERCLIENT_H gammaray-2.3.0/ui/tools/resourcebrowser/resourcebrowserwidget.cpp000066400000000000000000000202721255003167400254730ustar00rootroot00000000000000/* resourcebrowserwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "resourcebrowserwidget.h" #include "ui_resourcebrowserwidget.h" #include "resourcebrowserclient.h" #include "clientresourcemodel.h" #include #include <3rdparty/qt/resourcemodel.h> #include #include #include #include #include #include using namespace GammaRay; static QObject* createResourceBrowserClient(const QString & /*name*/, QObject *parent) { return new ResourceBrowserClient(parent); } ResourceBrowserWidget::ResourceBrowserWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::ResourceBrowserWidget) , m_timer(new QTimer(this)) , m_interface(0) { ObjectBroker::registerClientObjectFactoryCallback(createResourceBrowserClient); m_interface = ObjectBroker::object(); connect(m_interface, SIGNAL(resourceDeselected()), this, SLOT(resourceDeselected())); connect(m_interface, SIGNAL(resourceSelected(QPixmap)), this, SLOT(resourceSelected(QPixmap))); connect(m_interface, SIGNAL(resourceSelected(QByteArray)), this, SLOT(resourceSelected(QByteArray))); connect(m_interface, SIGNAL(resourceDownloaded(QString,QPixmap)), this, SLOT(resourceDownloaded(QString,QPixmap))); connect(m_interface, SIGNAL(resourceDownloaded(QString,QByteArray)), this, SLOT(resourceDownloaded(QString,QByteArray))); ui->setupUi(this); ClientResourceModel* model = new ClientResourceModel(this); model->setSourceModel(ObjectBroker::model("com.kdab.GammaRay.ResourceModel")); ui->treeView->setModel(model); ui->treeView->setSelectionModel(ObjectBroker::selectionModel(ui->treeView->model())); ui->searchLine->setProxy(model); DeferredTreeViewConfiguration *config = new DeferredTreeViewConfiguration(ui->treeView); config->hideColumn(3); connect(ui->treeView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted())); ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(handleCustomContextMenu(QPoint))); ui->resourceLabel->setText(tr("Select a Resource to Preview")); ui->stackedWidget->setCurrentWidget(ui->contentLabelPage); m_timer->setInterval(100); m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), SLOT(setupLayout())); m_timer->start(); } ResourceBrowserWidget::~ResourceBrowserWidget() { } void ResourceBrowserWidget::rowsInserted() { m_timer->start(); } void ResourceBrowserWidget::setupLayout() { // now we can assume the model is filled properly and can adjust the tree view column sizes for(int i = 0; i < 3; ++i) { ui->treeView->resizeColumnToContents(i); } // now the view was setup properly and we can mess with the splitter to resize // the widgets for nicer display int viewWidth = ui->treeView->columnWidth(0) + ui->treeView->columnWidth(1) + ui->treeView->columnWidth(2) + ui->treeView->contentsMargins().left() + ui->treeView->contentsMargins().right() + 25; const int totalWidth = ui->splitter->width(); const int minPreviewWidth = 150; if (totalWidth > viewWidth + minPreviewWidth) { ui->splitter->setSizes(QList() << viewWidth << (totalWidth - viewWidth)); ui->splitter->setStretchFactor(1, 3); } } void ResourceBrowserWidget::resourceDeselected() { ui->resourceLabel->setText(tr("Select a Resource to Preview")); ui->stackedWidget->setCurrentWidget(ui->contentLabelPage); } void ResourceBrowserWidget::resourceSelected(const QPixmap &pixmap) { ui->resourceLabel->setPixmap(pixmap); ui->stackedWidget->setCurrentWidget(ui->contentLabelPage); } void ResourceBrowserWidget::resourceSelected(const QByteArray &contents) { //TODO: make encoding configurable ui->textBrowser->setText(contents); ui->stackedWidget->setCurrentWidget(ui->contentTextPage); } void ResourceBrowserWidget::resourceDownloaded(const QString &targetFilePath, const QPixmap &pixmap) { if (!pixmap.save(targetFilePath)) { qWarning("Unable to write resource content to %s", qPrintable(targetFilePath)); return; } } void ResourceBrowserWidget::resourceDownloaded(const QString &targetFilePath, const QByteArray &contents) { QFile file(targetFilePath); if (!file.open(QIODevice::WriteOnly)) { qWarning("Unable to write resource content to %s", qPrintable(targetFilePath)); return; } file.write(contents); file.close(); } static QStringList collectDirectories(const QModelIndex &index, const QString &baseDirectory) { QStringList result; const QAbstractItemModel *model = index.model(); const QString directoryPath = index.data(ResourceModel::FilePathRole).toString(); const QString relativeDirectory = directoryPath.mid(baseDirectory.size()); result << relativeDirectory; for (int row = 0; row < model->rowCount(index); ++row) { const QModelIndex childIndex = model->index(row, 0, index); if (model->hasChildren(childIndex)) result += collectDirectories(childIndex, baseDirectory); } return result; } static QStringList collectFiles(const QModelIndex &index, const QString &baseDirectory) { QStringList result; const QAbstractItemModel *model = index.model(); for (int row = 0; row < model->rowCount(index); ++row) { const QModelIndex childIndex = model->index(row, 0, index); if (model->hasChildren(childIndex)) { result += collectFiles(childIndex, baseDirectory); } else { const QString filePath = childIndex.data(ResourceModel::FilePathRole).toString(); const QString relativeFilePath = filePath.mid(baseDirectory.size()); result << relativeFilePath; } } return result; } void ResourceBrowserWidget::handleCustomContextMenu(const QPoint &pos) { const QModelIndex selectedIndex = ui->treeView->indexAt(pos); if (!selectedIndex.isValid()) return; QMenu menu; menu.addAction(tr("Save As...")); if (!menu.exec(ui->treeView->mapToGlobal(pos))) return; if (selectedIndex.model()->hasChildren(selectedIndex)) { const QString sourceDirectory = selectedIndex.data(ResourceModel::FilePathRole).toString(); const QString targetDirectory = QFileDialog::getExistingDirectory(this, tr("Save As")); // create local target directory tree foreach (const QString &directoryPath, collectDirectories(selectedIndex, sourceDirectory)) { if (directoryPath.isEmpty()) continue; QDir dir(targetDirectory + '/' + directoryPath); dir.mkpath("."); } // request all resource files foreach (const QString &filePath, collectFiles(selectedIndex, sourceDirectory)) { m_interface->downloadResource(sourceDirectory + filePath, targetDirectory + filePath); } } else { const QString sourceFilePath = selectedIndex.data(ResourceModel::FilePathRole).toString(); const QString sourceFileName = sourceFilePath.mid(sourceFilePath.lastIndexOf('/') + 1); const QString targetFilePath = QFileDialog::getSaveFileName(this, tr("Save As"), sourceFileName); if (targetFilePath.isEmpty()) return; m_interface->downloadResource(sourceFilePath, targetFilePath); } } gammaray-2.3.0/ui/tools/resourcebrowser/resourcebrowserwidget.h000066400000000000000000000041641255003167400251420ustar00rootroot00000000000000/* resourcebrowserwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_RESOURCEBROWSER_RESOURCEBROWSERWIDGET_H #define GAMMARAY_RESOURCEBROWSER_RESOURCEBROWSERWIDGET_H #include class QTimer; class QItemSelection; namespace GammaRay { class ResourceBrowserInterface; namespace Ui { class ResourceBrowserWidget; } class ResourceBrowserWidget : public QWidget { Q_OBJECT public: explicit ResourceBrowserWidget(QWidget *parent = 0); ~ResourceBrowserWidget(); private slots: void rowsInserted(); void setupLayout(); void resourceDeselected(); void resourceSelected(const QPixmap &pixmap); void resourceSelected(const QByteArray &contents); void resourceDownloaded(const QString &fileName, const QPixmap &pixmap); void resourceDownloaded(const QString &fileName, const QByteArray &contents); void handleCustomContextMenu(const QPoint &pos); private: QScopedPointer ui; QTimer *m_timer; ResourceBrowserInterface *m_interface; }; } #endif // GAMMARAY_RESOURCEBROWSER_H gammaray-2.3.0/ui/tools/resourcebrowser/resourcebrowserwidget.ui000066400000000000000000000066151255003167400253330ustar00rootroot00000000000000 GammaRay::ResourceBrowserWidget 0 0 1036 846 0 0 0 0 Qt::Horizontal 1 0 0 0 0 0 0 0 0 QFrame::NoFrame true Qt::AlignCenter 0 0 527 846 Qt::AlignCenter KFilterProxySearchLine QWidget
kde/kfilterproxysearchline.h
gammaray-2.3.0/ui/tools/standardpaths/000077500000000000000000000000001255003167400177325ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/standardpaths/standardpathswidget.cpp000066400000000000000000000031311255003167400245000ustar00rootroot00000000000000/* standardpathswidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "standardpathswidget.h" #include "ui_standardpathswidget.h" #include using namespace GammaRay; StandardPathsWidget::StandardPathsWidget(QWidget *parent) : QWidget(parent), ui(new Ui::StandardPathsWidget) { ui->setupUi(this); ui->pathView->setModel(ObjectBroker::model("com.kdab.GammaRay.StandardPathsModel")); ui->pathView->header()->setResizeMode(QHeaderView::ResizeToContents); } StandardPathsWidget::~StandardPathsWidget() { } gammaray-2.3.0/ui/tools/standardpaths/standardpathswidget.h000066400000000000000000000030421255003167400241460ustar00rootroot00000000000000/* standardpathswidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2012-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_STANDARDPATHSWIDGET_H #define GAMMARAY_STANDARDPATHSWIDGET_H #include namespace GammaRay { namespace Ui { class StandardPathsWidget; } class StandardPathsWidget : public QWidget { Q_OBJECT public: explicit StandardPathsWidget(QWidget *parent = 0); ~StandardPathsWidget(); private: QScopedPointer ui; }; } #endif // GAMMARAY_STANDARDPATHSWIDGET_H gammaray-2.3.0/ui/tools/standardpaths/standardpathswidget.ui000066400000000000000000000013321255003167400243340ustar00rootroot00000000000000 GammaRay::StandardPathsWidget 0 0 400 300 0 false true gammaray-2.3.0/ui/tools/textdocumentinspector/000077500000000000000000000000001255003167400215445ustar00rootroot00000000000000gammaray-2.3.0/ui/tools/textdocumentinspector/textdocumentcontentview.cpp000066400000000000000000000032331255003167400272620ustar00rootroot00000000000000/* textdocumentcontentview.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "textdocumentcontentview.h" #include using namespace GammaRay; TextDocumentContentView::TextDocumentContentView(QWidget *parent): QTextEdit(parent) { } void TextDocumentContentView::setShowBoundingBox(const QRectF &boundingBox) { m_boundingBox = boundingBox; viewport()->update(); } void TextDocumentContentView::paintEvent(QPaintEvent *e) { QTextEdit::paintEvent(e); if (!m_boundingBox.isEmpty()) { QPainter painter(viewport()); painter.setPen(Qt::red); painter.drawRect(m_boundingBox); } } gammaray-2.3.0/ui/tools/textdocumentinspector/textdocumentcontentview.h000066400000000000000000000032051255003167400267260ustar00rootroot00000000000000/* textdocumentcontentview.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTCONTENTVIEW_H #define GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTCONTENTVIEW_H #include namespace GammaRay { class TextDocumentContentView : public QTextEdit { Q_OBJECT public: explicit TextDocumentContentView(QWidget *parent = 0); void setShowBoundingBox(const QRectF &boundingBox); protected: void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE; private: QRectF m_boundingBox; }; } #endif // GAMMARAY_TEXTDOCUMENTCONTENTVIEW_H gammaray-2.3.0/ui/tools/textdocumentinspector/textdocumentinspectorwidget.cpp000066400000000000000000000100371255003167400301270ustar00rootroot00000000000000/* textdocumentinspectorwidget.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "textdocumentinspectorwidget.h" #include "ui_textdocumentinspectorwidget.h" #include "core/tools/textdocumentinspector/textdocumentmodel.h" #include #include #include #include #include using namespace GammaRay; TextDocumentInspectorWidget::TextDocumentInspectorWidget(QWidget *parent): QWidget(parent), ui(new Ui::TextDocumentInspectorWidget) { ui->setupUi(this); ui->documentList->setModel(ObjectBroker::model("com.kdab.GammaRay.TextDocumentsModel")); QItemSelectionModel *selectionModel = ObjectBroker::selectionModel(ui->documentList->model()); ui->documentList->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(documentSelected(QItemSelection,QItemSelection))); ui->documentTree->setModel(ObjectBroker::model("com.kdab.GammaRay.TextDocumentModel")); selectionModel = ObjectBroker::selectionModel(ui->documentTree->model()); ui->documentTree->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(documentElementSelected(QItemSelection,QItemSelection))); ui->documentFormatView->setModel(ObjectBroker::model("com.kdab.GammaRay.TextDocumentFormatModel")); new DeferredResizeModeSetter(ui->documentFormatView->header(), 0, QHeaderView::ResizeToContents); if (Endpoint::instance()->isRemoteClient()) // FIXME: content preview doesn't work remotely yet ui->tabWidget->hide(); } TextDocumentInspectorWidget::~TextDocumentInspectorWidget() { } void TextDocumentInspectorWidget::documentSelected(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); const QModelIndex selectedRow = selected.first().topLeft(); QObject *selectedObj = selectedRow.data(ObjectModel::ObjectRole).value(); QTextDocument *doc = qobject_cast(selectedObj); if (m_currentDocument) { disconnect(m_currentDocument, SIGNAL(contentsChanged()), this, SLOT(documentContentChanged())); } m_currentDocument = QPointer(doc); if (doc) { ui->documentView->setDocument(doc); connect(doc, SIGNAL(contentsChanged()), SLOT(documentContentChanged())); documentContentChanged(); } } void TextDocumentInspectorWidget::documentElementSelected(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); const QModelIndex selectedRow = selected.first().topLeft(); const QRectF boundingBox = selectedRow.data(TextDocumentModel::BoundingBoxRole).toRectF(); ui->documentView->setShowBoundingBox(boundingBox); } void TextDocumentInspectorWidget::documentContentChanged() { ui->htmlView->setPlainText(m_currentDocument->toHtml()); } gammaray-2.3.0/ui/tools/textdocumentinspector/textdocumentinspectorwidget.h000066400000000000000000000040621255003167400275750ustar00rootroot00000000000000/* textdocumentinspectorwidget.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTINSPECTORWIDGET_H #define GAMMARAY_TEXTDOCUMENTINSPECTOR_TEXTDOCUMENTINSPECTORWIDGET_H #include #include #include class QItemSelection; namespace GammaRay { class TextDocumentModel; class TextDocumentFormatModel; namespace Ui { class TextDocumentInspectorWidget; } class TextDocumentInspectorWidget : public QWidget { Q_OBJECT public: explicit TextDocumentInspectorWidget(QWidget *parent = 0); ~TextDocumentInspectorWidget(); private slots: void documentSelected(const QItemSelection &selected, const QItemSelection &deselected); void documentElementSelected(const QItemSelection &selected, const QItemSelection &deselected); void documentContentChanged(); private: QScopedPointer ui; QPointer m_currentDocument; }; } #endif // GAMMARAY_TEXTDOCUMENTINSPECTOR_H gammaray-2.3.0/ui/tools/textdocumentinspector/textdocumentinspectorwidget.ui000066400000000000000000000076061255003167400277720ustar00rootroot00000000000000 GammaRay::TextDocumentInspectorWidget 0 0 762 631 Qt::Horizontal All documents: false true true Qt::Vertical Document structure: 10 true true Element format: false true true 0 Content HTML GammaRay::TextDocumentContentView QTextEdit
tools/textdocumentinspector/textdocumentcontentview.h
gammaray-2.3.0/ui/tooluifactory.h000066400000000000000000000060561255003167400170150ustar00rootroot00000000000000/* This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2010-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Volker Krause Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_TOOLUIFACTORY_H #define GAMMARAY_TOOLUIFACTORY_H #include #include #include namespace GammaRay { /** * @brief An abstract interface for creating the UI parts of probe tools. * * The ToolUiFactory class is an abstract base class for creating UIs for probe tools * for GammaRay. The unique identifier used for the UI must match the one of the corresponding * probe tool. */ class ToolUiFactory { public: virtual inline ~ToolUiFactory() { } /** * Unique id of this tool, must match the id of a the corresponding probe tool. * @return a QString containing the tool id. */ virtual QString id() const = 0; /** * Return true if this tool supports remoting, false otherwise. */ virtual bool remotingSupported() const = 0; /** * Create the UI part of this tool. * @param parentWidget The parent widget for the visual elements of this tool. * @return a pointer to the created QwWidget. */ virtual QWidget *createWidget(QWidget *parentWidget) = 0; /** * Initialize UI related stuff for this tool. This function is called on loading * the plugin, before the widget itself is needed. Use createWidget to create * the actual widget. */ virtual void initUi() {} }; /** * @brief A templated convenience ToolUiFactory applicable for most use-cases. */ template class StandardToolUiFactory : public ToolUiFactory { public: virtual inline QString id() const { return QString(); // TODO is this a problem?? } virtual inline QWidget *createWidget(QWidget *parentWidget) { return new ToolUi(parentWidget); } virtual bool remotingSupported() const { return true; } }; } Q_DECLARE_INTERFACE(GammaRay::ToolUiFactory, "com.kdab.GammaRay.ToolUiFactory/1.0") Q_DECLARE_METATYPE(GammaRay::ToolUiFactory *) #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define Q_PLUGIN_METADATA(x) #endif #endif gammaray-2.3.0/ui/variantcontainermodel.cpp000066400000000000000000000057531255003167400210400ustar00rootroot00000000000000/* variantcontainermodel.cpp This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "variantcontainermodel.h" using namespace GammaRay; VariantContainerModel::VariantContainerModel(QObject *parent) : QAbstractTableModel(parent) { } void VariantContainerModel::setVariant(const QVariant &variant) { beginResetModel(); m_variant = variant; endResetModel(); } int VariantContainerModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || (!m_variant.canConvert() && !m_variant.canConvert())) { return 0; } if (m_variant.canConvert()) { QSequentialIterable iter = m_variant.value(); return iter.size(); } QAssociativeIterable iter = m_variant.value(); return iter.size(); } int VariantContainerModel::columnCount(const QModelIndex &parent) const { if (parent.isValid() || (!m_variant.canConvert() && !m_variant.canConvert())) { return 0; } if (m_variant.canConvert()) { return 1; } if (m_variant.canConvert()) { return 2; } return 0; } QVariant VariantContainerModel::data(const QModelIndex &index, int role) const { if ((!m_variant.canConvert() && !m_variant.canConvert()) || !index.isValid()) { return QVariant(); } if (m_variant.canConvert()) { QSequentialIterable iter = m_variant.value(); if (role == Qt::DisplayRole) { return iter.at(index.row()); } } if (m_variant.canConvert()) { QAssociativeIterable iter = m_variant.value(); QAssociativeIterable::const_iterator it = iter.begin() + index.row(); if (role == Qt::DisplayRole) { if (index.column() == 0) return it.key(); if (index.column() == 1) return it.value(); } } return QVariant(); } gammaray-2.3.0/ui/variantcontainermodel.h000066400000000000000000000035261255003167400205010ustar00rootroot00000000000000/* variantsequencemodel.h This file is part of GammaRay, the Qt application inspection and manipulation tool. Copyright (C) 2013-2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Author: Stephen Kelly Licensees holding valid commercial KDAB GammaRay licenses may use this file in accordance with GammaRay Commercial License Agreement provided with the Software. Contact info@kdab.com if any conditions of this licensing are not clear to you. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef GAMMARAY_VARIANTCONTAINERMODEL_H #define GAMMARAY_VARIANTCONTAINERMODEL_H #include namespace GammaRay { /** Model showing sequence inside a QVariant instance.. */ class VariantContainerModel : public QAbstractTableModel { Q_OBJECT public: explicit VariantContainerModel(QObject *parent = 0); void setVariant(const QVariant &variant); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; private: QVariant m_variant; }; } #endif // GAMMARAY_VARIANTCONTAINERMODEL_H