pax_global_header00006660000000000000000000000064142717513500014517gustar00rootroot0000000000000052 comment=6a4e0b9cf6c0d240aac8f161a028992d50c0ad7d ddcui-0.3.0/000077500000000000000000000000001427175135000126075ustar00rootroot00000000000000ddcui-0.3.0/.gitignore000066400000000000000000000002661427175135000146030ustar00rootroot00000000000000temp* old/ *old new/ *~ *.autosave *.lo *temp *tmp temp/ *.txt *.bak *.ctl meson.build build* .settings .cproject .project *.lst *.tgz *.tar.gz ddcui-coverity.tgz config.h todo TODO ddcui-0.3.0/AUTHORS000066400000000000000000000000521427175135000136540ustar00rootroot00000000000000Sanford Rockowitz ddcui-0.3.0/CHANGELOG.md000066400000000000000000000146261427175135000144310ustar00rootroot00000000000000# Changelog ## [0.3.0] 2022-07-28 ### Added - CTL-Q terminates **ddcui** (does not apply within dialog boxes) ### Changed - Errors opening /dev/i2c and /dev/usb/hiddev devices are reporting using a message box instead of to the terminal. These are typically lack of permissions (Linux error EACCESS). - Optionally requiring the control key to be pressed when changing feature values now applies to all changes, not just those made using sliders. (The option is set using command line option ***--require-control-key*** or the UI Options dialog box). - A status message is issued when the control key is required. - Special handling for feature X60: - Allow extra sleep time before validation. (It was observed that a Dell U4320 returns a Null Message if getvcap for validation is called too quickly - For simple NC values, do not include the SH field in validation. (getvcp for feature x60 on U4320 returns non-zero SH.) - Options ***--force-slave-address*** and ***--disable-force-slave-address*** have no effect and are deprecated. ### Fixed - Option dialogs: Tab key was not jumping to the OK and Cancel buttons - Fix free() before final use in certain cases of function tracing. - Custom feature lists: Fix assert statements. - Memory leaks - Cast many pointers to ( void* ) to avoid compiler warnings ## [0.2.2] 2022-02-22 ### Fixed - Erroneous assert() statment that could cause compilation failure or segfault in ValueSpecialWidgetX62.cpp. ## [0.2.1] 2022-01-28 ### Added - Command line option ***--force-slave-address***. Its meaning for **ddcui** is the same as for **ddcutil**. See [Option: --force-slave-address](https://www.ddcutil.com/other_options/#option-force-slave-address) and section [Device Busy (EBUSY) Errors](https://www.ddcutil.com/release_notes/#device-busy-ebusy-errors) on the [ddcutil web site](https://www.ddcutil.com). - Command line option ***--disable-force-slave-address*** disables the setting in case it has been enabled by shared library configuration. ### Changed - If monitor communication fails because of Linux error EBUSY, the Summary view reports it as "Busy" instead of "Invalid" suggests use of option ***--force-slave-address***. - The Capabilities and Feature views for monitor cannot be selected if it doesn't support DDC/CI, or if the the capabilities string cannot be read. - Disable all view selection if no monitor is detected. - More consistently use the term "display" instead of "Monitor" in the user interface. - **ddcui** recognizes environment variable DDCUTIL_DEBUG_PARSE to enable tracing in command line parsing without recompiling. - CMakeLists.txt has been extensively updated. - The minimum supported version is specified as 3.10, as that is known to work. If need be, CMakeLists.txt can be edited to specify an earlier version and the script will likely still work. - The script uses command line option ***--log-level*** to control message output. Message level VERBOSE is new as of cmake 3.15. If the script is being executed on an earlier version, messages marked VERBOSE are treated as STATUS. - Command line option ***--use-cache*** controls whether ccache is used to speed builds (assuming it is installed). The default is ***--use-ccache=yes***. - Building in the source directories is not allowed. - Better support for cmake variable CMAKE_BUILD_TYPE. The default value is RelWithDebInfo. Validation of the supplied value has been factored out into file validate_CMAKE_BUILD_TYPE.cmake. - Requires glib version at least 2.40 for function g_option_context_strv(). ### Fixed - Segfaults - In particular, handle the pathological case, reported for Gentoo, where glib function g_option_context_parse_strv() fails but does not return an error message. - Numerous memory leaks - Code simplification, particularly for display initialization and error message propogation ### Removed - The "Use Latest Feature Values" setting in the NC Feature Values dialog, and corresponding command line option ***--use-latest-nc-values***. This feature was hard to document and convoluted to implement. Instead, the User Defined Features facility allows for definition of the possible NC feature values for a monitor feature. ## [0.2.0] 2021-10-15 This log summarizes user visible changes in **ddcui**. Though the list of changes is short, in fact the code base has been extensively reworked. For details, see [ddcui Release Notes](https://www.ddcutil.com/ddcui_release_notes). ### Added - Support VCP features, e.g. x62 (Audio Balance), that have both a continuous range. and a set of special values. The widget for these features has both a slider/spinbox for the continuous range, and a combo-box for the special values. - Desktop integration - Install ddcui.desktop in /usr/share/applications - Install icons in /usr/share/icons/hicolor, /usr/share/pixmaps - Install ddcui.appdata.xml in /usr/share/metainfo - Configuration file, typically $HOME/.config/ddcutil/ddcutilrc, which is shared with **ddcutil** and **libddcutil**. - Special handling for unrecognizd NC feature values - When obtaining the value id and names for a feature, **ddcui** normally uses the values and names specified for the monitor's MCCS version. Sometimes monitors use feature values defined in a later version. The ***Use Latest MCCS Values*** checkbox in the **NC Feature Values** dialog specifies that the NC value table for the highest applicable MCCS version be used. This can also be specified by command line option ***--force-latest-nc_value-names***. - Handle the case where a monitor reports a NC value that is not in the MCCS or capabilities list. - Menubar option Actions->Redetect Monitors tells libddcutil to redetect displays. The caller should replace its data structures to reflect the new list of monitors. ### Changed - Use "video-display" icon from Oxygen theme - Rename the "Other Options" dialog to "NC Feature Values" - Revise and extend help screen content - User interface cleanup - Command line option ***--help*** does not report deveelopment related options. Use ***--help-developmen*** or ***--help-all***. ### Removed - qmake is no longer supported, use cmake - Command line options affecting only libddcutil that can be specified instead in configuration file ddcutilrc: --udf, --no-udf, --nousb, --maxtries, --sleep-multiplier, --sleep-less, --less-sleep, --no-less-sleep, --dynamic-sleep-adjustment ddcui-0.3.0/CMakeLists.txt000066400000000000000000000350341427175135000153540ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10) message(STATUS "cmake version: ${CMAKE_VERSION}") # message(VERBOSE) requires cmake 3.15 if (CMAKE_VERSION VERSION_LESS 15) set(VERBOSE STATUS) else() set(VERBOSE VERBOSE) endif() set(ddcui_qt_version 5.5) set(ddcui_glib_version 2.40) # g_option_context_parse_strv() new in 2.40 set(ddcui_libddcutil_version 1.2.2) set(cmake_build_type_default "RelWithDebInfo") message(${VERBOSE} "Required Minimum Versions:") message(${VERBOSE} " ddcui_qt_version: ${ddcui_qt_version}" ) message(${VERBOSE} " ddcui_qlib_version: ${ddcui_glib_version}" ) message(${VERBOSE} " ddcui_libddcutil_version: ${ddcui_libddcutil_version}" ) option(USE_CCACHE "Use ccache" ON) message(STATUS "USE_CCACHE: ${USE_CCACHE}" ) string(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}) include(validate_CMAKE_BUILD_TYPE) project(ddcui VERSION 0.3.0 LANGUAGES C CXX) message(STATUS "Build type is: ${CMAKE_BUILD_TYPE} (CMAKE_BUILD_TYPE)") message(${VERBOSE} " CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}" ) message(${VERBOSE} " CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}" ) message(${VERBOSE} " CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}" ) message(${VERBOSE} " CMAKE_C_FLAGS_DEBUG: ${CMAKE_C_FLAGS_DEBUG}" ) message(${VERBOSE} " CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" ) message(${VERBOSE} " CMAKE_C_FLAGS_RELWITHDEBINFO: ${CMAKE_C_FLAGS_RELWITHDEBINFO}" ) message(${VERBOSE} " CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}" ) message(${VERBOSE} " CMAKE_C_FLAGS_RELEASE: ${CMAKE_C_FLAGS_RELEASE}" ) # message(${VERBOSE} "Project variables:") # message(${VERBOSE} " PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR}" ) # message(${VERBOSE} " PROJECT_BINARY_DIR ${PROJECT_BINARY_DIR}" ) message(STATUS "Source directory: ${CMAKE_SOURCE_DIR} (CMAKE_SOURCE_DIR)" ) message(STATUS "Build directory: ${CMAKE_BINARY_DIR} (CMAKE_BINARY_DIR)" ) if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} ) message(WARNING "Attempting to build in source directory.") if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13") message(WARNING "Use -B option to set the build directory.") endif() endif() set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) # add_compile_definitions(QT_NO_DEBUG) find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND AND USE_CCACHE) message( STATUS "Using ccache to improve build performance" ) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) endif() # set (coverity_cflags --type_traits_helpers) # set (coverity_cflags --no_predefined_feature_test_macros) # set (COVERITY_DUMMIES OFF) message(${VERBOSE} "Significant environment variables:") message(${VERBOSE} " INCLUDE: $ENV{INCLUDE}") message(${VERBOSE} " LD_LIBRARY_PATH: $ENV{LD_LIBARARY_PATH}") message(${VERBOSE} " PKG_CONFIG_PATH: $ENV{PKG_CONFIG_PATH} ") message(${VERBOSE} "cmake paths:") message(${VERBOSE} " CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}") message(${VERBOSE} " CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") message(${VERBOSE} " CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}" ) message(${VERBOSE} " CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}" ) message(${VERBOSE} " EXCECUTABLE_OUTPUT_PATH: ${EXECUTABLE_OUTPUT_PATH}" ) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Find includes in corresponding build directories, needed for config.h set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) message( ${VERBOSE} "Qt settings:") message( ${VERBOSE} " CMAKE_AUTOUIC: ${CMAKE_AUTOUIC}") message( ${VERBOSE} " CMAKE_AUTOMOC: ${CMAKE_AUTOMOC}") message( ${VERBOSE} " CMAKE_AUTORCC: ${CMAKE_AUTORCC}") # message( ${VERBOSE} "AUTOGEN_BUILD_DIR: ${AUTOGEN_BUILD_DIR}") overrides default location set(QT5_LIBRARIES Qt5::Widgets ) # Ensures all Qt componenets have same version: find_package(Qt5 ${ddcui_qt_version} COMPONENTS Core Widgets Gui Help REQUIRED) message( ${VERBOSE} "Qt directories:") message( ${VERBOSE} " Qt5Widgets_INCLUDE_DIRS: ${Qt5Widgets_INCLUDE_DIRS}" ) message( ${VERBOSE} " Qt5Core_INCLUDE_DIRS: ${Qt5Core_INCLUDE_DIRS}" ) message( ${VERBOSE} " Qt5Gui_INCLUDE_DIRS: ${Qt5Gui_INCLUDE_DIRS}" ) message( ${VERBOSE} " Qt5Help_INCLUDE_DIRS: ${Qt5Help_INCLUDE_DIRS}" ) find_package (PkgConfig REQUIRED ) pkg_check_modules(GLIB2 REQUIRED glib-2.0>=${ddcui_glib_version}) pkg_check_modules(DDCUTIL REQUIRED ddcutil>=${ddcui_libddcutil_version}) # set(DDCUTIL_LIBRARY_DIRS /usr/lib/x86_64-linux-gnu/) # hack for testing message( ${VERBOSE} "Set by pkg-config:" ) message( ${VERBOSE} " GLIB2_INCLUDE_DIRS: ${GLIB2_INCLUDE_DIRS}" ) message( ${VERBOSE} " GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}" ) message( ${VERBOSE} " DDCUTIL_INCLUDE_DIRS: ${DDCUTIL_INCLUDE_DIRS}" ) message( ${VERBOSE} " DDCUTIL_LIBRARY_DIRS: ${DDCUTIL_LIBRARY_DIRS}" ) message( ${VERBOSE} " DDCUTIL_LIBRARIES: ${DDCUTIL_LIBRARIES}" ) configure_file(cconfig.h.in config.h) set(SOURCES src/c_util/data_structures.c src/c_util/ddcutil_config_file.c src/c_util/file_util_base.c src/c_util/glib_util.c src/c_util/debug_util.c src/c_util/report_util.c src/c_util/simple_ini_file.c src/c_util/string_util.c src/c_util/xdg_util.c src/base/core.cpp src/base/ddca_utils.cpp src/base/ddcui_parms.cpp src/base/feature_list.c src/base/feature_selector.cpp src/base/global_state.cpp src/base/monitor.h src/base/nc_values_state.cpp src/base/user_interface_options_state.cpp src/base/widget_debug.cpp src/core_widgets/hex_number_validator.cpp src/core_widgets/hline_widget.cpp src/core_widgets/number_entry_widget.cpp src/core_widgets/spin_slider.cpp src/cmdline/ddcui_cmd_parser.c src/cmdline/ddcui_cmd_parser_aux.c src/cmdline/ddcui_parsed_cmd.c src/nongui/ddca_simulator.cpp src/nongui/feature_base_model.cpp src/nongui/feature_value.cpp src/nongui/msgbox_queue.cpp src/nongui/vcprequest.cpp src/nongui/vcpthread.cpp src/monitor_desc/monitor_desc_actions.cpp src/monitor_desc/monitor_desc_ui.cpp src/feature_value_widgets/value_2button_widget.cpp src/feature_value_widgets/value_base_widget.cpp src/feature_value_widgets/value_bytes_widget.cpp src/feature_value_widgets/value_cnc_widget_x14.cpp src/feature_value_widgets/value_nc_widget.cpp src/feature_value_widgets/value_ncplus_widget.cpp src/feature_value_widgets/value_new_cont_widget.cpp src/feature_value_widgets/value_reset_widget.cpp src/feature_value_widgets/value_simple_cont_widget.cpp src/feature_value_widgets/value_special_widget_x62.cpp src/feature_value_widgets/value_stacked_widget.cpp src/feature_value_widgets/value_std_widget.cpp src/feature_scrollarea/feature_widget.cpp src/feature_scrollarea/feature_widget_header.cpp src/feature_scrollarea/features_scrollarea.cpp src/feature_scrollarea/features_scrollarea_contents.cpp src/feature_scrollarea/features_scrollarea_ui.cpp src/feature_scrollarea/features_scrollarea_view.cpp src/help/help_dialog.cpp src/help/help_browser.cpp ddcui.qrc src/action_dialogs/debug_actions_dialog.cpp src/option_dialogs/feature_selection_dialog.cpp src/option_dialogs/nc_values_dialog.cpp src/option_dialogs/user_interface_options_dialog.cpp src/main/main.cpp src/main/mainwindow.cpp src/main/mainwindow_ui.cpp src/main/monitor.cpp src/main/msgbox_thread.cpp ) # file(GLOB dummy_SOURCES src/dummies/*.cpp) # if (COVERITY_DUMMIES) # set (SOURCES ${SOURCES} ${dummy_SOURCES} ) # endif() set(UI_SOURCES src/option_dialogs/feature_selection_dialog.ui src/option_dialogs/nc_values_dialog.ui src/option_dialogs/user_interface_options_dialog.ui src/action_dialogs/debug_actions_dialog.ui ) # must come before add_executable(): link_directories(${DDCUTIL_LIBRARY_DIRS}) # qt5_wrap_ui(UI_GENERATED_HEADERS ${UI_SOURCES}) # add_executable(ddcui ${SOURCES} ${UI_GENERATED_HEADERS}) add_executable(ddcui ${SOURCES}) # -Wno-format-pedantic -Wno-sign-compare -std=c++20 -Wno-format -pedantic -Wextra -Wall # set(more_options -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-parameter -Wno-non-pod-varargs ) target_compile_options(ddcui PUBLIC "-fPIC" ${coverity_cflags}) # add_compile_options(-Og -H V=1) # redundant: ${Qt5Gui_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS}. # ${Qt5Help_INCLUDE_DIRS} is a superset of them all target_include_directories(ddcui SYSTEM PRIVATE ${Qt5Help_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} ${DDCUTIL_INCLUDE_DIRS}) target_include_directories(ddcui PRIVATE src) get_property(dirs TARGET ddcui PROPERTY INCLUDE_DIRECTORIES) message( ${VERBOSE} "INCLUDE_DIRECTORIES: ${dirs}" ) message( ${VERBOSE} "Expanded:" ) foreach(d ${dirs}) message(${VERBOSE} " ${d}") endforeach() # Use the Widgets module from Qt 5. target_link_libraries(ddcui Qt5::Widgets ${GLIB2_LIBRARIES} ${DDCUTIL_LIBRARIES}) ### make clean # ADDITIONAL_MAKE_CLEAN_FILES( ... ) ### make install # define GNU standard installation directories include(GNUInstallDirs) message( ${VERBOSE} "GNU installation directories:") message( ${VERBOSE} " CMAKE_INSTALL_BINDIR: ${CMAKE_INSTALL_BINDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}" ) message( ${VERBOSE} " CMAKE_INSTALL_DATATROOTDIR: ${CMAKE_INSTALL_DATAROOTDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_SYSCONFDIR: ${CMAKE_INSTALL_SYSCONFDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_LIBEXECDIR: ${CMAKE_INSTALL_LIBEXECDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_INCLUDEDIR: ${CMAKE_INSTALL_INCLUDEDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_INFODIR: ${CMAKE_INSTALL_INFODIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_MANDIR: ${CMAKE_INSTALL_MANDIR}" ) message( ${VERBOSE} " CMAKE_INSTALL_DOCDIR: ${CMAKE_INSTALL_DOCDIR}" ) # Special handling for openSuse and SLE. # Normally, documentation files are stored in directory /usr/share/doc/ddcui. # The value of CMAKE_INSTALL_DOCDIR is "share/doc/ddcui". However, on SuSE # systems, doc files are instead stored in directory /usr/share/doc/packages/ddcui. # However, CMAKE_INSTALL_DOCDIR is still set to "share/doc/ddcui". # The following code tries to determine if we're running on a system where # the value of CMAKE_INSTALL_DOCDIR needs to be changed to "share/doc/packages/ddcui". # For SuSe (and Fedora) file /etc/os-release is automatically installed # from the default packages. However, for SLE it is not, so the os-release check # is not possible. Instead, a heuristic test is performed. set(suse_special_case FALSE) if(EXISTS "/etc/os-release") message(STATUS "File /etc/os-release found") file(STRINGS "/etc/os-release" id_line REGEX "^ID=(.*)$") string(STRIP ${id_line} id_line) # Testcases: # set(id_line "ID=\"opensuse-leap\"") # set(id_line "ID=opensuse-leap") # message(STATUS "id_line: |${id_line}|") string(SUBSTRING ${id_line} 3 -1 distro_name0) string(SUBSTRING ${distro_name0} 0 1 ch) if (ch STREQUAL "\"") string(LENGTH ${distro_name0} len) math(EXPR l2 "${len}-2") string(SUBSTRING ${distro_name0} 1 ${l2} distro_name0) endif() string(SUBSTRING ${distro_name0} 0 8 distro_name) message(STATUS "Distribution: distro_name = |${distro_name}|") if( distro_name STREQUAL "opensuse" ) # message(STATUS "distro_name matches opensuse") set(suse_special_case TRUE) endif() else() message(STATUS "File /etc/os-release NOT found. Performing heuristic test for doc directory.") # Heuristic test for suse set(dir_to_test "/usr/share/doc/packages") file(GLOB globbed "${dir_to_test}/*") string(LENGTH "${globbed}" len_globbed) if (${len_globbed} GREATER 0) set(suse_special_case TRUE) message(STATUS "Found non-empty /usr/share/doc/packages") endif() endif() if (${suse_special_case}) message(STATUS "suse special handling, setting CMAKE_INSTALL_DOCDIR") set(CMAKE_INSTALL_DOCDIR "share/doc/packages/ddcui") endif() message(STATUS "After possible fixup CMAKE_INSTALL_DOCDIR: ${CMAKE_INSTALL_DOCDIR}") install(TARGETS ddcui DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(FILES man/ddcui.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) # message(STATUS "suse_special_case = ${suse_special_case}") # if ( suse_special_case ) # message(STATUS "Installing to opensuse location") # install(FILES AUTHORS CHANGELOG.md NEWS.md README.md # DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/packages/ddcui) # else() install(FILES AUTHORS CHANGELOG.md NEWS.md README.md DESTINATION ${CMAKE_INSTALL_DOCDIR}) # endif() install(FILES ddcui.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications) install(FILES ddcui.appdata.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo) install(FILES icons/video-display-128px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps RENAME ddcui.png) install(FILES icons/video-display-64px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps RENAME ddcui.png) install(FILES icons/video-display-48px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps RENAME ddcui.png) install(FILES icons/video-display-32px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps RENAME ddcui.png) install(FILES icons/video-display-16px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps RENAME ddcui.png) # install(FILES icons/ddcui.svg DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps) # GNOME classic only looks in pixmaps for icons: # install(FILES icons/ddcui-48px.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps RENAME ddcui.png) ### make uninstall # per https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake # uninstall target if(NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() ddcui-0.3.0/COPYING000066400000000000000000000432541427175135000136520ustar00rootroot00000000000000 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. ddcui-0.3.0/NEWS.md000066400000000000000000000006611427175135000137100ustar00rootroot00000000000000ddcui ===== The [ddcutil website](http://www.ddcutil.com) is the primary location of information for ddcui users. Recent announcements can be found on the [home page](http://www.ddcutil.com). Earlier announcements are located at [prior announcements](http://www.ddcutil.prior_announcements). Detailed information about user-visible changes for each release are located at [release notes](http://www.ddcutil.com/release_notes). ddcui-0.3.0/README.md000066400000000000000000000023531427175135000140710ustar00rootroot00000000000000**ddcui** ======= **ddcui** is a graphical user interface for **ddcutil**, implemented using Qt. ![ddcui_features](/screenshots/ddcui_features.png) For a guide to building **ddcui** from source, see [Building ddcui](http://www.ddcutil.com/building_ddcui) in the ddcutil documentation. Note that it is possible for feature values reported by **ddcui** to become out of sync with actual monitor values. - If feature values are changed using the monitor's On Screen Display. - If feature values are changed by another program, including the command line program **ddcutil**. - Some monitors will change their state (e.g. red gain) when the value in the GUI changes. However, the value reported by the monitor is unchanged. - Conversely, some monitors report a newly set value, but the observed state of the monitor is unchanged. The first two cases can generally be corrected by menu item ***Actions->Rescan Feature Values***. ## User Support Please direct technical support questions, bug reports, and feature requests to the [Issue Tracker](https://github.com/rockowitz/ddcui/issues) on the github repository. Use of this forum allows everyone to benefit from individual questions and ideas. ## Author Sanford Rockowitz ddcui-0.3.0/cconfig.h.in000066400000000000000000000004471427175135000150020ustar00rootroot00000000000000#ifndef DDCUI_CMAKE_CONFIG_H #define DDCUI_CMAKE_CONFIG_H // config.h template file, CMake version #define DDCUI_VSTRING "${PROJECT_VERSION}" #define DDCUI_VMAJOR ${PROJECT_VERSION_MAJOR} #define DDCUI_VMINOR ${PROJECT_VERSION_MINOR} #define DDCUI_VMICRO ${PROJECT_VERSION_PATCH} #endif ddcui-0.3.0/cmake_uninstall.cmake.in000066400000000000000000000020551427175135000173710ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) message(STATUS "root access may be required to remove old files") string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) ddcui-0.3.0/ddcui.appdata.xml000066400000000000000000000064311427175135000160360ustar00rootroot00000000000000 com.ddcutil.ddcui CC0-1.0 CC0-1.0 ddcui Manage monitor settings

Communicates with a monitor's Virtual Control Panel (VCP) to query or change monitor settings, such as brightness, red gain, and power on hours. In general, settings and information that can be accessed using the monitor's On Screen Display can more easily be accessed using this application.

ddcui normally communicates with the monitor using the DDC/CI protocol on a /dev/i2c device exposed by the video driver. Alternatively, ddcui supports monitors that use USB for VCP communication.

The corresponding command line program is ddcutil.

ddcui.desktop https://www.ddcutil.com/images/ddcui_features.png Feature Detail View https://www.ddcutil.com/images/ddcui_summary.png Summary View https://www.ddcutil.com/images/ddcui_capabilities.png Capabilities View rockowitz@minsoft.com> Sanford Rockowitz https://www.ddcutil.com https://github.com/rockowitz/ddcui/issues https://www.ddcutil.com/faq
ddcui-0.3.0/ddcui.desktop000066400000000000000000000004201427175135000152660ustar00rootroot00000000000000[Desktop Entry] Version=1.1 Name=ddcui GenericName=Monitor Settings Comment=Control monitor settings Keywords=ddcutil;DDC/CI;MCCS Exec=ddcui TryExec=ddcui Icon=ddcui Terminal=false Type=Application Categories=Settings;HardwareSettings; X-Desktop-File-Install-Version=0.24 ddcui-0.3.0/ddcui.qrc000066400000000000000000000012451427175135000144100ustar00rootroot00000000000000 ./docs/help_actions_debug.html ./docs/help_actions_menu.html ./docs/help_feature_selection.html ./docs/help_features_view.html ./docs/help_general.html ./docs/help_help_menu.html ./docs/help_limitations.html ./docs/help_menu_bar.html ./docs/help_nc_values.html ./docs/help_options_menu.html ./docs/help_toolbar.html ./docs/help_ui_options.html ./icons/ddcui_multires.ico ddcui-0.3.0/docs/000077500000000000000000000000001427175135000135375ustar00rootroot00000000000000ddcui-0.3.0/docs/.gitignore000066400000000000000000000000261427175135000155250ustar00rootroot00000000000000ddcui.qhp ddcui.qhcp ddcui-0.3.0/docs/help_actions_debug.html000066400000000000000000000010661427175135000202460ustar00rootroot00000000000000 ddcui - Execution Statistics

Execution Statistics

The Execution Statistics dialog box reports performance statistics. These are the same statistics as are shown by the --stats option of program ddcutil.

If Extended Stats is checked, detailed per-thread statistics are reported. Normally only aggreagate statistics are reported. ddcui-0.3.0/docs/help_actions_menu.html000066400000000000000000000017301427175135000201220ustar00rootroot00000000000000 ddcui - Actions Menu

Actions Menu

The Actions menu has the following actions:
  • Redetect Displays - Use if a monitor is connected or disconnected.
  • Rescan Feature Values - The values shown in the Features view can become out of sync with a monitor's actual values. For example, the user can change values using the monitor's On Screen Display, or another program can change the values. This action causes feature values to be reread from the monitor.
  • Execution Statistics Report execution statistics, corresponding to those of ddcutil option --stats.
ddcui-0.3.0/docs/help_feature_selection.html000066400000000000000000000050061427175135000211360ustar00rootroot00000000000000 ddcui - Feature Selection

Feature Selection

The Feture Selection dialog controls the features shown in the Features view. Features are specified as a group, and further refined by filters on the group.

Feature Groups

  • MCCS - All features defined in the MCCS specification for the VCP version reported by the monitor. Includes features in the manufacturer specific range (xe0..xff)
  • Capabilities - All features listed in the capabilities string.
  • Scan - Examine all possible feature codes, except those known to be read-only or of type Table
  • Manufacturer - Examine feature codes in the range reserved for use by manufacturers (xe0..xff)
  • Color - Color related feature codes.
  • Custom - A list of 2 byte feature codes, separated by blanks and/or commas. Each feature must contain 2 hexadecimal characters, optionally preceded by 'x' or followed by 'h'. The hex digits, prefix, and suffix are case-insensifive.

Feature Filters


The features selected can further be refined by filters. Not all filters apply to every group.
  • Include all features in the capabilities string - Add all features in the capabilities string to those in the group.
  • Exclude features not in the capabilities string - Include only features in the group that are also found in the capabilities string
  • Show Unsupported Features - Include features in the group that are reported as unsupported.
ddcui-0.3.0/docs/help_features_view.html000066400000000000000000000040311427175135000203030ustar00rootroot00000000000000 ddcui - Features View

Features View

The Features view has the following columns:
  • Feature code - A one byte hexadecimal number
  • Feature name - Can vary depending on the version of the Monitor Control Command Specification that the monitor implements.
  • RW, RO, WO - Indicates if the feature can be read and/or written.
  • Type field. - C for "continuous" features, and NC for "non-continuous". Continuous features can take any of range of values up to some maximum value, for example feature x10 brightness typically takes values in the range 0..100 or the range 0.255. Simple Non-continous features are can take one of a limited set of values, for example x60 Input Source. Complex Non-Continuous features, those that have feature-specific definitions, e.g. x9c Display Firmware Level, or xd9 VCP Version. These features are almost always RO. As the MCCS specification has evolved, NC has become a grab-bag for features that are not clearly caterorizable as Continuous or Non-Continuous.
  • Feature Value - The form of the feature value field depends on the feature. Modifyable Continuous features have a slider and spin box, either of which can be used to change the value. Modifyable simple Non-Continuous features typically have a drop down combo box showing the possible values. Features in the range xE0..xFF are reserved for manufacturer use. As ddcui does not know how to interpret them, it simply allows for editing the individual bytes of the value.
ddcui-0.3.0/docs/help_general.html000066400000000000000000000024001427175135000170460ustar00rootroot00000000000000 ddcui Overview

ddcui

ddcui communicates with a monitor's Virtual Control Panel using the DDC/CI protocol. It allows for reading and changing monitor settings such as brightness, color, and input source, and for querying read-only values such as power on hours. It is a graphical user interface for ddcutil

Topics:

ddcui-0.3.0/docs/help_help_menu.html000066400000000000000000000012271427175135000174130ustar00rootroot00000000000000 ddcui - Help Menu

Help Menu

The Help menu opens the usual help-related dialog boxes.
  • Contents - Primary help screen.
  • About ddcui - Build and copyright information for ddcui.
  • About Qt - Information about the Qt framework used to build ddcui.
ddcui-0.3.0/docs/help_limitations.html000066400000000000000000000044401427175135000177730ustar00rootroot00000000000000 ddcui - Limitations

Fundamental Limitations

Inadequacies in the DDC/CI design, and its marginal implementation in many monitors, lead to some problems for which ddcui has no good workaround.

  • Actual monitor settings may not match those reported by ddcui
    • Some monitors will change their state (e.g. red gain) when the value in the GUI changes. However, the value reported by the monitor is unchanged.
    • Conversely, some monitors report a newly set value, but the observed state of the monitor is unchanged.
    • Monitor settings can be changed by another program, including the command like program ddcutil
    • If feature values are changed using the monitor's On Screen Display. The DDC/CI specification includes a mechanism for informing a program of changes made using the OSD. In practice, this facility cannot be relied on.
    • The DDC/CI and Monitor Control Command Set specifications are old. Advanced features of recent monitors, such as Picture-by-Picture were simply not envisioned and have no (at least documented) integration to the Virtual Control Panel.
  • It is possible for feature values reported in **ddcui** to become out of sync with actual monitor values.
    • If feature values are changed using the monitor's On Screen Display.
    • If feature values are changed by another program, including the command line program **ddcutil**.
    • Some monitors will change their state (e.g. red gain) when the value in the GUI changes. However, the value reported by the monitor is unchanged.
    • Conversely, some monitors report a newly set value, but the observed state of the monitor is unchanged.

    Implementation

    • ddcui does not detect that a monitor has been connected or disconnected. The program must be restarted.
    • The value of various special feature codes is not interpreted, but instead simply reported as bytes. Interpretations of these feature codes will be added with time.
    ddcui-0.3.0/docs/help_menu_bar.html000066400000000000000000000035301427175135000172260ustar00rootroot00000000000000 ddcui - Menu Bar

    Menu Bar

    The Menu Bar has several drop-down menus:

    View

    For each detected display, the View menu provides 3 different views of monitor information. (If DDC communication with the monitor is unsuccessful, only the Monitor Summary view can be selected.

    The views are:
    • Monitor Summary - Identifying information about the monitor, along with the first 128 bytes of the monitor's EDID block, in hex form.
    • Capabilities - Reports the capabilities string returned by the monitor, along with interpretation based on the MCCS specification.
    • Features - Displays each of the feature codes detected, and allows for editing of feature values where appropriate. Errors for individual features are reported here. See Features View

    Actions

    This menu controls various actions. See Actions Menu

    Options

    The Options menu contains dialog boxes that tailor ddcui behavior. See Options Menu

    Help

    This menu contains the usual help related entries. See Help Menu ddcui-0.3.0/docs/help_nc_values.html000066400000000000000000000043151427175135000174170ustar00rootroot00000000000000 ddcui - Non-Continuous Feature Values

    Non-Continuous Feature Values

    Source of Non-Continuous Feature Values

    This option indicates the source of the values shown in the combo box for simple Non-Continuous (NC) features. There are two sources for the value codes. Each has advantages and disadvantages. The choices are:

    • Monitor Control Command Set - The VESA Monitor Control Command Set specification (MCCS) lists valid values for simple Non-Continuous (NC) features, along with their names.

      The advantage of this source is completeness. Valid values can vary by MCCS version, and ddcui takes this into account. The disadvantage is that the list of values for a feature may well include values that do not apply to the particular monitor. Also, the monitor may implement additional manufacturer specific values.

    • Capabilites String - The capabilities string reported by the monitor indicates the allowed values for simple Non-Continuous features. If this option is chosen, the values are those listed in the string. Unfortunately, the capabilities string is sometimes wrong. The capabilities string lists only hex numbers for allowed feature values. The names of values come from MCCS.
    • Both MCCS and Capabilities - The values shown are the union of those in the MCCS specification and those in the capabilities string.
    ddcui-0.3.0/docs/help_options_menu.html000066400000000000000000000013761427175135000201630ustar00rootroot00000000000000 ddcui - Options Menu

    Options Menu

    The Options menu opens dialog boxes for tailoring ddcui execution. ddcui-0.3.0/docs/help_toolbar.html000066400000000000000000000004731427175135000171030ustar00rootroot00000000000000 ddcui - Toolbar

    Toolbar

    The Toolbar has one widget:

    Display Selector

    Selects the monitor to communicate with. ddcui-0.3.0/docs/help_ui_options.html000066400000000000000000000007341427175135000176310ustar00rootroot00000000000000 >ddcui - User Interface Options

    User Interface Options

    Require control key to change values

    When swiping or scrolling with a mouse it is possible to indvertently change values. If this option is checked, values can only be changed when a control key is held down. ddcui-0.3.0/icons/000077500000000000000000000000001427175135000137225ustar00rootroot00000000000000ddcui-0.3.0/icons/COPYING000066400000000000000000000232231427175135000147570ustar00rootroot00000000000000The files in this directory are extracted and possibly renamed from video-display.png in from package oxygen-icons5 in the KDE framework. Following is the copyright notice from that package. The Oxygen Icon Theme Copyright (C) 2007 Nuno Pinheiro Copyright (C) 2007 David Vignoni Copyright (C) 2007 David Miller Copyright (C) 2007 Johann Ollivier Lapeyre Copyright (C) 2007 Kenneth Wimer Copyright (C) 2007 Riccardo Iaconelli and others 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 3 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, see . Clarification: The GNU Lesser General Public License or LGPL is written for software libraries in the first place. We expressly want the LGPL to be valid for this artwork library too. KDE Oxygen theme icons is a special kind of software library, it is an artwork library, it's elements can be used in a Graphical User Interface, or GUI. Source code, for this library means: - where they exist, SVG; - otherwise, if applicable, the multi-layered formats xcf or psd, or otherwise png. The LGPL in some sections obliges you to make the files carry notices. With images this is in some cases impossible or hardly useful. With this library a notice is placed at a prominent place in the directory containing the elements. You may follow this practice. The exception in section 5 of the GNU Lesser General Public License covers the use of elements of this art library in a GUI. kde-artists [at] kde.org ----- GNU LESSER 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. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ddcui-0.3.0/icons/ddcui.ico000066400000000000000000004066101427175135000155150ustar00rootroot00000000000000€€ (f hŽ ˆö   ¨•00 ¨%¸¥@@ (B`Ë(€ ¹n¹n 0FS ] `bdddddddccccccccccccccbbbbbbbbbbbbbaaaaaaaaaaaaaa````````_\ZXSJ?*µ³±QÍÊÇîÄÁ»üËÆÀÿÌÈÃÿÎÉÄÿÏËÆÿÐÌÇÿÒÍÈÿÓÏÊÿÔÐËÿÖÑÍÿ×ÒÎÿØÔÐÿÙÕÑÿÚÖÓÿÛØÔÿÜÙÕÿÞÚÖÿßÜØÿáÝÙÿãÞÛÿäáÝÿåâßÿæãáÿçåâÿéæãÿêçåÿëèæÿëéçÿíêèÿîëéÿîìêÿðíëÿðíëÿñîìÿñîìÿðîìÿðíëÿðíëÿîìêÿíëéÿìêèÿëéçÿêèåÿéçäÿèæãÿçäâÿæãàÿäâßÿäàÝÿâßÜÿáÞÚÿàÜ×ÿßÛ×ÿÝÚÕÿÜ×ÔÿÛ×ÒÿÙÕÑÿÙÓÏÿÖÒÎÿÕÑÌÿÔÐËÿÓÏÊÿÑÍÈÿÐÌÇÿÏÊÅÿÍÉÄÿÌÇÂÿÉľýÝÚØô´±¯YåâàlííëÿçäâÿçæãÿèæäÿèæäÿéæåÿéçæÿêèæÿêèæÿëéçÿëéçÿìêèÿìêèÿíìéÿîëêÿîìêÿïíìÿïíëÿïîìÿðîíÿñïíÿñïîÿòñîÿòñïÿòòïÿóóñÿóóòÿôóòÿôóòÿôóóÿõóòÿõóòÿõôòÿõôòÿõôòÿõôóÿõôóÿõôòÿõôòÿõóòÿõóóÿôóóÿôôòÿôóòÿóóñÿôòñÿóòðÿóñðÿòñïÿòðïÿñðîÿñïíÿïïíÿïîìÿîîìÿîíëÿíìêÿíìêÿìëéÿìëéÿìêèÿìêçÿêéçÿêéæÿéèæÿéèåÿèçäÿèæäÿçæãÿóòðÿàÜÛoª¥¡k…~yÿrkeÿqjdÿrjdÿrkeÿrkeÿrkeÿsleÿslfÿslfÿslfÿsmgÿsmgÿtmgÿtmgÿtmgÿtmgÿtmgÿtmgÿsmgÿsmfÿslfÿslfÿslfÿrleÿrkeÿrkeÿrjdÿtmgÿvoiÿvoiÿuniÿunhÿtmhÿtmgÿslfÿslfÿrkeÿrkeÿqjdÿpjcÿohbÿjc[ÿib[ÿia[ÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿjb\ÿ}wrÿ¥ œnqic#yslú{tnÿ{tnÿ|uoÿ|uoÿ|vpÿ}vpÿ}wpÿ}wqÿ~wqÿ~wqÿ~xqÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~wqÿ~wqÿ}wqÿ}wpÿ}vpÿ|vpÿ|uoÿ|uoÿ~xrÿ‚{vÿ{vÿzuÿ€zuÿ€ytÿytÿxsÿ~xsÿ~wrÿ~wqÿ}vqÿ}vpÿ{tnÿtmgÿsleÿrkeÿrkdÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿpicûjc]#~wrž{tÿ‚{uÿ‚{uÿ‚|vÿƒ|vÿƒ}wÿ„}wÿ„}wÿ„~xÿ„~xÿ…~xÿ…~xÿ…yÿ…yÿ…yÿ…yÿ…yÿ…xÿ…~xÿ…~xÿ„~xÿ„~wÿ„}wÿƒ}wÿƒ}vÿ‚|vÿ‚|uÿ†zÿ‰ƒ}ÿ‰ƒ}ÿˆ‚}ÿˆ‚|ÿ‡‚|ÿ‡{ÿ†€{ÿ†€zÿ…zÿ…yÿ„~xÿ„}xÿ‚|vÿ{tnÿzslÿyrkÿxqkÿxqjÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿunhŸ{up"‡|úˆ‚|ÿˆ‚}ÿ‰‚}ÿ‰ƒ}ÿŠƒ~ÿŠ„~ÿŠ„ÿ‹„ÿ‹…ÿ‹…€ÿ‹…€ÿ‹…€ÿŒ…€ÿŒ…€ÿŒ…€ÿŒ…€ÿ‹…€ÿ‹…€ÿ‹…ÿ‹„ÿŠ„ÿŠ„~ÿŠƒ~ÿ‰ƒ~ÿ‰ƒ}ÿ‰‚}ÿŽˆƒÿŠ…ÿ‰„ÿŽˆƒÿŽˆƒÿˆ‚ÿ‡‚ÿŒ‡ÿŒ†ÿ‹…€ÿ‹…ÿŠ„ÿŠ„ÿŠ„ÿƒ}wÿ€ysÿysÿxrÿ~wqÿ~wqÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpûtnh#‹„œŽˆ‚ÿˆƒÿ‰ƒÿ‰„ÿŠ„ÿŠ…ÿ‘Š…ÿ‘‹†ÿ‘‹†ÿ‘‹†ÿ’Œ†ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ†ÿ’‹†ÿ‘‹†ÿ‘‹†ÿ‘Š…ÿŠ…ÿŠ„ÿ‰„ÿ‰„ÿŠ„ÿ”ŽŠÿ“ˆÿ’Œ‡ÿ’Œ†ÿ‘‹…ÿ‘Š…ÿŠ„ÿ‰ƒÿ‰‚ÿŽˆ‚ÿއ‚ÿ‡ÿ‡ÿއ‚ÿ‹„ÿ†€zÿ†yÿ…~xÿ„~xÿ„}wÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿztž‡‚|!”މú•‰ÿ•Šÿ–Šÿ–‹ÿ—‹ÿ—‘‹ÿ—‘Œÿ—‘Œÿ˜’Œÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜‘Œÿ—‘Œÿ—‘Œÿ—‹ÿ—‘Œÿž™”ÿ¨£Ÿÿ«¦¡ÿ¡œ–ÿ›“ÿ–‰ÿ‘‹…ÿŒ…ÿˆ‚|ÿ…xÿ„}wÿ…~xÿ†yÿŠƒ|ÿˆ€ÿ’‹„ÿ–އÿ•އÿ”†ÿ‘‰ƒÿ†ÿ‹„~ÿŠƒ~ÿŠƒ}ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ú€zs#–‹››•ÿ›•ÿœ–‘ÿœ–‘ÿ–’ÿ—’ÿ—“ÿž˜“ÿž˜“ÿž˜”ÿž˜”ÿž˜”ÿŸ™”ÿŸ˜”ÿž˜”ÿž˜”ÿž˜”ÿž˜“ÿ—“ÿ š–ÿ¨¢žÿ­¨¤ÿ œ™ÿœš—ÿš–ÿ‰…ÿŠƒ|ÿ‡ÿ‘Š‚ÿ–†ÿ˜‡ÿ™‡ÿ™†ÿ–Œÿ‘ˆ~ÿŽ…|ÿŠyÿ†wÿƒ{sÿxrÿ~wqÿ{vÿ’‹…ÿ›•ÿœ–ÿ‘Š„ÿ‰ƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿŒ†€’Œˆ ¡š–ù¡›–ÿ¡›—ÿ¢œ—ÿ¢œ˜ÿ£˜ÿ£™ÿ¤ž™ÿ¤žšÿ¤žšÿ¤žšÿ¥Ÿšÿ¥Ÿšÿ¥Ÿšÿ¤žšÿ¤žšÿ¤žšÿ¤ž™ÿ©¤ ÿ¦¢Ÿÿ‹‡ÿ¢ŸœÿÌÊÈÿïîíÿâàÜÿÁ½¸ÿ´°ªÿ±­§ÿ¯ª¦ÿ­¨¤ÿ­¨¤ÿ¬¨¥ÿ­¨¥ÿ­©¥ÿ­¨¦ÿ®ª¥ÿ°«¨ÿ³®©ÿµ¯ªÿ¶°©ÿ¹³¬ÿ¥Ÿ—ÿއÿ„zÿ“‹ÿ®©¥ÿ–Šÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މúŠ„"¢˜™§¡œÿ§¡ÿ¨¡ÿ¨¢žÿ¨¢žÿ©£Ÿÿ©£Ÿÿª¤ ÿª¤ ÿª¤ ÿ«¥ ÿ«¥¡ÿ«¥ ÿª¥ ÿª¤ ÿª¤ ÿ©£Ÿÿ£ž›ÿ¯«©ÿÐÎÉÿÇÃÀÿ±­©ÿ™“ŽÿŠ…ÿ•Šÿ–Œÿ–Œÿ–‘Œÿ–‘ÿ—‘ÿ—‘Žÿ—’Žÿ—’Žÿ˜“ÿ˜“ÿ˜“ÿ˜”ÿš“ÿ’Œ‡ÿ‘‹†ÿ¥ ›ÿ±¬§ÿÁ¼·ÿÏÍÉÿ©§¤ÿ˜“ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ˜‘Œœ›–’«¥¡ù­§¢ÿ­§£ÿ­¨£ÿ®¨¤ÿ®©¤ÿ¯©¥ÿ¯©¥ÿ°ª¦ÿ°ª¦ÿ°«¦ÿ±«§ÿ°«¦ÿ°ª¦ÿ°ª¦ÿ¯ª¥ÿ®©¥ÿÆÄÁÿÅÁ¿ÿ—“ÿ˜’ÿ˜’ÿ™“ÿ˜”ÿŸš–ÿŸš–ÿŸš–ÿŸš–ÿ ›—ÿ ›—ÿ ›—ÿ œ˜ÿ¡œ˜ÿ¡œ˜ÿ¡œ˜ÿ¡™ÿ¢™ÿ¢™ÿŸ›–ÿ™“ÿ™“ÿ˜’ÿ˜’Œÿ®©¦ÿåäãÿ£™ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ ›•ú”Š!­©¤˜±­¨ÿ²­©ÿ²®©ÿ³®ªÿ³¯ªÿ´¯«ÿ´°«ÿ´°¬ÿµ±¬ÿµ±­ÿµ±­ÿµ±­ÿµ±¬ÿµ°¬ÿ´°¬ÿ´¯«ÿÿ¼ÿ š–ÿ¡›—ÿ¡›—ÿ¡›—ÿ¢™ÿ§¢žÿ§¢Ÿÿ§¢Ÿÿ¨£Ÿÿ¨£ ÿ¨£ ÿ¨£ ÿ¨¤ ÿ©¤ ÿ©¤¡ÿ©¤¡ÿ©¥¡ÿ©¥¡ÿª¥¢ÿª¥¢ÿª¥¡ÿ£žšÿ¡›—ÿ¡›—ÿ¡›—ÿ š–ÿª¥ ÿ¸³¯ÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ£˜œ¥Ÿ›·²®ø·²®ÿ·³¯ÿ¸³¯ÿ¸´°ÿ¹´°ÿ¹µ±ÿºµ±ÿºµ²ÿº¶²ÿ»¶²ÿº¶²ÿº¶²ÿºµ±ÿ¹µ±ÿ¹´°ÿ¾ºµÿ©£Ÿÿ©¤ ÿ©¤ ÿ©¤ ÿª¦¢ÿ¬¨¤ÿ¬¨¥ÿ¬©¥ÿ­©¦ÿ­©¦ÿ®ª¦ÿ®ª§ÿ®ª§ÿ¯«§ÿ¯«¨ÿ¯«¨ÿ¯¬¨ÿ¯¬©ÿ°­©ÿ°®ªÿ°®ªÿ­©¦ÿ©¤ ÿ©¤ ÿ©¤ ÿ©¤ ÿ°«§ÿ±«§ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ­§£ù™” ·²®–¼¸³ÿ¼¸´ÿ½¸´ÿ½¹µÿ¾¹µÿ¾¹µÿ¾º¶ÿ¿º¶ÿ¿º¶ÿ¿º·ÿ¿º¶ÿ¿º¶ÿ¾º¶ÿ¾ºµÿ¾¹µÿ½¹µÿ¼·´ÿµ°¬ÿ²¬©ÿ²¬©ÿ«¦¢ÿ©¥¡ÿª¦¢ÿ«§£ÿ«§¤ÿ¬¨¤ÿ¬©¥ÿ­©¦ÿ­ª¦ÿ®ª§ÿ®«¨ÿ®«¨ÿ¯«¨ÿ°¬©ÿ±­ªÿ±®«ÿ±®«ÿ°¬©ÿ²¬©ÿ²¬©ÿ²¬©ÿ´®«ÿ´¯«ÿ³®©ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ¯©¥›«§¤¾¹µ¨Â½ºòľ»ÿÄ¿»ÿÄ¿»ÿÅ¿¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅ¿¼ÿÅ¿»ÿÄ¿»ÿÄÀ»ÿÄ¿ºÿ¾ºÿ¿¹¶ÿ±­ªÿª¦¢ÿ¬§£ÿ¬¨¤ÿ­©¥ÿ®ª¦ÿ¯ª§ÿ¯«¨ÿ°¬¨ÿ°¬©ÿ°¬©ÿ±­ªÿ±®ªÿ²®¬ÿ³¯­ÿ³¯­ÿ³¯­ÿµ±­ÿºµ±ÿ½¸³ÿ¼¶²ÿ¼¶²ÿ¼¶²ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ°ÿº´°óµ°¬®¦¢ž®©¥m­©¥ÿ¯ª¦ÿ°«¨ÿ±¬©ÿ±®ªÿ²®«ÿ³¯¬ÿ´°­ÿ´±­ÿµ±®ÿµ²®ÿ¶²¯ÿ¶²°ÿ·³±ÿ·³±ÿ·³±ÿµ²¯i±­©L±­©ÿ²®ªÿ³¯¬ÿ´°­ÿ¶²®ÿ¶²¯ÿ·´°ÿ¸µ±ÿ¹µ²ÿ¹¶³ÿº¶´ÿº·´ÿ»¸µÿ»¸µÿ»¸µÿ»¸µÿ¸µ³I²­ª+µ±­ÿ¶²¯ÿ¸³°ÿ¹µ²ÿº¶³ÿ»·´ÿ¼¹µÿ½º·ÿ¾»¸ÿ¿»¹ÿÀ¼¹ÿÁ½ºÿÁ½»ÿÁ½ºÿÁ½ºÿ¾ºÿ·³°(²¯« ¾º·ÿ½º¶ÿ½º·ÿ¾º·ÿ¾º·ÿ¿»¸ÿ¿¼¹ÿÀ¼ºÿÁ½ºÿ¿»ÿÃÀ¼ÿÄÁ½ÿÄÁ¿ÿÄÁ¿ÿÅ¿ÿÇÃÁÿ¨¤  ·±­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿ´°­ÿ´°­ÿ´°­ÿ´°­ÿ´°­ÿ·±®ÿ¸²¯ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿ¸²¯ÿ¼¸¶ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿ¹µ³ÿ¹µ³ÿ¹µ³ÿ¹µ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿ¼¸¶ÿÁ½»ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿÓÐÏÿÐÎÎÿÎËËÿÌÈÉÿÉÆÅÿÆÂÂÿÁ¼¼ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿÁ½»ÿ½»ºÿ»¹¸ÿ»¹¸ÿ»¹¸ÿÍËÌÿ…€Ñyt‹‚{v‹‚{v‹zu‹Œ…ÈÂÀ¿ÿ»¹¸ÿ»¹¸ÿ»¹¸ÿ½»ºÿ¸¸·ÿµµµÿµ´µÿµ´´ÿÁÀÁÿ»´³™»µ³†¼»»ÿµ´µÿµ´µÿµµµÿ¸¸·ÿ™——ÿ—–•ÿ—–•ÿ—–•ÿš˜˜ÿ¼¶´™¼¶´†žžÿ—–•ÿ—–•ÿ—–•ÿ™——ÿQONÿPNNÿPNNÿONMÿ[ZYÿ½·µ™½·µ†[ZYÿONMÿPNNÿPNNÿQONÿqd^ob\«ob\÷l`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿk`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿk`Zÿk_Yÿj^Xÿj^Xÿj^Xÿi^Wÿj^Xÿj_Yÿl`Zÿl`Zÿj_Yÿj^Xÿi^Wÿj^Xÿj^Xÿj^Xÿk_Yÿk`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿnb\÷nb\«qd^rf`«F?;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿLE@ÿrf`«vjd÷ÿÿ($!ÿ($"ÿ($!ÿ($!ÿ'#!ÿ'#!ÿ'# ÿ'" ÿ&" ÿ&" ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$!ÿ'#!ÿ)&$ÿ+(&ÿ-*(ÿ0,*ÿ2/-ÿ41/ÿ631ÿ954ÿ1.,ÿ ÿ!ÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿvjd÷wlgÿÿ)$"ÿ'#!ÿ'# ÿ'# ÿ&" ÿ&" ÿ&"ÿ&!ÿ%!ÿ%!ÿ%!ÿ$ ÿ$ ÿ$ ÿ# ÿ#ÿ#ÿ%! ÿ'$"ÿ)&$ÿ,(&ÿ.+)ÿ0-+ÿ2/-ÿ51/ÿ742ÿ:75ÿ%" ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ<87ÿ+(&ÿ'$"ÿ864ÿ/,*ÿDA?ÿTPNÿ40/ÿ$"!ÿ'$"ÿ($"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwlgÿ|qkÿÿ($"ÿ'# ÿ'# ÿ&" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$ ÿ$ ÿ$ ÿ# ÿ#ÿ#ÿ#ÿ$!ÿ&# ÿ)%#ÿ+'%ÿ-*(ÿ/,*ÿ1.,ÿ30/ÿ631ÿ853ÿ40.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB>=ÿÿJGFÿSPNÿ?<:ÿ><8ÿ@<:ÿE@?ÿSONÿ20.ÿ@<;ÿ?<;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ|qkÿ€uoÿÿ($!ÿ'# ÿ'" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$ ÿ$ ÿ$ ÿ#ÿ#ÿ#ÿ"ÿ# ÿ%" ÿ($"ÿ*'%ÿ,)&ÿ.+)ÿ0-+ÿ30.ÿ520ÿ742ÿ986ÿ(%#ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ>;9ÿ)&%ÿ(%$ÿ'%#ÿ'$"ÿ520ÿ51/ÿ2.,ÿ&"!ÿ@=:ÿ#! ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€uoÿƒzsÿÿ($!ÿ'" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$ ÿ$ ÿ$ ÿ#ÿ#ÿ#ÿ"ÿ"ÿ"ÿ%!ÿ'$!ÿ)&#ÿ+(&ÿ-*(ÿ0,+ÿ2/-ÿ41/ÿ632ÿ964ÿ733ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒzsÿ†~xÿÿ(#!ÿ&" ÿ&"ÿ%"ÿ# ÿ"ÿ"ÿ!ÿ!ÿ!ÿ!ÿÿÿÿÿÿÿÿÿ"! ÿ$##ÿ&%%ÿ(''ÿ,)*ÿ.,,ÿ0/.ÿ221ÿ543ÿ766ÿ'&&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†~xÿŠ‚}ÿÿ'#!ÿ&"ÿ&"ÿ# ÿ£` ÿ»n(ÿ»m(ÿ»n(ÿ»n(ÿ¼n(ÿ¼n(ÿ¼n(ÿ¼n(ÿ¼p)ÿ¼p)ÿ½p*ÿ¼p*ÿ½q*ÿ¾q+ÿ¿r+ÿ¿r+ÿ¿s,ÿ¿r,ÿ¿r-ÿ¿r,ÿ¿r,ÿ¿s,ÿ¾s,ÿ¾s-ÿ¿r-ÿ¾p)ÿ¾q)ÿ¾q)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ¼p)ÿ¼p)ÿ»o)ÿ»o)ÿ»o)ÿ»o)ÿ»o)ÿºo)ÿºn)ÿ¹n)ÿ¹n)ÿ¹n)ÿ¹n)ÿ¹m)ÿ¹m*ÿ¸m*ÿ¸m*ÿ¹m*ÿ¸l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹k+ÿºk+ÿºk-ÿºk-ÿºk-ÿºk-ÿºk-ÿºk,ÿºk,ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿºk-ÿºk-ÿºk-ÿºk-ÿºk-ÿ¹k-ÿ¹k,ÿ¸k,ÿ¸k,ÿ¸k,ÿ¸k-ÿ·k+ÿ·k+ÿ¶j,ÿ¡^#ÿÿÿÿÿÿŠ‚}ÿ†ÿÿ'# ÿ&"ÿ%!ÿ"ÿµm'ÿÏ|1ÿÑ|1ÿÒ|1ÿÒ|1ÿÒ|1ÿÓ}1ÿÔ}1ÿÓ~1ÿÓ~2ÿÓ~2ÿÓ2ÿÓ3ÿÔ3ÿÔ4ÿÔ4ÿÕ4ÿÖ‚6ÿ׃6ÿ׃6ÿ׃7ÿ׃7ÿׄ8ÿׄ8ÿׄ8ÿׄ9ÿÖ‚4ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÔ2ÿÔ2ÿÔ~2ÿÔ~2ÿÔ~2ÿÔ~2ÿÓ~2ÿÓ~2ÿÓ}2ÿÓ}2ÿÒ}2ÿÑ|2ÿÑ|2ÿÐ|2ÿÐ{2ÿÐ{2ÿÐ{2ÿÏ{2ÿÏ{2ÿÏz3ÿÏz3ÿÏz3ÿÏz3ÿÏz3ÿÏz4ÿÏy4ÿÏy4ÿÏy4ÿÏy4ÿÏy5ÿÏy5ÿÐy5ÿÐy5ÿÐy5ÿÐy5ÿÐx5ÿÐx5ÿÐx6ÿÐx6ÿÐx6ÿÑx6ÿÑx6ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑw7ÿÑw7ÿÑw7ÿÐw7ÿÐw7ÿÐw7ÿÏw7ÿÏw7ÿÍw6ÿÎw6ÿÎw6ÿÍw6ÿÍw5ÿ´i,ÿÿÿÿÿÿ†ÿ“Š„ÿÿ'# ÿ%!ÿ%!ÿ"ÿ¼q)ÿÐ}1ÿÐ}1ÿÒ}1ÿÒ}1ÿÓ~1ÿÓ~1ÿÔ~1ÿÕ2ÿÕ2ÿÕ€2ÿÕ€3ÿÕ€3ÿÕ€3ÿÖ4ÿÖ4ÿÖ4ÿÖ5ÿÖ‚5ÿ׃6ÿØ„7ÿÙ„7ÿÙ„8ÿÙ…8ÿÙ…8ÿØ…9ÿØ…9ÿ×3ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿÖ€2ÿÖ€2ÿÖ€2ÿÖ€2ÿÖ€2ÿÕ€2ÿÕ€2ÿÔ2ÿÔ2ÿÓ2ÿÓ2ÿÒ~2ÿÒ~2ÿÑ~2ÿÑ}2ÿÐ}2ÿÐ}2ÿÐ|2ÿÐ|2ÿÏ|3ÿÏ|3ÿÏ|3ÿÏ{3ÿÏ{3ÿÏ{4ÿÏ{4ÿÏ{4ÿÏ{4ÿÏz4ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÐy6ÿÐy6ÿÐy6ÿÐy6ÿÐy7ÿÐy7ÿÑy7ÿÑy7ÿÑy7ÿÑy8ÿÑy8ÿÑy8ÿÒy8ÿÑy8ÿÒy8ÿÑy8ÿÑy8ÿÑy8ÿÑy8ÿÑx8ÿÑx8ÿÐx8ÿÐx8ÿÐx8ÿÐx8ÿÏx8ÿÏx7ÿÎx7ÿÎx7ÿÎx7ÿÎx6ÿµj,ÿÿÿÿÿÿ“Š„ÿ–ˆÿÿ&" ÿ%!ÿ%!ÿ"ÿ¾s)ÿÙ„3ÿÑ2ÿÑ~2ÿÓ2ÿÔ2ÿÔ2ÿÔ2ÿÕ2ÿÖ€3ÿׂ3ÿׂ3ÿׂ4ÿׂ4ÿׂ5ÿ؃5ÿ؃5ÿ؃6ÿ؃6ÿ؃6ÿ׃7ÿ׃8ÿØ…8ÿÚ‡9ÿÚ‡9ÿÚ†:ÿÚ†:ÿÚ„7ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ3ÿ×3ÿ×3ÿ×3ÿÖ3ÿÖ€3ÿÕ€3ÿÕ€3ÿÔ€3ÿÔ3ÿÓ3ÿÓ~3ÿÒ~3ÿÒ~3ÿÑ}3ÿÑ}4ÿÑ}4ÿÑ}4ÿÐ}4ÿÐ}4ÿÐ|4ÿÐ|5ÿÐ|5ÿÐ|5ÿÐ|5ÿÐ{5ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{7ÿÐz7ÿÐz7ÿÑz7ÿÑz8ÿÑz8ÿÑz8ÿÒz8ÿÒz8ÿÒz9ÿÒz9ÿÒz9ÿÓz9ÿÓz9ÿÓz9ÿÓz:ÿÓz:ÿÓz:ÿÓy:ÿÒy:ÿÒy:ÿÒy:ÿÒy:ÿÑy:ÿÑy9ÿÑy9ÿÑy9ÿÐy9ÿÐy9ÿÏy8ÿÐy8ÿ¶j-ÿÿÿÿÿÿ–ˆÿš“ÿÿ&" ÿ%!ÿ%!ÿ!ÿÀt*ÿ܆4ÿÛ…4ÿÓ€3ÿÒ3ÿÕ€3ÿÖ€3ÿÖ3ÿÖ3ÿÖ4ÿׂ4ÿÙƒ4ÿÙƒ5ÿÙƒ5ÿÙ„5ÿÚ„6ÿÚ„6ÿÚ„7ÿÚ„7ÿÚ…7ÿÚ…8ÿÙ…8ÿÙ…8ÿØ…9ÿÙ†:ÿÚ‡:ÿ܈;ÿ܈;ÿÛ„5ÿÛ„4ÿÛ„4ÿÛ„4ÿÛ„4ÿÛ„4ÿÚ„4ÿÚ„4ÿÚ„4ÿÚ„4ÿÚƒ4ÿÚƒ4ÿÙƒ4ÿÙƒ4ÿÙƒ4ÿ؃4ÿØ‚4ÿׂ4ÿׂ4ÿÖ‚4ÿÖ4ÿÖ4ÿÕ4ÿÕ€4ÿÔ€4ÿÔ4ÿÓ4ÿÓ4ÿÒ~5ÿÒ~5ÿÒ~5ÿÒ~5ÿÒ~5ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ|6ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|8ÿÒ|8ÿÒ{8ÿÒ{9ÿÓ{9ÿÓ{9ÿÓ{9ÿÓ{:ÿÔ{:ÿÔ{:ÿÔ{:ÿÔ{:ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔz;ÿÔz;ÿÔz;ÿÓz;ÿÓz;ÿÓz;ÿÒz;ÿÒz;ÿÒz:ÿÑz:ÿÒz:ÿ¸k.ÿÿÿÿÿÿš“ÿž—’ÿÿ&" ÿ%!ÿ$ ÿ!ÿÁv+ÿ݈5ÿ܇5ÿ܇5ÿÔ‚4ÿÒ€4ÿÕ‚4ÿׂ3ÿׂ3ÿׂ3ÿׂ4ÿ؃4ÿÙ„6ÿÚ…6ÿÚ…6ÿÚ†7ÿÛ†7ÿÛ†7ÿÛ†8ÿÛ‡8ÿÛ‡9ÿÛ‡9ÿÚ‡9ÿÚ‡:ÿÚ‡:ÿÙ‡:ÿ؆;ÿÚ‡;ÿÛ‡9ÿ܆5ÿ܆5ÿ܆5ÿÜ…5ÿÜ…5ÿÜ…5ÿÜ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÚ…5ÿÚ„5ÿÚ„5ÿÙ„5ÿÙ„5ÿÙ„5ÿ؃5ÿ؃5ÿ׃5ÿׂ5ÿÖ‚5ÿÖ‚5ÿÕ5ÿÕ5ÿÕ5ÿÔ€5ÿÔ€6ÿÓ€6ÿÓ6ÿÓ6ÿÒ6ÿÒ7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ}8ÿÒ}8ÿÑ}8ÿÒ}8ÿÒ}8ÿÒ}9ÿÒ}9ÿÓ}9ÿÓ}:ÿÓ|:ÿÓ|:ÿÔ|:ÿÔ|;ÿÔ|;ÿÔ|;ÿÕ|;ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|=ÿÕ|=ÿÕ{=ÿÕ{=ÿÕ{=ÿÕ{=ÿÔ{<ÿÔ{<ÿÔ{<ÿÓ{<ÿÓ{<ÿÓ{<ÿÓ{;ÿ¹l0ÿÿÿÿÿÿž—’ÿ¢›–ÿÿ&"ÿ$ ÿ$ ÿ!ÿÂv+ÿÞˆ6ÿÞ‰6ÿÞˆ6ÿ݈6ÿÖƒ5ÿÓ‚4ÿÖƒ5ÿ׃4ÿ؃4ÿ؃5ÿØ„5ÿØ…5ÿÚ…6ÿÛ†7ÿÛ‡8ÿ܇8ÿ܇8ÿ܇9ÿ܇9ÿ܈9ÿ܈:ÿ܈:ÿ܈;ÿ܉;ÿÛ‰;ÿÛ‰<ÿÛ‰<ÿÚ‰<ÿØ…6ÿÙ„5ÿÚ…5ÿ܆6ÿ݇6ÿ݇6ÿ܇5ÿ܇5ÿ܇5ÿ܆5ÿ܆5ÿ܆5ÿ܆5ÿÛ†5ÿÛ†5ÿÛ†5ÿÚ…6ÿÚ…6ÿÙ…6ÿÙ…5ÿÙ„6ÿØ„6ÿØ„6ÿ׃6ÿ׃6ÿ׃6ÿÖƒ6ÿÖ‚6ÿÕ‚6ÿÕ7ÿÔ7ÿÔ7ÿÔ€7ÿÓ€7ÿÓ€7ÿÓ€8ÿÓ€8ÿÒ8ÿÒ8ÿÒ8ÿÒ8ÿÒ~9ÿÒ~9ÿÒ~9ÿÓ~9ÿÓ~:ÿÓ~:ÿÓ~;ÿÔ};ÿÔ};ÿÔ};ÿÕ}<ÿÕ}<ÿÕ}<ÿÕ}<ÿÕ}=ÿÖ}=ÿÖ}=ÿÖ}=ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ|>ÿÖ|>ÿÖ|>ÿÖ|>ÿÕ|>ÿÕ|>ÿÕ|>ÿÕ|>ÿÔ|>ÿÔ|=ÿÓ|=ÿºm3ÿÿÿÿÿÿ¢›–ÿ¦ šÿÿ%!ÿ$ ÿ$ ÿÿÂx,ÿ߉6ÿÞŠ7ÿߊ7ÿߊ7ÿÞŠ7ÿÖ„5ÿÔƒ5ÿÖ„5ÿØ„5ÿÙ„6ÿÙ…6ÿÙ†6ÿÙ†7ÿÚ†7ÿ܇8ÿ܉9ÿ݉9ÿ݈9ÿ݈:ÿÝŠ:ÿ݉;ÿ݉;ÿ݉;ÿÝŠ<ÿÝŠ<ÿÜŠ<ÿÜŠ<ÿÜŠ<ÿ܉;ÿÛ†5ÿÙ…5ÿØ…5ÿÙ…6ÿÛ†6ÿ݈7ÿ݈7ÿ݈7ÿ݈7ÿ݈6ÿ݈6ÿ݈6ÿ܈6ÿ܇6ÿ܇6ÿ܇6ÿÛ‡7ÿÛ‡7ÿÚ†7ÿÚ†7ÿÚ†7ÿÙ†6ÿÙ…6ÿÙ…7ÿØ…7ÿØ„7ÿׄ7ÿׄ7ÿÖƒ7ÿÖƒ7ÿÖƒ8ÿÕ‚8ÿÕ‚8ÿÔ8ÿÔ8ÿÓ8ÿÓ8ÿÓ€9ÿÓ€9ÿÓ€9ÿÓ€9ÿÓ€:ÿÓ:ÿÓ:ÿÓ;ÿÔ;ÿÔ;ÿÔ<ÿÕ~<ÿÕ~<ÿÕ~=ÿÕ~=ÿÖ~=ÿÖ~=ÿÖ~>ÿÖ~>ÿÖ~>ÿÖ~>ÿÖ~?ÿ×~?ÿ×~?ÿ×~?ÿ×~?ÿ×}?ÿ×}?ÿ×}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÕ}?ÿÕ}>ÿ»n4ÿÿÿÿÿÿ¦ šÿª£žÿÿ%!ÿ$ ÿ# ÿÿÃx,ÿߊ7ÿà‹7ÿà‹7ÿàŒ7ÿà‹7ÿà‹7ÿ×…6ÿÖ„5ÿØ…5ÿÙ…6ÿÚ‡6ÿÚ‡6ÿÚ‡7ÿÚ‡7ÿÛ‡7ÿ܉9ÿÞŠ9ÿߊ:ÿÞŠ:ÿߊ:ÿÞ‹;ÿÞ‹;ÿÞ‹;ÿÞ‹<ÿÞŒ<ÿÞŒ=ÿÞŒ=ÿÞŒ=ÿÞŒ>ÿ݉9ÿ݇6ÿ܇6ÿ܇6ÿÛ†6ÿÙ†5ÿÙ†6ÿÛ‡6ÿ݈7ÿߊ7ÿ߉7ÿÞ‰7ÿÞ‰7ÿÞ‰7ÿÞ‰7ÿ݉7ÿ݈7ÿ݈7ÿ܈7ÿ܈7ÿ܇7ÿÛ‡7ÿÛ‡7ÿÛ‡7ÿÚ†7ÿÚ†7ÿÚ†7ÿÙ…7ÿÙ…7ÿØ…7ÿØ„8ÿØ„8ÿׄ8ÿ׃8ÿÖƒ8ÿÖ‚8ÿÕ‚9ÿÕ‚9ÿÕ‚9ÿÕ9ÿÕ9ÿÕ:ÿÕ:ÿÕ:ÿÕ;ÿÕ€;ÿÕ€;ÿÖ€<ÿÖ€<ÿÖ€<ÿÖ=ÿ×=ÿ×=ÿ×>ÿ×>ÿ×>ÿØ>ÿØ?ÿØ?ÿØ?ÿØ?ÿØ@ÿØ@ÿÙ~@ÿÙ~@ÿÙ~@ÿØ~@ÿØ~@ÿØ~@ÿØ~@ÿØ~@ÿ×~@ÿ×~@ÿ½p5ÿÿÿÿÿÿª£žÿ­¨¢ÿÿ%!ÿ# ÿ#ÿÿÃx-ÿà‹8ÿàŒ8ÿáŒ8ÿá8ÿá8ÿá8ÿáŒ8ÿ׆6ÿÖ…6ÿÙ†6ÿÙ‡7ÿÛˆ7ÿÛˆ8ÿÛˆ8ÿÛˆ8ÿÛ‰9ÿÞŠ9ÿß‹:ÿß‹;ÿß‹;ÿߌ<ÿߌ<ÿߌ<ÿߌ=ÿß=ÿß=ÿß>ÿß>ÿß>ÿÞ>ÿ݉7ÿ݉7ÿ݉7ÿ݉7ÿ݈7ÿ܈6ÿÛˆ6ÿÚ‡6ÿÙ†6ÿÚ‡7ÿÛˆ7ÿÞŠ8ÿß‹8ÿߊ8ÿÞŠ8ÿÞŠ8ÿÞŠ8ÿÞŠ8ÿ݉8ÿ݉8ÿ݉8ÿ܉8ÿ܈8ÿ܈8ÿÛˆ8ÿÛˆ8ÿÛ‡8ÿÚ‡8ÿÚ†8ÿÚ†8ÿÙ†8ÿÙ†9ÿØ…9ÿØ…9ÿׄ9ÿׄ9ÿÖƒ9ÿÖƒ:ÿÕƒ:ÿÕƒ:ÿÕ‚:ÿÕ‚;ÿÕ‚;ÿÕ‚;ÿÖ‚<ÿÖ<ÿÖ<ÿÖ=ÿ×=ÿ×=ÿ×>ÿ×€>ÿ×€>ÿ×€?ÿØ€?ÿØ€?ÿØ€@ÿØ€@ÿÙ€@ÿÙ€@ÿÙ€AÿÙ€AÿÙAÿÙAÿÙAÿÙBÿÙBÿÙBÿÙBÿÙBÿÙBÿÙBÿ¾p6ÿÿÿÿÿÿ­¨¢ÿ±¬§ÿÿ$!ÿ#ÿ#ÿÿÃz-ÿàŒ9ÿà9ÿáŽ9ÿâŽ9ÿâŽ9ÿâŽ9ÿâŽ9ÿáŽ9ÿׇ7ÿ׆7ÿÙˆ8ÿÚˆ8ÿÛ‰8ÿ܉9ÿ܉9ÿÜŠ:ÿÝŠ:ÿÝ‹:ÿß‹;ÿàŒ<ÿà<ÿà=ÿà=ÿà=ÿà>ÿàŽ>ÿà?ÿàŽ?ÿàŽ?ÿß?ÿߌ;ÿÞŠ7ÿÞŠ7ÿÞŠ7ÿÞŠ7ÿÝŠ7ÿÝŠ7ÿ݉7ÿ݉7ÿ܉7ÿÛˆ7ÿÙ‡7ÿÙ‡7ÿÚˆ8ÿ܉8ÿÞ‹9ÿß‹9ÿß‹9ÿÞ‹8ÿÞ‹8ÿÞŠ8ÿÝŠ9ÿÝŠ9ÿÝŠ9ÿ܉9ÿ܉9ÿ܉9ÿ܉9ÿÛˆ9ÿÛˆ9ÿÚˆ9ÿÚ‡9ÿÙ‡:ÿÙ‡:ÿÙ†:ÿ؆:ÿØ…:ÿ×…:ÿ×…;ÿÖ„;ÿÖ„;ÿÖ„;ÿÖƒ<ÿÖƒ<ÿÖƒ<ÿÖƒ=ÿׂ=ÿׂ=ÿׂ>ÿׂ>ÿׂ>ÿ×?ÿØ?ÿØ?ÿØ@ÿØ@ÿØ@ÿÙAÿÙAÿÙAÿÙAÿÙBÿÚBÿÚ€BÿÚ€BÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚCÿ¿p8ÿÿÿÿÿÿ±¬§ÿ²®©ÿÿ$ ÿ#ÿ#ÿÿÃ{.ÿà9ÿáŽ:ÿá:ÿâ:ÿâ:ÿâ:ÿã:ÿâ:ÿá:ÿׇ8ÿ؈9ÿÚŠ9ÿÚŠ9ÿÛŠ:ÿÜŠ:ÿÜ‹:ÿÝŒ;ÿÞŒ;ÿÞŒ<ÿß<ÿàŽ<ÿà>ÿà>ÿà>ÿá?ÿà?ÿà?ÿà?ÿà?ÿà@ÿà?ÿߌ8ÿß‹8ÿß‹8ÿß‹8ÿß‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÝŠ8ÿÝŠ8ÿÛ‰8ÿÚ‰8ÿ؈8ÿ؈8ÿÚ‰9ÿÛŠ9ÿÞ‹9ÿߌ:ÿÞŒ:ÿÞŒ9ÿÞ‹9ÿÝ‹:ÿÝ‹:ÿÝŠ:ÿÝŠ:ÿÜŠ:ÿÜŠ:ÿÛ‰:ÿÛ‰:ÿÛ‰:ÿÚˆ:ÿÚˆ;ÿÚˆ;ÿÙ‡;ÿÙ‡;ÿ؇;ÿ؆;ÿ×…<ÿ×…<ÿ×…<ÿ×…<ÿׄ=ÿׄ=ÿׄ>ÿׄ>ÿ׃>ÿ׃?ÿ׃?ÿ؃?ÿ؃@ÿØ‚@ÿØ‚@ÿØ‚AÿÙ‚AÿÙ‚AÿÙ‚BÿÙ‚BÿÙ‚BÿÚ‚BÿÚ‚CÿÚCÿÚCÿÚCÿÚDÿÚDÿÚDÿÚDÿÚDÿÛ‚Dÿ¿q8ÿÿÿÿÿÿ²®©ÿ³¯ªÿÿ$ ÿ#ÿ"ÿÿÄ|/ÿáŽ:ÿá:ÿâ;ÿâ;ÿã;ÿã‘;ÿã‘;ÿã‘;ÿã‘;ÿâ:ÿ؉9ÿÚŠ:ÿÛ‹:ÿÚ‹;ÿÛ‹;ÿÝŒ;ÿÝ<ÿÞ<ÿÞ<ÿÞ=ÿß=ÿá>ÿá>ÿá>ÿá?ÿá?ÿá‘?ÿá‘@ÿá‘@ÿá‘@ÿá‘Aÿá=ÿà9ÿà9ÿà9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿÞŒ9ÿÞŒ9ÿÞ‹9ÿÝ‹9ÿÝ‹9ÿÝŠ9ÿÜŠ9ÿÚ‰9ÿÙˆ9ÿ؈9ÿÙ‰9ÿÛŠ:ÿÝŒ:ÿß;ÿߌ;ÿÞŒ;ÿÞŒ;ÿÞ‹;ÿÝ‹;ÿÝ‹;ÿÝ‹;ÿÜŠ;ÿÜŠ;ÿÜŠ;ÿÛ‰;ÿÛ‰<ÿÚˆ<ÿÚˆ<ÿÚˆ<ÿÙ‡<ÿÙ‡=ÿ؆=ÿ؆=ÿ؆=ÿ؆>ÿØ…>ÿØ…?ÿØ…?ÿØ„?ÿØ„@ÿØ„@ÿØ„@ÿØ„Aÿ؃AÿÙƒAÿÙƒAÿÙƒBÿÙƒBÿÙƒCÿÚƒCÿÚƒCÿÚƒCÿÚƒDÿÚ‚DÿÛ‚DÿÛ‚EÿÛ‚EÿÛ‚EÿÛ‚EÿÛ‚Fÿ܃FÿÁr8ÿÿÿÿÿÿ³¯ªÿ³°«ÿÿ$ ÿ"ÿ"ÿÿÄ|/ÿá:ÿâ:ÿâ;ÿã‘;ÿã‘;ÿä‘;ÿä’;ÿä’;ÿå’;ÿå’;ÿá;ÿØŠ:ÿÛ‹:ÿÜŒ;ÿÛŒ;ÿÛ‹;ÿÞŽ<ÿߎ<ÿߎ<ÿàŽ=ÿàŽ=ÿà=ÿá>ÿâ‘?ÿã’@ÿã‘@ÿã’?ÿã’@ÿã’@ÿâ’@ÿâ’Aÿâ“Aÿá;ÿáŽ9ÿáŽ9ÿáŽ9ÿáŽ9ÿáŽ9ÿà9ÿà9ÿà9ÿà9ÿà9ÿß9ÿß9ÿߌ9ÿÞŒ9ÿÞŒ9ÿÞŒ9ÿÞŒ9ÿÝ‹9ÿÜ‹9ÿÛŠ9ÿÙ‰9ÿ؈9ÿ؉:ÿÚŠ:ÿÛ‹:ÿÝŒ;ÿß;ÿÞ;ÿÞŒ;ÿÞŒ;ÿÞŒ;ÿÝ‹;ÿÝ‹<ÿÜ‹<ÿÜŠ<ÿÜŠ<ÿÛŠ<ÿÛ‰<ÿÚ‰=ÿÚˆ=ÿÚˆ=ÿÙ‡=ÿÙ‡>ÿÙ‡>ÿÙ†>ÿÙ†?ÿÙ†?ÿÙ†@ÿÙ…@ÿÙ…@ÿÙ…@ÿÙ…AÿÙ„AÿÚ„AÿÚ„BÿÚ„BÿÚ„BÿÚ„CÿÛ„CÿÛ„CÿÛ„DÿÛ„DÿÛƒDÿ܃Eÿ܃Eÿ܃Eÿ܃Eÿ܃FÿÝ„FÿÁs9ÿÿÿÿÿÿ³°«ÿ´°¬ÿÿ# ÿ"ÿ"ÿÿÄ}0ÿá‘;ÿâ‘;ÿâ‘<ÿã’<ÿã’<ÿä’<ÿä“<ÿå“<ÿå“<ÿå“<ÿå“<ÿá<ÿÙ‹;ÿÜ;ÿÝ<ÿÜ<ÿÜ=ÿÞŽ<ÿà<ÿà=ÿà=ÿà=ÿà>ÿá>ÿâ’?ÿã“@ÿã“@ÿã”Aÿã”Aÿã”Aÿã”Bÿã”Bÿâ“@ÿâ:ÿâ:ÿá:ÿá:ÿá:ÿá:ÿá:ÿá:ÿáŽ:ÿàŽ:ÿàŽ:ÿàŽ:ÿàŽ:ÿߎ:ÿߎ:ÿß:ÿÞ:ÿÞ:ÿÞ:ÿÞŒ:ÿÝŒ:ÿÝ‹:ÿÜ‹:ÿÛ‹:ÿÚ‰:ÿ؉:ÿ׈:ÿ؉;ÿÙŠ;ÿÛ‹;ÿÜŒ<ÿÞ<ÿÞŒ<ÿÞŒ<ÿÝŒ<ÿÝ‹=ÿÜ‹=ÿÜ‹=ÿÜŠ=ÿÛŠ=ÿÛ‰>ÿÛ‰>ÿÚˆ>ÿÚˆ?ÿÚˆ?ÿÚˆ?ÿÙ‡@ÿÙ‡@ÿÙ‡@ÿÙ†AÿÚ†AÿÚ†AÿÚ†BÿÚ†BÿÚ…BÿÚ…CÿÚ…CÿÚ…CÿÛ…DÿÛ…DÿÛ…DÿÛ…EÿÛ…EÿÜ„EÿÜ„EÿÜ„FÿÜ„FÿÜ„FÿÝ„GÿÂt9ÿÿÿÿÿÿ´°¬ÿ´±­ÿÿ#ÿ"ÿ"ÿÿÄ}0ÿá‘<ÿá‘<ÿâ’<ÿã’<ÿã“=ÿä“=ÿä”=ÿå”=ÿå”=ÿå”=ÿå”=ÿæ”>ÿß=ÿÚŒ;ÿÜŽ=ÿÝŽ<ÿÝŽ<ÿÝ=ÿÞ=ÿà>ÿá>ÿá>ÿá‘?ÿá‘?ÿá‘?ÿá’@ÿã“Aÿä•Aÿä•Bÿä•Bÿä•Bÿä•Cÿã–Cÿã’=ÿâ‘;ÿâ‘;ÿâ;ÿâ;ÿâ;ÿâ;ÿá;ÿá;ÿá;ÿá;ÿá;ÿà;ÿà;ÿà;ÿà;ÿß;ÿߎ;ÿߎ;ÿÞŽ;ÿÞŽ;ÿÞ;ÿÞ;ÿÝ;ÿÝŒ;ÿÜŒ;ÿÜŒ;ÿÛ‹;ÿÚ‹;ÿÙŠ;ÿ׉;ÿÖˆ;ÿ׉<ÿ؉<ÿÙŠ<ÿÚ‹=ÿÛŒ=ÿÝŒ>ÿÝŒ>ÿÜŒ>ÿÜ‹>ÿÜ‹>ÿÛŠ?ÿÛŠ?ÿÛ‰?ÿÚ‰@ÿÚ‰@ÿÚˆ@ÿÚˆAÿÚˆAÿÚˆAÿÚ‡BÿÚ‡BÿÚ‡BÿÚ†CÿÚ†CÿÚ†CÿÚ†DÿÛ†DÿÛ†DÿÛ†EÿÛ†EÿÛ…EÿÜ…FÿÜ…FÿÜ…FÿÜ…GÿÜ…GÿÞ…GÿÂu:ÿÿÿÿÿÿ´±­ÿµ±®ÿÿ#ÿ"ÿ!ÿÿÄ~1ÿá’=ÿâ’=ÿâ“=ÿã“=ÿä”=ÿä”=ÿä”>ÿå•>ÿå•>ÿå•>ÿæ•>ÿæ•?ÿæ–?ÿÞ=ÿÛŽ=ÿÞ=ÿÞ=ÿÞ>ÿÞ>ÿÞ>ÿà‘?ÿá‘?ÿá’@ÿá“@ÿá“@ÿá“Aÿâ“Aÿã•Aÿä–Cÿä–Cÿä–Cÿä–Dÿä–Dÿä–Cÿã’<ÿã’<ÿã’<ÿã’<ÿã’<ÿã’<ÿâ‘<ÿâ‘<ÿâ‘<ÿâ‘<ÿâ‘<ÿá‘<ÿá<ÿá<ÿá<ÿà<ÿà<ÿà<ÿà<ÿß<ÿß<ÿß<ÿÞŽ<ÿÞŽ<ÿÞŽ<ÿÝ<ÿÝ<ÿÜ<ÿÜŒ<ÿÜŒ<ÿÛ‹=ÿÛ‹=ÿÚŠ=ÿÙŠ=ÿ؉=ÿ׈=ÿÖˆ=ÿÖˆ>ÿ׉>ÿ؉>ÿ؉>ÿÙŠ?ÿÚ‹?ÿÜ‹@ÿÛ‹@ÿÛŠAÿÛŠAÿÛ‰AÿÚ‰AÿÚ‰BÿÚ‰BÿÚˆBÿÚˆCÿÚˆCÿÚˆCÿÛ‡DÿÛ‡DÿÛ‡DÿÛ‡EÿÛ‡EÿÛ‡FÿÛ‡FÿÛ†Fÿ܆Fÿ܆Gÿ܆Gÿ܆GÿÞ…HÿÂu:ÿÿÿÿÿÿµ±®ÿµ²¯ÿÿ#ÿ!ÿ!ÿÿÄ~1ÿá“>ÿâ“>ÿã“>ÿã”>ÿä”>ÿå•>ÿå•>ÿæ–?ÿæ–?ÿæ–?ÿç–?ÿç–?ÿç—@ÿæ—@ÿÜ>ÿÝ>ÿß‘>ÿß‘?ÿß‘?ÿß‘?ÿÞ@ÿà‘@ÿâ“@ÿâ”Aÿã”Aÿã”Aÿã”Bÿã”Bÿã•Cÿä–Dÿæ—Dÿå—Dÿæ—Eÿå˜Eÿå•@ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿã’=ÿã’=ÿã’=ÿã’=ÿâ’=ÿâ’=ÿâ’=ÿâ‘=ÿá‘=ÿá‘=ÿá‘=ÿà=ÿà=ÿà=ÿß=ÿß=ÿß=ÿÞ=ÿÞŽ=ÿÞŽ=ÿÝŽ=ÿÝ=ÿÜ=ÿÜ>ÿÜŒ>ÿÛŒ>ÿÛ‹>ÿÚ‹>ÿÚŠ>ÿÙŠ?ÿÙ‰?ÿ؈?ÿ׈?ÿÖ‡?ÿÕ‡?ÿÖ‡@ÿÖ‡@ÿÖ‡Aÿ׈Aÿ؈AÿÙˆBÿÙ‰BÿÚ‰CÿÛ‰CÿÛ‰DÿÛ‰DÿÛ‰DÿÛˆDÿ܈Eÿ܈Eÿ܈Fÿ܈Fÿ܈Fÿ܇Gÿ܇Gÿ݇Gÿ݇Hÿ݇HÿÞ†HÿÂv;ÿÿÿÿÿÿµ²¯ÿ¶³°ÿÿ"ÿ!ÿ!ÿÿÄ2ÿá“>ÿâ”>ÿã”>ÿã•>ÿä•>ÿå•>ÿå–>ÿæ–?ÿæ–?ÿæ—?ÿç—?ÿç—@ÿç—@ÿç™@ÿæ˜@ÿÛ?ÿÞ>ÿà’?ÿß“?ÿà’?ÿß’@ÿß‘@ÿß’@ÿâ”Aÿã•Aÿã•Bÿã•Bÿã•Bÿã–Cÿã–Cÿä–Dÿå˜Eÿæ˜Eÿæ™Eÿæ™Eÿå”>ÿå”=ÿå”=ÿå”=ÿå”=ÿä”=ÿä”=ÿä”=ÿä”=ÿä“=ÿä“=ÿã“=ÿã“=ÿã“=ÿã“=ÿã“=ÿã“=ÿâ“=ÿâ’=ÿá’=ÿá‘=ÿá‘=ÿà‘=ÿà‘=ÿà=ÿß=ÿß=ÿß=ÿÞ=ÿÞ=ÿÝ=ÿÝŽ=ÿÝŽ>ÿÜ>ÿÜ>ÿÛŒ>ÿÛŒ>ÿÚŒ?ÿÚ‹?ÿÚ‹?ÿÙŠ?ÿÙŠ@ÿÙ‰@ÿ؉@ÿ؈Aÿ׈AÿׇAÿׇBÿÖ†BÿÖ†BÿÖ…CÿÕ…CÿÕ…DÿÕ…DÿÖ†Dÿ׆Dÿ×…Eÿ؆Eÿ؆EÿÙ†FÿÙ‡FÿÚ‡FÿÚ‡GÿÛ‡GÿÛ‡Gÿ܇Hÿ݈HÿÁw;ÿÿÿÿÿÿ¶³°ÿ¶´±ÿÿ"ÿ!ÿ ÿÿÄ2ÿá”>ÿá”?ÿâ•?ÿã•?ÿä–?ÿä–?ÿå—?ÿå—?ÿæ—@ÿæ˜@ÿç˜@ÿç˜@ÿç˜Aÿç™AÿèšAÿä—AÿÛ?ÿß’@ÿà”@ÿá“@ÿà“Aÿà“Aÿß“Aÿß“Bÿâ•Bÿã–Bÿä–Cÿä–Cÿä–Cÿä—Dÿä—Dÿä—Dÿå˜Fÿæ™FÿæšFÿæ˜Cÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿä•>ÿä•>ÿä”>ÿä”>ÿä•>ÿä”>ÿä”>ÿã”>ÿã”>ÿã”>ÿã”>ÿâ“>ÿâ“>ÿá’>ÿá’>ÿá’>ÿà’>ÿà‘>ÿß‘>ÿß‘>ÿß>ÿÞ>ÿÞ>ÿÝ>ÿÝ>ÿÝŽ?ÿÜŽ?ÿÜŽ?ÿÛ?ÿÛ?ÿÛŒ@ÿÚŒ@ÿÚ‹@ÿÙ‹@ÿÙŠAÿÙŠAÿÙŠBÿ؉Bÿ؉Bÿ؈Cÿ׈CÿׇDÿׇDÿׇEÿ׆Eÿ׆Eÿ׆Fÿ×…Fÿ×…Gÿ×…Gÿ×…Gÿ×…Hÿ×…Hÿ×…HÿØ…IÿØ…IÿØ„JÿÙ„Jÿ¾u<ÿÿÿÿÿÿ¶´±ÿ·´²ÿÿ"ÿ ÿ ÿÿÀ3ÿá•?ÿá•?ÿâ•?ÿã–?ÿä–@ÿä—@ÿä—@ÿå˜@ÿæ˜@ÿæ˜@ÿæ˜@ÿç™Aÿç™Bÿç™BÿèšBÿè›Cÿá–BÿÝ’@ÿß”Aÿà•Aÿá”Aÿá”Bÿà”Bÿà”Bÿß”Cÿá•Cÿã—Dÿä—Dÿä—Dÿä˜Eÿä˜Eÿä™Eÿå˜Fÿå˜Fÿæ›Fÿç›Gÿæ—@ÿæ—?ÿæ–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿä–?ÿä–?ÿä–?ÿä–?ÿä–?ÿä•?ÿä•?ÿä•?ÿä•?ÿã•?ÿâ”?ÿá“>ÿá“?ÿá“?ÿà“?ÿà’?ÿß’?ÿß’?ÿß‘?ÿÞ‘?ÿÞ?ÿÝ?ÿÝ?ÿÝ?ÿÜ@ÿÜŽ@ÿÛŽ@ÿÛ@ÿÛ@ÿÚAÿÚŒAÿÚŒAÿÙ‹BÿÙ‹BÿÙŠCÿØŠCÿ؉Cÿ؉Dÿ؉Dÿ׈Eÿ׈EÿׇEÿׇFÿׇFÿ׆Gÿ׆Gÿ׆Hÿ׆Hÿ؆Iÿ؆Iÿ؆IÿØ…JÿÙ†JÿÚ…Kÿ¿u=ÿÿÿÿÿÿ·´²ÿ·µ³ÿÿ!ÿ ÿ ÿÿÄ€4ÿá”@ÿâ•@ÿâ–@ÿã—@ÿä—@ÿå—Aÿå˜Aÿæ˜Aÿæ™Aÿç™Aÿç™AÿçšAÿèšBÿèšCÿè›Cÿé›DÿéœDÿß”Bÿß”Bÿá•Bÿâ–Bÿâ•Cÿâ•Cÿâ•Cÿá–Dÿà•Dÿà•Dÿä—Eÿå˜Eÿæ™Eÿæ™FÿæšFÿæšFÿæšGÿæšGÿæ›HÿçšEÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå–@ÿä•?ÿâ”?ÿâ”?ÿâ”?ÿá“?ÿá“@ÿà“@ÿà’@ÿà’@ÿß’@ÿß‘@ÿÞ‘@ÿÞ@ÿÞ@ÿÝAÿÝAÿÜAÿÜŽAÿÜŽBÿÛBÿÛBÿÚŒBÿÚŒCÿÚŒCÿÚ‹DÿÙ‹DÿÙŠDÿÙŠEÿÙ‰Eÿ؉Fÿ؈Fÿ؈Gÿ؈Gÿ؇Gÿ؇Hÿ؇Hÿ؇Iÿ؇IÿÙ‡JÿÙ‡JÿÙ‡JÿÚ†KÿÀv=ÿÿÿÿÿÿ·µ³ÿ¸¶´ÿÿ!ÿ ÿ ÿÿÃ4ÿá•Bÿá–Aÿâ—Aÿã—Aÿä˜Aÿä˜Aÿå˜Aÿå™Bÿæ™Bÿæ™BÿçšBÿçšBÿçšBÿè›CÿèœCÿèœDÿéœEÿèœDÿÞ”Cÿà•Cÿâ—Cÿã—Dÿã–Dÿã—Dÿâ—Eÿâ—Eÿá–Eÿà–Fÿã—FÿåšFÿæ›Gÿæ›Gÿæ›Gÿæ›Hÿæ›HÿæœHÿæœIÿæ™Bÿç˜Aÿè™Aÿè™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç˜Aÿç˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿå˜Aÿå˜Aÿå˜Aÿå—Aÿä–@ÿã•@ÿâ•@ÿâ•@ÿá”@ÿá”Aÿà”Aÿà“Aÿà“Aÿß“Aÿß’Aÿß’AÿÞ‘AÿÞ‘AÿÝBÿÝBÿÜBÿÜBÿÜBÿÛŽCÿÛŽCÿÛCÿÚDÿÚŒDÿÚŒEÿÚ‹EÿÙ‹EÿÙŠFÿÙŠFÿØŠGÿ؉Gÿ؉Hÿ؉Hÿ؈Hÿ؈Iÿ؈Iÿ؈JÿÙˆJÿÙ‡KÿÚ‡Kÿ¿v=ÿÿÿÿÿÿ¸¶´ÿ¸·µÿÿ!ÿ ÿÿÿÃ4ÿà•Bÿá–Bÿâ–Bÿâ—Bÿã—Bÿä˜Bÿä˜Bÿå™Bÿå™Bÿæ™BÿæšCÿçšCÿçšCÿè›DÿèœDÿèœDÿèœEÿéFÿåšEÿÞ•Cÿá—Cÿã—Dÿã—Dÿã—Dÿã˜Eÿã—Eÿâ—Eÿâ—Fÿá—Fÿá—FÿåšGÿæ›Hÿæ›Hÿç›Iÿç›IÿçœIÿçœJÿæ›Hÿæ˜Aÿç™Aÿè™Bÿè™Bÿè™Bÿè™Bÿè™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿå—Aÿã–Aÿâ•Aÿâ•Aÿá”Aÿá”Aÿá”Aÿà“Aÿà“Bÿß“Bÿß’BÿÞ’BÿÞ’BÿÞ‘BÿÝ‘CÿÝCÿÝCÿÜCÿÜDÿÛŽDÿÛŽDÿÛDÿÚEÿÚŒEÿÚŒFÿÚ‹FÿÙ‹GÿÙ‹GÿÙŠGÿØŠHÿ؉Hÿ؉Iÿ؉Iÿ؈Iÿ؈Jÿ؈Jÿ؈KÿÚˆKÿ¿v=ÿÿÿÿ ÿÿ¸·µÿº·¶ÿÿ!ÿÿÿÿÂ5ÿà–Bÿà–Bÿá—Bÿâ—Bÿã˜Bÿã˜Bÿä™Bÿå™BÿåšBÿåšBÿæšCÿæ›Cÿç›Cÿç›DÿèœDÿèDÿèEÿèFÿéFÿâ™Eÿà–Dÿã˜Dÿã˜Dÿã˜Dÿã™Eÿã™Eÿã™Eÿã˜Fÿâ˜Fÿá˜Fÿá˜GÿäšHÿæœHÿçœIÿçœIÿçIÿçžJÿçžJÿç›Dÿæ™Aÿæ™AÿçšBÿè›Bÿè›Bÿè›BÿèšBÿèšBÿèšBÿèšBÿèšBÿèšBÿçšBÿçšBÿçšBÿçšBÿçšBÿçšBÿç™Bÿç™Bÿç™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿå˜Bÿã—Aÿâ–Aÿâ–Aÿá•Aÿá•Bÿà•Bÿà”Bÿà”Bÿß”Bÿß“BÿÞ“BÿÞ’CÿÞ’CÿÝ‘CÿÝ‘CÿÜ‘DÿÜDÿÜDÿÛDÿÛŽEÿÛŽEÿÚŽEÿÚFÿÚFÿÚŒGÿÙŒGÿÙ‹GÿÙ‹HÿÙŠHÿØŠIÿØŠIÿ؉Jÿ؉Jÿ؉JÿÙ‰Kÿ¿x=ÿÿÿÿ ÿÿº·¶ÿº¸·ÿÿ ÿÿÿÿ‚6ÿà–Cÿà—Bÿá—Bÿâ˜Bÿã˜Cÿä™Cÿä™CÿåšCÿæšCÿæšCÿæ›Cÿç›Cÿç›DÿèœDÿèEÿèEÿéFÿéžFÿéžFÿéžGÿà˜Eÿâ˜Dÿä™Eÿä™Eÿä™EÿäšFÿäšFÿä™Fÿä™Gÿã™GÿãšGÿâšHÿâšHÿæIÿèIÿèžIÿèŸJÿèŸKÿèŸJÿèšBÿèšBÿçšBÿèšBÿè›BÿéœCÿéœCÿéœCÿéœCÿéœCÿé›Cÿé›Cÿé›Cÿé›Cÿé›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›CÿçšCÿçšCÿçšCÿçšCÿçšCÿçšCÿçšCÿæ™Cÿä˜Bÿã—Bÿã—Bÿâ–Bÿâ–Bÿá•Cÿá•Cÿá•Cÿà”Cÿà”Cÿß“Cÿß“CÿÞ“DÿÞ’DÿÞ’DÿÝ‘DÿÝ‘EÿÜEÿÜEÿÜEÿÛFÿÛŽFÿÛŽGÿÛGÿÚHÿÚŒHÿÚŒHÿÙ‹IÿÙ‹IÿÙ‹JÿÙŠJÿÙŠKÿÙŠKÿ¾x=ÿÿÿÿ ÿÿº¸·ÿ»º¸ÿÿ ÿÿÿÿ‚6ÿß–Dÿà—Cÿá˜Cÿâ˜Cÿã™Cÿã™CÿäšDÿäšDÿå›Dÿæ›Dÿæ›DÿæœDÿçœDÿçœDÿèEÿèžFÿèžFÿéžGÿéŸGÿéŸGÿçžGÿà˜Eÿã™FÿäšFÿäšFÿå›Gÿä›GÿåšGÿäšHÿäšHÿä›Hÿã›Iÿã›IÿâšIÿåJÿèŸJÿéŸJÿé Kÿé KÿèžFÿè›Bÿè›Bÿè›Bÿè›Bÿè›BÿéœCÿêDÿêDÿéDÿéDÿéDÿéDÿéœDÿéœDÿéœDÿéœDÿéœDÿéœDÿèœDÿèœDÿèœDÿèœDÿèœDÿèœDÿè›Dÿè›Dÿç›Dÿç›Dÿç›Dÿç›DÿæšCÿä™Cÿã˜Cÿã—Cÿâ—Cÿâ—Cÿá–Cÿá–Cÿá–Dÿà•Dÿà•Dÿß”Dÿß”DÿÞ“DÿÞ“DÿÝ’EÿÝ’EÿÝ‘EÿÜ‘FÿÜFÿÜFÿÛGÿÛGÿÛGÿÛŽHÿÚŽHÿÚIÿÚIÿÙŒIÿÙŒJÿÙŒJÿÚ‹Kÿ¿z=ÿÿÿÿ ÿÿ»º¸ÿ»ººÿÿ ÿÿÿÿ‚7ÿß—DÿߘDÿà˜Dÿá™Dÿâ™DÿãšDÿãšDÿä›Dÿå›DÿåœEÿæœEÿæœEÿæœEÿçEÿçFÿèžFÿèŸFÿèŸGÿéŸHÿéŸHÿéŸIÿäœGÿá™FÿäšGÿä›Gÿä›GÿåœHÿåœHÿå›Iÿå›Iÿä›IÿäœJÿäœJÿãœJÿâ›KÿãœKÿçŸKÿé¡Lÿé¡Lÿé¡KÿéDÿéœCÿéœCÿéœCÿéœCÿéœCÿéCÿéžDÿêžEÿêžEÿêžEÿêžEÿéžEÿéžEÿéEÿéEÿéEÿéEÿéEÿéEÿéEÿèEÿèEÿèEÿèEÿèœEÿèœEÿèœEÿèœEÿçœEÿçœEÿçœEÿæ›Dÿä™Dÿã™Dÿã˜Dÿâ˜Dÿâ—Dÿá—Dÿá—Dÿà–Dÿà–Dÿà•Eÿß•Eÿß”EÿÞ”EÿÞ”EÿÝ“FÿÝ“FÿÜ’FÿÜ’GÿÜ‘GÿÛ‘GÿÛHÿÛHÿÛHÿÚIÿÚŽIÿÚŽIÿÙJÿÙJÿÚKÿ¿{=ÿÿÿÿ ÿÿ»ººÿ»»»ÿÿ ÿÿÿÿÁƒ7ÿÞ—DÿÞ˜Eÿà™Eÿá™EÿášEÿâšEÿã›Eÿã›EÿäœEÿåœEÿåœEÿæFÿæFÿçFÿçžGÿçŸGÿèŸGÿèŸHÿè Hÿé Hÿé Iÿè¡Iÿá›Gÿã›Hÿä›Hÿä›HÿåœIÿåœIÿåœIÿåœJÿåœJÿåJÿåKÿäKÿäKÿãœLÿâLÿåŸLÿé¢Mÿê¢Mÿé IÿéDÿéDÿéDÿéDÿéDÿéDÿéDÿéžDÿéŸEÿêŸFÿêŸFÿêŸFÿêŸFÿêŸFÿêžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿèžFÿèFÿèFÿèFÿèFÿèFÿçFÿçEÿæœEÿäšEÿã™Eÿã™Eÿâ˜Eÿá˜Eÿá˜Eÿá—Eÿà—Eÿà—Eÿß–Fÿß–FÿÞ•FÿÞ•FÿÞ”FÿÝ”GÿÝ“GÿÜ“GÿÜ’GÿÛ’HÿÛ‘HÿÛ‘HÿÛIÿÚIÿÚJÿÚJÿÙŽJÿÚŽKÿ¿|=ÿÿÿÿ ÿÿ»»»ÿ¼¼¼ÿÿÿÿÿÿÁƒ7ÿÞ˜EÿÞ˜Eÿß™EÿàšEÿášEÿâ›Eÿâ›EÿãœEÿäœEÿäEÿåEÿåEÿæžFÿæžFÿçžGÿçŸGÿç Gÿè Hÿè Hÿè Hÿé Iÿé¡Iÿç Iÿá›HÿäœHÿäœHÿåIÿåIÿåIÿåJÿåJÿåJÿåžKÿåžKÿåžKÿäžLÿäžLÿãžLÿãŸMÿè¢Mÿê£MÿéŸFÿéžDÿéžDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸEÿê Eÿê Fÿê Fÿê Fÿê Fÿê Fÿê FÿêŸFÿêŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿæFÿã›EÿãšEÿãšEÿâ™Eÿâ™Eÿá™Eÿá˜Eÿà˜Eÿà—Fÿß—Fÿß–FÿÞ–FÿÞ•FÿÞ•GÿÝ•GÿÝ”GÿÜ“GÿÜ“HÿÛ’HÿÛ’HÿÛ‘IÿÚ‘IÿÚ‘JÿÚJÿÚ‘Jÿ¿}=ÿÿÿÿ!ÿÿ¼¼¼ÿ½½½ÿÿÿÿÿÿÁ„8ÿÞ˜EÿÞ™EÿßšEÿàšEÿášFÿâ›FÿâœFÿãœFÿäFÿäFÿåFÿåžFÿæžFÿæžFÿçŸGÿçŸHÿè Hÿè Hÿè¡Iÿé¡Iÿé¡Jÿé¡Jÿê¢JÿäžJÿãœIÿåIÿåJÿæžJÿæžJÿæžKÿæžKÿæžKÿæŸLÿæŸKÿæŸKÿæŸLÿåŸLÿåŸLÿäŸMÿäŸMÿæ¡Nÿê¢LÿêŸEÿê Eÿê Eÿê Eÿë Eÿë Eÿê Eÿë Eÿê Eÿê Eÿë Fÿë¡Fÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë Gÿë Gÿê Gÿê Gÿê Gÿê Gÿê Gÿê Gÿê Gÿé GÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿèŸGÿåœFÿä›Fÿä›FÿãšFÿãšFÿâšFÿâ™Fÿá™Fÿá˜Fÿà˜Gÿà—Gÿß—Gÿß—GÿÞ–GÿÞ–GÿÞ•HÿÝ•HÿÝ”HÿÜ”IÿÜ“IÿÛ“IÿÛ’JÿÛ’JÿÛ’JÿÀ<ÿÿÿ ÿ!ÿÿ½½½ÿ¾¾¾ÿÿÿÿÿÿÁ„8ÿݘFÿÝ™FÿÞšFÿßšFÿà›Fÿá›FÿâœFÿâGÿãGÿäGÿäžGÿåžGÿæžGÿæŸGÿæŸGÿç Hÿç¡Hÿè¡Hÿè¡Iÿè¡Iÿé¢Jÿé¢Kÿé£Kÿé£KÿâIÿäžJÿåžJÿåŸKÿæŸJÿæŸJÿæŸKÿæŸKÿæ Kÿæ Lÿæ Lÿæ Mÿæ Mÿæ Mÿå¡Mÿå Nÿä Nÿä Oÿç Iÿë Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¢Gÿë¢Gÿë¢Hÿë¢Hÿë¢Hÿë¢Hÿë¡Hÿë¡Hÿë¡Hÿê¡Hÿê¡Hÿê¡Hÿê¡Gÿê¡Gÿê¡Gÿê¡Hÿê Hÿê Hÿé Hÿé Hÿé Hÿé Hÿé Hÿé HÿçŸGÿåGÿäœGÿãœGÿã›Gÿâ›GÿâšGÿášGÿá™Gÿà™Gÿà™Gÿà˜GÿߘHÿß—HÿÞ—HÿÞ–HÿÝ–HÿÝ•IÿÜ•IÿÜ”IÿÛ”IÿÛ“JÿÛ”JÿÀ€<ÿÿ ÿ ÿ!ÿÿ¾¾¾ÿ¿¿¿ÿÿÿÿÿÿÀ„9ÿÝšGÿÝšGÿÞšGÿÞ›Gÿß›GÿàœGÿáœGÿâGÿâGÿãžGÿäžGÿäžHÿåŸHÿåŸHÿæ Hÿæ Iÿç¡Iÿç¢Iÿç¢Jÿè¢Jÿè¢Jÿé¢Kÿé£Kÿé¤Lÿæ¡LÿãžJÿåŸJÿå Kÿå Kÿæ Kÿæ Lÿæ Lÿæ Lÿæ¡Mÿæ¡Mÿæ¡Mÿæ¡Nÿæ¡Nÿæ¡Nÿæ¢Oÿå¡Oÿå¡Oÿä NÿäFÿé¡Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë£Gÿë£Hÿë£Iÿë£Iÿë£Iÿë¢Iÿë¢Iÿë¢Hÿë¢Hÿë¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¡Hÿê¡Hÿé¡Hÿé¡Iÿé¡Iÿé¡Iÿé¡Iÿè¡IÿçŸHÿäGÿäHÿãœHÿãœHÿâ›Hÿâ›Hÿá›HÿášHÿàšHÿà™Hÿß™Hÿß™HÿÞ˜HÿÞ—IÿÝ—IÿÝ—IÿÜ–IÿÜ–IÿÜ•JÿÜ”JÿÀ<ÿÿ ÿ ÿ!ÿÿ¿¿¿ÿÀÀÀÿÿÿÿÿÿ¿…9ÿÜšGÿÜšHÿÝ›HÿÞ›HÿßœHÿàœHÿàHÿáHÿâžHÿãžHÿãŸHÿäŸHÿäŸHÿå Iÿæ Iÿæ Iÿç¡Jÿç¢Jÿç¢Jÿè£Kÿè£Kÿè£Kÿé£Lÿé¤Lÿé¤MÿãŸKÿäŸKÿå Kÿå¡Lÿæ¡Lÿæ¡Mÿæ¡Mÿæ¡Mÿæ¡Nÿæ¢Nÿæ¢Nÿç¢Oÿç¢Oÿæ¢Oÿæ£Pÿæ£Pÿæ¢Pÿå¢QÿäŸKÿâGÿæŸGÿê£Hÿë£Hÿë£Hÿë£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿë£Hÿë£Hÿì¤Iÿì¤Iÿë¤Iÿë¤Iÿë£Iÿë£Iÿë£Iÿë£Iÿë£Iÿê£Iÿê£Iÿê£Iÿê£Iÿê¢Iÿê¢Iÿê¢Iÿê¢Iÿé¢Iÿé¢Iÿé¢Iÿé¢Jÿé¢Jÿè¡IÿåŸHÿäžHÿäHÿãHÿãHÿâœHÿâœHÿá›Iÿá›IÿàšIÿàšIÿßšIÿß™IÿÞ™IÿÞ˜IÿݘIÿÝ—JÿÜ—JÿÝ–JÿÀƒ<ÿÿ ÿ ÿ!ÿÿÀÀÀÿÁÁÁÿÿÿÿÿÿÀ…:ÿÜ›GÿÝ›GÿÝ›HÿÞ›HÿßœHÿßœHÿàHÿážHÿâžHÿâŸHÿãŸHÿäŸHÿä Hÿå Iÿå Iÿæ¡Iÿç¡Jÿç¢Jÿç£Kÿè£Kÿè£Kÿè¤Lÿé¤Lÿé¥Lÿé¥Mÿè¤MÿãŸKÿå Lÿæ¢Lÿæ¢Lÿæ¢Mÿç¢Mÿç¢Mÿç¢Nÿç£Nÿç£Nÿç£Oÿç£Oÿç£Oÿç£Pÿç¤Pÿç£Pÿç£Qÿæ£PÿåžHÿäžGÿäžGÿè¢Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¥Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿì¤Hÿì¤Hÿì¥Iÿì¥Jÿì¤Jÿì¤Iÿì¤Iÿì¤Iÿì¤Iÿì¤Iÿë¤Iÿë¤Iÿë¤Iÿë£Iÿë£Iÿë£Iÿë£Iÿë£Iÿê£Iÿê£Jÿê£Iÿê£Jÿê£Jÿé£Jÿè¡IÿåŸHÿåŸHÿäžHÿäžHÿãIÿãHÿâœIÿáœIÿá›Iÿà›Iÿà›IÿßšIÿßšIÿÞ™IÿÞ™IÿݘJÿÞ˜Jÿ„<ÿÿ ÿ ÿ!ÿÿÁÁÁÿÂÂÂÿÿÿÿÿÿ¿…:ÿÛ›HÿÜ›HÿÝœHÿÝœHÿÞœHÿßHÿßIÿàžIÿážIÿâŸIÿâŸIÿã Iÿä Iÿä¡Iÿå¡Iÿå¡Iÿæ¢Kÿæ£Kÿç£Kÿç£Lÿè¤Lÿè¤Lÿè¤Mÿé¥Mÿé¦Mÿé¦Nÿå¢Mÿå¡Lÿæ¢Mÿæ¢Mÿæ¢Mÿæ¢Nÿç£Nÿç£Nÿç£Oÿç¤Oÿç¤Oÿç¤Pÿç¤Pÿè¤Pÿç¤Qÿç¤Qÿç¤Qÿç¤Rÿæ¢NÿåŸHÿäŸHÿäžHÿå Iÿë¤Iÿí¥Iÿí¥Iÿí¥Iÿí¥Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¥Iÿí¥Iÿí¥Iÿí¥Jÿí¦Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿë¥Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿê¤Jÿê¤Jÿê¤Jÿê¤Jÿê£Jÿé£Jÿé£Jÿæ¡Iÿå IÿäŸIÿäŸIÿãžIÿãžIÿâžIÿâIÿáIÿàœIÿàœJÿß›Jÿß›JÿßšJÿÞšJÿÞšJÿÂ…<ÿÿ ÿ ÿ"ÿÿÂÂÂÿÃÃÃÿÿÿÿÿÿ¾†<ÿÛ›IÿÛ›IÿÜœIÿÝœIÿÝIÿÞIÿßžIÿßžIÿàžIÿáŸJÿá Jÿâ Jÿã Jÿã¡Jÿä¡Jÿå¢Jÿå¢Kÿæ£Kÿæ¤Kÿç¤Lÿç¤Lÿè¥Lÿè¥Nÿè¥Nÿé¦Nÿé¦Oÿè¦Oÿâ¡Mÿå¢Nÿæ£Nÿæ£Nÿæ£Oÿæ£Oÿç£Oÿç£Pÿç¤Pÿç¤Pÿç¤Qÿç¤Qÿç¤Qÿç¥Rÿç¥Rÿç¥Rÿç¥Sÿç¥Rÿæ¡Jÿå Iÿå Iÿä IÿäŸIÿç¢Iÿì¦Jÿí¦Jÿí¦Jÿí¦Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí¦Jÿí¦Jÿí¦Jÿì¦Jÿì¦Jÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿê¥Kÿê¥Kÿê¤Kÿê¤Kÿé¤Kÿé¤Kÿè¤Jÿå¡Jÿå Jÿä Jÿã JÿãŸJÿãŸJÿâžJÿážJÿáJÿàJÿàJÿßœJÿß›KÿßœKÿ‡=ÿÿ ÿ!ÿ"ÿÿÃÃÃÿÄÄÄÿÿÿÿÿÿ¾†=ÿÚœJÿÚœJÿÛœJÿÜJÿÝJÿÝžJÿÞžJÿßžJÿߟJÿàŸJÿà Jÿá Jÿâ¡Jÿã¡Jÿä¢Kÿä¢Kÿå£Lÿå£Lÿæ¤Lÿæ¤Mÿç¥Mÿç¥Mÿè¥Mÿè¦Nÿè§Oÿè§Oÿé§Pÿæ¤Oÿä¢Nÿæ¤Oÿæ¤Oÿæ¤Pÿæ¤Pÿæ¤Pÿç¤Pÿç¥Qÿç¥Qÿç¥Qÿç¥Rÿç¥Rÿç¥Rÿç¦Sÿç¦Sÿç¦Sÿç¦Tÿæ¥Qÿæ¡Jÿå¡Jÿå¡Jÿå Jÿä Jÿä¡Jÿé¤Jÿí§Kÿí§Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿí¨Kÿí¨Kÿí§Kÿí§Kÿì§Kÿì§Kÿì§Kÿì§Lÿì§Lÿì§Lÿì§Lÿì¦Lÿì¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿê¦Lÿê¥Lÿê¥Lÿê¥Lÿê¥Lÿé¥Lÿé¥Lÿæ£Kÿå¡Kÿä¡Kÿä¡Kÿã Kÿã KÿâŸKÿáŸKÿážKÿàžKÿàžKÿßKÿßžKÿÈ=ÿÿ!ÿ!ÿ"ÿÿÄÄÄÿÅÅÅÿÿÿÿÿÿ¾†=ÿÚœKÿÚœKÿÛKÿÜKÿÝžKÿÞžKÿÞžKÿߟKÿߟKÿà Kÿá Kÿá¡Kÿâ¡Kÿã¢Kÿä¢Kÿä¢Kÿå£Lÿå£Mÿæ¥Mÿæ¥Mÿç¥Nÿç¦Nÿè¦Nÿè¦Oÿé§Oÿé§Oÿé¨Pÿé§Pÿä£Oÿæ¤Pÿæ¥Pÿç¥Pÿç¥Qÿç¥Qÿç¥Qÿç¥Rÿç¦Rÿè¦Rÿè¦Sÿè¦Sÿè¦Sÿè§Tÿè§Tÿè§Tÿè§Uÿè§Uÿç£Mÿç¢Jÿæ¢Jÿæ¢Jÿæ¡Jÿå¡Jÿä¡Jÿå¢Kÿë¦Kÿï©Kÿï©Kÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿî©Lÿî¨Lÿî¨Lÿî¨Lÿí¨Lÿí¨Lÿí¨Lÿí¨Lÿí¨Mÿí§Mÿí§Mÿí§Mÿì§Mÿì§Mÿì§Mÿì§Mÿì§Mÿë§Mÿë§Mÿë¦Mÿë¦Mÿë¦Mÿê¦Mÿê¦Mÿê¥Mÿé¥Lÿæ¢Lÿå¢Lÿå¢Kÿä¡Kÿä¡Kÿã Lÿã LÿâŸLÿáŸLÿáŸLÿàžLÿĉ=ÿÿ!ÿ!ÿ"ÿÿÅÅÅÿÆÆÆÿÿÿÿÿÿ½†>ÿÙKÿÙKÿÚKÿÛžKÿÜžKÿÝžKÿÞŸKÿÞŸKÿß Kÿß Kÿà Kÿá¡Kÿá¡Kÿâ¢Kÿã¢Kÿä£Kÿä£Lÿå¤Mÿæ¥Mÿæ¥Nÿæ¦Nÿç¦Nÿç¦Oÿè§Oÿè§Oÿé¨Oÿé¨Pÿé¨Pÿç¦Pÿå¤Pÿæ¦Pÿæ¦Pÿç¦Qÿç¦Qÿç¦Qÿç¦Rÿç§Rÿç§Rÿè§Sÿè§Sÿè§Sÿè§Tÿè¨Tÿè¨Tÿè¨Uÿè¨Uÿè§Sÿç£Kÿç£Kÿç£Jÿæ£Jÿæ¢Jÿå¢Jÿå¢Jÿâ¡Jÿæ£Kÿì¨LÿïªLÿïªLÿïªLÿïªLÿð«LÿðªLÿïªLÿïªLÿïªLÿïªLÿîªLÿî©Lÿî©Lÿî©Lÿí©Lÿí¨Lÿí¨Lÿí¨Mÿí¨Mÿí¨Mÿí¨Mÿì¨Mÿì¨Mÿì¨Mÿì¨Mÿì¨Mÿë¨Mÿë§Mÿë§Mÿë§Mÿë§Mÿê§Mÿê¦Mÿê¦Mÿé¦Mÿç¤Lÿå£Lÿå£Kÿä¢Kÿä¢Kÿã¡Lÿã¡Kÿâ Lÿá Lÿá¡LÿÅŠ>ÿÿ!ÿ!ÿ"ÿÿÆÆÆÿÇÇÇÿÿÿÿÿÿ¼‡>ÿÙKÿÙKÿÚžKÿÛžKÿÛžLÿÜŸLÿÝŸLÿÞ LÿÞ Lÿß¡Lÿß¡Lÿà¡Lÿá¢Lÿá¢Lÿâ£Lÿã£Lÿä¤Lÿä¤Mÿå¥Mÿå¦Mÿæ¦Oÿæ§Oÿç§Oÿç§Pÿè§Pÿè©Pÿè©Qÿé©Qÿê©Qÿå¥Qÿå¦Qÿæ§Qÿæ§Rÿç§Rÿç§Rÿç§Sÿç¨Sÿç¨Sÿç¨Tÿè¨Tÿè¨Tÿè¨Tÿè©Tÿè©Tÿè©Uÿè©Uÿè©Uÿç¦Oÿç¤Kÿç¤Kÿæ¤Kÿæ£Kÿæ£Kÿå£Kÿä¢Kÿä¢Kÿã¢Kÿè¥LÿîªLÿð«Mÿð«Mÿð«Mÿð¬Mÿð¬Mÿð¬Mÿð«Mÿï«Mÿï«Mÿï«MÿîªMÿîªMÿîªMÿîªMÿí©Mÿí©Mÿì©Mÿì©Mÿì©Mÿì©Nÿì©Nÿì©Nÿì©Nÿì©Nÿì©Nÿë¨Nÿë¨Nÿë¨Mÿë¨Mÿê¨Nÿê§Nÿê§Nÿê§Nÿé§Mÿè¦Mÿæ¤Lÿå¤Lÿä£Lÿä£Lÿä¢Lÿã¢Lÿâ¡Lÿâ¢LÿÅŒ>ÿÿ!ÿ!ÿ"ÿÿÇÇÇÿÈÈÈÿÿÿÿÿÿ¼‡?ÿמLÿØLÿÙžLÿÚžLÿÛŸLÿÜŸLÿÜ LÿÝ LÿÞ¡MÿÞ¡Mÿß¡MÿߢMÿà¢Mÿá¢Mÿá£Mÿâ£Mÿã¤Mÿã¥Nÿä¥Nÿå¦Nÿå§Oÿæ§Oÿæ§Oÿç¨Pÿç¨Qÿç©Qÿè©Qÿè©RÿêªRÿç¨Rÿå¦Rÿæ§Rÿæ¨Rÿæ¨Sÿç¨Sÿç¨Sÿç¨Tÿç©Tÿç©Tÿç©Tÿè©Tÿè©Tÿè©UÿèªUÿèªUÿèªVÿèªVÿèªUÿç¥Lÿç¥Lÿç¤Lÿæ¤Lÿæ¤Lÿå¤Lÿå£Lÿä£Lÿä£Lÿã¢Lÿã£Lÿé§Mÿï¬Mÿð¬Mÿð­Mÿð­Mÿð­Mÿð­Mÿð­Mÿð¬Nÿï¬Nÿï¬Nÿï¬Nÿî«Nÿî«Mÿî«MÿíªNÿíªMÿìªMÿìªNÿì©Nÿì©NÿìªNÿìªNÿìªOÿì©Oÿì©Nÿë©Nÿë©Nÿë©Nÿë©Nÿê¨Nÿê¨Nÿê¨Nÿé¨Nÿé§Nÿè§Nÿç¥Mÿå¥Mÿå¤Mÿä¤Mÿä£Mÿã£Mÿã¤MÿÆ?ÿÿ!ÿ!ÿ#ÿÿÈÈÈÿÉÉÉÿÿÿÿÿÿ¼ˆ?ÿמMÿØžMÿÙžMÿÚŸMÿÚŸMÿÛ MÿÜ MÿÝ¡MÿÝ¡MÿÞ¢MÿÞ¢MÿߢMÿà£Mÿà£Nÿá£Nÿá¤Nÿâ¥Nÿã¥Nÿä¥Oÿä§Oÿå§Oÿå§Pÿæ¨Pÿæ¨Pÿç¨Qÿç©QÿèªQÿèªRÿéªRÿêªRÿå§Rÿæ¨Sÿæ¨Sÿæ¨Sÿæ©Sÿç©Sÿç©Tÿç©TÿçªTÿçªUÿçªUÿèªUÿèªVÿè«Vÿè«Vÿè«Wÿè«Wÿè«Wÿè¨Rÿç¥Mÿç¥Mÿæ¥Mÿæ¥Mÿæ¤Mÿå¤Mÿå¤Mÿä¤Mÿä£Mÿä£Mÿã£Mÿä¤Mÿë©Nÿð­Nÿñ®Nÿñ®Nÿñ®Nÿñ®Nÿñ®Nÿð­Nÿð­Nÿï­Nÿï­Nÿï¬Nÿî¬Nÿî¬Nÿî«Nÿí«Nÿí«NÿìªNÿìªNÿìªNÿìªNÿëªNÿìªNÿìªOÿìªOÿìªOÿëªOÿëªOÿë©Oÿê©Oÿê©Oÿê©Oÿê¨Oÿé¨Oÿé¨Oÿè§Nÿæ¦Nÿå¥Nÿä¥Nÿä¤Nÿä¥NÿÇŽ@ÿÿ!ÿ"ÿ#ÿÿÉÉÉÿËËËÿÿÿÿÿÿ¼ˆ@ÿÖNÿןNÿÙŸNÿÚŸNÿÛ NÿÛ¡NÿÜ¡NÿÝ¡NÿÝ¢NÿÞ¢NÿߣNÿߣNÿà£Nÿà¤Nÿá¤Nÿá¤Nÿâ¤Nÿã¥Nÿä¦Pÿä§Pÿå§Pÿå¨Qÿæ¨Qÿæ¨Qÿç©Rÿç©RÿèªRÿè«Sÿé«Sÿê«Sÿè©Sÿå¨Sÿæ©Sÿç©Tÿç©Tÿç©Tÿç©Uÿè©UÿèªUÿè«Uÿè«Vÿè«Vÿè«Vÿè«Wÿè¬Wÿè¬Wÿè¬Xÿè«XÿèªXÿç¦Oÿç¦Nÿç¦Nÿç¦Nÿæ¥Nÿæ¥Nÿæ¥Nÿå¥Nÿå¤Nÿå¤Nÿå¤Nÿä¤Nÿä¤Nÿæ¥Nÿì«Oÿó¯Oÿò¯Oÿò¯Oÿò¯Oÿñ¯Oÿñ®Oÿñ®Oÿð®Oÿð­Oÿï­Oÿï­Oÿï¬Oÿî¬Oÿî¬Oÿî¬Oÿí«Oÿí«Oÿí«OÿìªOÿìªOÿìªOÿëªOÿëªOÿëªOÿì«PÿìªPÿëªPÿëªPÿëªPÿê©Pÿê©Pÿê©Pÿê©Pÿé¨Oÿç§Oÿæ¦Oÿå¦Oÿä¦OÿÇ@ÿÿ"ÿ"ÿ#ÿÿËËËÿÌÌÌÿÿÿÿÿÿ»‰@ÿÖžNÿןOÿØ OÿÙ OÿÚ¡OÿÛ¡OÿÜ¢OÿÝ¢OÿÝ£OÿÞ£OÿÞ£OÿߤOÿߤOÿà¤Oÿá¥Oÿá¥Oÿâ¥Oÿâ¥Oÿã¦Pÿã§Pÿä¨Pÿå¨Qÿå©Rÿæ©Rÿæ©RÿçªSÿç«Sÿç«Sÿé«Tÿé«Tÿê¬Tÿå©TÿæªTÿæªTÿçªUÿçªUÿçªUÿçªVÿç«Vÿè«Vÿè«Wÿè«Wÿè«Wÿè«Xÿè¬Xÿè¬Xÿè¬Yÿè¬Yÿè¬YÿçªUÿç§Oÿç§Oÿç§Oÿå¥Nÿå¥Nÿå¥Nÿå¥Oÿå¥Oÿå¥Oÿå¥Oÿå¥Oÿä¥Oÿä¥Oÿâ¥Oÿæ§Oÿí­Pÿó°Pÿò°Pÿò°Pÿò°Pÿñ¯Pÿñ¯Pÿð¯Pÿð®Pÿï®Pÿï­Pÿï­Pÿî­Pÿî­Pÿî¬Pÿí¬Pÿí¬Pÿí¬Pÿì«Pÿì«Pÿë«PÿëªPÿëªPÿêªPÿêªPÿëªPÿë«Qÿë«QÿëªQÿêªPÿêªPÿêªPÿéªPÿé©Pÿç¨Pÿæ§Pÿå¦OÿÈBÿÿ"ÿ"ÿ#ÿÿÌÌÌÿÍÍÍÿÿÿÿÿÿ»ŠAÿÕ Oÿ× OÿØ OÿÙ¡OÿÚ¢OÿÛ¢OÿÛ£OÿÜ£OÿÝ£OÿݤOÿÞ¤OÿߤOÿߥOÿà¥Oÿà¥Oÿá¦Oÿá¦Oÿâ¦Oÿâ¦Pÿâ§Pÿã¨Pÿä©Qÿå©Qÿå©RÿæªRÿæªSÿç«Sÿç«Tÿè¬Tÿé¬Tÿé¬TÿçªUÿåªTÿæ«Uÿæ«Uÿæ«Uÿç«Uÿç«Vÿç«Vÿç¬Vÿè¬Wÿè¬Wÿè¬Wÿè¬Xÿè¬Xÿè­Xÿè­Yÿè­Yÿè­Yÿè­Zÿç©Qÿç¨Oÿæ§Oÿå¦Nÿå¦Nÿå¦Nÿå¦Nÿå¦Oÿå¦Oÿå¦Oÿå¦Oÿå¦Oÿä¦Oÿä¦Oÿä¦Oÿâ¥Oÿæ¨Oÿî®Pÿó±Pÿò±Pÿò°Pÿñ°Pÿñ°Pÿð¯Pÿð¯Pÿï¯Pÿï®Pÿï®Pÿî®Pÿî­Pÿí­Pÿí­Pÿí­Pÿì¬Pÿì¬Pÿì¬Pÿë¬Pÿë«Pÿë«Pÿê«Pÿê«PÿêªPÿéªPÿêªQÿê«Pÿê«Pÿê«Pÿê«PÿéªPÿéªPÿè©Pÿå¨PÿÈ‘Bÿÿ"ÿ"ÿ#ÿÿÍÍÍÿÎÎÎÿÿÿÿÿÿ»ŠAÿÕ¡PÿסPÿØ¡PÿÙ¢PÿÚ¢PÿÛ£PÿÛ¤PÿܤPÿݤPÿÝ¥PÿÞ¥PÿߥPÿߥPÿà¦Pÿà¦Pÿá¦Pÿá§Pÿâ§Pÿâ§Pÿâ§Qÿã¨Qÿã©QÿäªRÿåªRÿåªRÿæ«Sÿæ«Tÿç¬Tÿè¬Uÿè¬Uÿé­Uÿé¬VÿäªUÿæ«Uÿæ«Vÿæ«Vÿç¬Vÿç¬Wÿç¬Wÿç­Wÿç­Xÿè­Xÿè­Xÿè­Yÿè­Yÿè­Yÿè®Yÿè®Zÿè®Zÿè®Zÿè¬Xÿç¨Pÿæ§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿä§Oÿä§Oÿä§Oÿä¦Oÿâ¦Oÿç©Pÿï¯Qÿò±Qÿñ±Qÿñ±Qÿñ±Qÿð°Qÿð°Qÿï¯Qÿï¯Qÿï¯Qÿî¯Qÿî®Qÿî®Qÿí®Qÿí­Qÿí­Qÿì­Qÿì­Qÿë¬Qÿë¬Qÿë¬Qÿê¬Qÿê«Qÿê«Qÿé«Qÿé«QÿéªQÿéªQÿé«Qÿé«Qÿé«Qÿé«Qÿç«RÿÉ’Bÿÿ"ÿ"ÿ#ÿÿÎÎÎÿÏÏÏÿÿÿÿÿÿ»‹BÿÖ¢Pÿ×¢PÿØ£PÿÙ£PÿÚ£PÿÛ¤PÿÜ¥PÿÝ¥PÿÝ¥PÿÞ¥PÿÞ¦QÿߦQÿߦQÿà§Qÿà§Qÿá§Qÿá§Qÿâ¨Qÿâ¨Qÿã¨Rÿã©Rÿã©RÿäªSÿäªSÿå«Sÿæ«Tÿæ«Tÿç¬Tÿè­Uÿé­Uÿé­Vÿé­Wÿç¬Vÿæ¬Vÿæ¬Vÿç¬Wÿç¬Wÿç­Wÿç­Xÿè­Xÿè®Xÿè®Yÿè®Yÿè®Yÿè®Zÿé®Zÿé¯Zÿé¯[ÿé¯[ÿè¯[ÿè®\ÿçªTÿå§Pÿå§Pÿå§Pÿå§Pÿå¨Pÿå¨Pÿæ¨Pÿæ¨Pÿæ¨Pÿæ¨Pÿå¨Pÿå§Pÿå§Pÿå§Pÿå§Pÿä§Pÿä§Pÿä§Pÿè«Pÿï°Rÿò²Rÿñ±Rÿñ±Rÿñ±Rÿð°Rÿð°Rÿð°Rÿï°Rÿï¯Rÿï¯Rÿî¯Rÿî®Rÿí®Rÿí®Qÿí®Qÿì­Qÿì­Qÿì­Qÿë­Qÿë¬Qÿê¬Qÿê¬Qÿê¬Qÿé«Qÿé«Qÿè«QÿèªQÿèªQÿèªQÿé«RÿË“Cÿÿ"ÿ"ÿ$ÿÿÏÏÏÿÐÐÐÿÿÿÿÿÿ»ŒBÿÖ£Rÿ×£QÿؤQÿÙ¤QÿÚ¥QÿÛ¥QÿܦQÿܦQÿݦQÿÞ¦QÿÞ§Qÿß§Rÿß§Qÿà§Qÿà¨Qÿà¨Qÿá¨Rÿá¨Rÿâ©Rÿâ©Sÿã©SÿãªSÿãªTÿäªTÿä«Tÿå«Uÿæ¬Uÿæ­Uÿç­Uÿè­Vÿè®Vÿé®Vÿè­Wÿå¬Wÿæ­Wÿæ­Xÿç­Xÿç­Xÿç­Yÿç­Yÿç®Yÿè¯Zÿè¯Zÿè¯Zÿè¯[ÿè¯[ÿè¯[ÿè°[ÿè¯\ÿè¯\ÿè¯\ÿè®Zÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿè«Rÿð°Sÿò²Sÿñ²Sÿð±Sÿð±Sÿð±Rÿð±Rÿï°Rÿï°Rÿî°Rÿî¯Rÿî¯Rÿí¯Rÿí¯Rÿí®Rÿì®Rÿì®Rÿë®Rÿë­Rÿë­Rÿê­Rÿê¬Rÿé¬Rÿé¬Rÿè¬Rÿè«Rÿè«Rÿç«Rÿæ«SÿÉ“Cÿÿ"ÿ"ÿ$ÿÿÐÐÐÿÒÒÒÿÿÿÿÿÿ¼CÿÖ¤RÿפRÿØ¥RÿÙ¥RÿÚ¦RÿÛ¦RÿÛ§RÿܧRÿݧRÿݧRÿÞ¨RÿÞ¨RÿߨRÿߨRÿà¨Rÿà©Rÿá©Rÿá©Rÿá©Rÿâ©SÿâªSÿâ«Sÿã«Tÿã«Uÿã«Uÿä«Uÿå¬Vÿæ­Vÿæ®Vÿç®Wÿè®Wÿè®Wÿè¯Xÿæ­Wÿå­Wÿæ®Xÿæ®Xÿç®Yÿç®Yÿç®Zÿç¯Zÿç¯Zÿç¯[ÿè¯[ÿè¯[ÿè¯\ÿè¯\ÿè°\ÿè°\ÿè°\ÿè°\ÿç¯]ÿä«Vÿä©Rÿä©Rÿä©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿä©Rÿä©Rÿä©Rÿã¨Rÿã¨Rÿè¬Rÿî°Sÿð²Sÿð²Sÿð²Sÿð²Sÿï±Sÿï±Sÿï±Sÿî°Sÿî°Sÿî°Sÿí°Sÿí¯Sÿì¯Sÿì¯Sÿì¯Sÿë®Sÿë®Sÿë®Sÿê­Sÿê­Sÿé­Sÿé­Sÿè¬Sÿè¬Sÿç¬Sÿæ¬SÿÊ“Dÿÿ"ÿ#ÿ$ÿÿÒÒÒÿÓÓÓÿÿÿÿÿÿ¼ŽCÿÖ¦SÿצRÿئRÿÙ§RÿÚ§RÿÛ§RÿÛ¨RÿܨRÿܨRÿݨRÿÞ¨RÿÞ©RÿÞ©Rÿß©Rÿß©Rÿà©Rÿà©RÿàªRÿáªRÿáªSÿâªSÿâ«Sÿâ«Tÿã¬Uÿã¬Uÿã¬Uÿä¬Vÿä­Vÿæ®Vÿç®Wÿç¯Wÿç¯Wÿè¯Xÿç®Xÿå®Xÿå®Xÿæ®Yÿæ¯Yÿæ¯Yÿç¯Zÿç¯Zÿç°Zÿç°[ÿç°[ÿè°[ÿè°\ÿè°\ÿè°\ÿè±]ÿè±\ÿè±\ÿç¯]ÿå®\ÿä©Sÿä©Rÿä©Rÿä©Rÿä©Rÿä©Rÿå©RÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿäªRÿäªRÿä©Rÿä©Rÿä©Rÿã©Rÿã©Rÿã©Rÿç¬Sÿí±Sÿð³Sÿð²Sÿï²Sÿï²Sÿï²Sÿî±Sÿî±Sÿî±Sÿí±Sÿí°Sÿí°Sÿì°Sÿì¯Sÿë¯Sÿë¯Sÿë¯Sÿê®Sÿê®Sÿé®Sÿé®Sÿè­Sÿè­Sÿè­Sÿæ­TÿÊ”Eÿÿ#ÿ#ÿ$ÿÿÓÓÓÿÓÓÓÿÿÿÿÿÿ½DÿצTÿÙ§SÿÙ¨SÿÚ¨SÿÛ¨SÿÛ¨SÿÜ©SÿÜ©SÿÝ©SÿÝ©SÿÞ©Sÿß©SÿߪSÿߪSÿàªSÿàªSÿàªSÿáªSÿáªSÿá«Sÿâ«Tÿâ¬Tÿã¬Tÿã¬Uÿã¬Vÿä­Uÿä­Vÿä­Vÿå®Wÿæ®Xÿç¯Xÿè¯Xÿè°Xÿè°Yÿæ®Xÿæ¯Yÿæ¯Yÿæ¯Yÿç¯Yÿç¯Zÿç°Zÿè°Zÿè±[ÿè±[ÿè±[ÿè±\ÿè±\ÿè±\ÿè²]ÿè²]ÿè±]ÿæ¯]ÿæ¯^ÿå­YÿäªSÿäªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿäªSÿäªSÿäªSÿäªSÿäªSÿè­Tÿî±Tÿð³Tÿð³Tÿï²Tÿï²Tÿï²Tÿï²Tÿî±Tÿî±Tÿí±Tÿí±Tÿí°Tÿì°Tÿì°Tÿì¯Tÿë¯Tÿë¯Tÿê¯Tÿê®Tÿé®Sÿé®Tÿé®Tÿç­UÿÊ•Eÿ ÿ#ÿ#ÿ$ÿÿÓÓÓÿÏÏÏÿÿÿÿÿÿ½EÿÙ¨UÿÙ©TÿÚ©TÿÚ©TÿÛªTÿÛªTÿܪTÿܪTÿܪTÿݪTÿݪTÿÞªTÿÞªTÿß«Tÿß«Tÿß«Tÿà«Tÿà«Tÿá«Tÿá«Tÿá«Uÿâ¬Uÿâ­Uÿâ­Vÿã­Vÿã­Vÿã­Wÿä­Wÿä®Wÿå¯Wÿæ¯Xÿç°Xÿç°Xÿè°Yÿæ¯Yÿå¯Yÿæ°Zÿæ°Zÿæ°Zÿç°[ÿç°[ÿç°[ÿç±\ÿè±\ÿè±\ÿè²\ÿè²]ÿè±]ÿè²]ÿè²^ÿç²^ÿæ¯]ÿæ¯^ÿæ¯]ÿä«TÿäªSÿä«Sÿä«Sÿä«Sÿä«Sÿä«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Tÿå«Tÿå«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«TÿäªTÿãªTÿç­Tÿí±Uÿð³Uÿï³Uÿï³Uÿï³Uÿî²Uÿî²Uÿî²Uÿí²Uÿí±Tÿì±Tÿì±Uÿì°Uÿë°Tÿë°Tÿë°Tÿê°Tÿê¯Tÿé¯Tÿé¯Tÿé®UÿË–Eÿ ÿ#ÿ#ÿ$ÿÿÏÏÏÿÍÍÍÿÿÿÿÿÿ¾‘FÿÙªVÿÙªUÿÚªUÿÚ«UÿÛ«UÿÛ«UÿÛ«UÿÜ«UÿÜ«UÿÜ«UÿÝ«UÿÝ«UÿÞ«UÿÞ«Uÿß«Uÿ߬Uÿ߬Uÿà¬Uÿà¬Uÿá¬Uÿá¬Vÿá¬Vÿá­Vÿâ­Wÿâ­Wÿâ®Wÿã®Wÿã®Xÿä®Xÿå¯Xÿå¯Yÿæ°Yÿæ°Yÿç°Zÿç°Zÿå°Zÿå°[ÿæ±[ÿæ±[ÿæ±[ÿæ±\ÿç±\ÿç²\ÿç²]ÿç²]ÿç²]ÿè²^ÿè²^ÿè²^ÿè³_ÿç²^ÿå°^ÿå°_ÿå°_ÿå®\ÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿå¬Tÿä¬Tÿå¬Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿä«Tÿä«Tÿä«Tÿã«Tÿã«Tÿã«Tÿæ­Tÿì²Uÿï´Uÿï³Uÿî³Uÿî³Uÿî³Uÿí²Uÿí²Uÿì²Uÿì²Uÿì±Uÿë±Uÿë±Uÿë±Uÿê°Uÿê°Uÿé°Uÿé¯Uÿé¯VÿË—Fÿ ÿ#ÿ#ÿ$ÿÿÍÍÍÿÊÊÊÿÿÿÿÿÿ¾”FÿÚ¬WÿÚ«VÿÚ¬VÿÚ¬VÿÛ¬VÿÛ¬VÿÛ¬VÿܬVÿܬVÿܬVÿܬVÿݬVÿݬVÿÞ¬VÿÞ¬VÿÞ¬Vÿ߬Vÿ߬Vÿ߬Vÿà­Vÿà­Vÿá­Wÿá®Wÿá®Wÿâ®Xÿâ®Xÿâ®Xÿã®Yÿã¯Yÿä°Yÿå°Zÿå°Zÿå°Zÿæ°Zÿç±[ÿå°[ÿå±[ÿå±\ÿå±\ÿæ±\ÿæ±]ÿæ²]ÿæ²]ÿç³^ÿç³^ÿç³^ÿç³^ÿç³_ÿç³_ÿç³_ÿå²_ÿå±_ÿå±_ÿå±`ÿå±`ÿä­Wÿâ¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿã¬Uÿã¬Uÿã¬Uÿã¬Uÿå®Uÿë±Vÿî´Vÿî´Vÿî´Vÿí³Vÿí³Vÿí³Vÿì²Vÿì²Vÿì²Vÿë²Vÿë±Vÿê±Vÿê±Vÿé±Vÿé°Vÿé°Wÿ˘Gÿ ÿ#ÿ#ÿ$ÿÿÊÊÊÿÈÈÈÿÿÿÿÿÿ¿•GÿÛ­WÿÛ­VÿÛ­VÿÜ­VÿÜ­VÿÜ­VÿÜ­VÿÜ­VÿÝ­VÿÝ­VÿÝ­VÿÝ­VÿÝ­VÿÞ­VÿÞ­Vÿß­Vÿß­Vÿß­Vÿà­Vÿà­Vÿà­Vÿá­Wÿá®Wÿá¯Wÿâ¯Xÿâ¯Xÿâ¯Xÿã¯Yÿã¯Yÿä°Yÿå°Zÿå±Zÿæ±Zÿæ±[ÿæ±[ÿæ±[ÿå±[ÿå²\ÿæ²\ÿæ²\ÿæ²]ÿæ²]ÿç²]ÿç³^ÿç´^ÿç´^ÿç´_ÿè´_ÿç´_ÿè³_ÿå±_ÿå±_ÿå±_ÿå±`ÿå±`ÿå±^ÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿã­Uÿã¬Uÿã¬Uÿå­Vÿê±Vÿî´Vÿî´Vÿî´Vÿí´Vÿí³Vÿí³Vÿì³Vÿì³Vÿì²Vÿë²Vÿë²Vÿê²Vÿê±Vÿê±Vÿ˘Gÿ ÿ#ÿ#ÿ$ÿÿÈÈÈÿÅÅÅÿÿÿÿÿÿ¿–GÿÛ®WÿÛ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÝ®WÿÝ®WÿÝ®WÿÝ®WÿÝ®WÿÞ®WÿÞ®WÿÞ®Wÿß®Wÿß®Wÿß®Vÿà®Vÿà®Wÿà®Wÿá¯Wÿá¯Xÿá¯Yÿâ¯Yÿâ¯Yÿã°Zÿä°Zÿä±Zÿå±[ÿå±[ÿå±[ÿæ²\ÿæ²\ÿå±[ÿå²\ÿå²]ÿå²]ÿæ³]ÿæ³^ÿæ³^ÿæ³^ÿç´_ÿç´_ÿç´_ÿç´`ÿç´`ÿæ³`ÿä²`ÿå²`ÿå²`ÿå²aÿå²aÿå²aÿä¯Zÿã­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä­Vÿã­Vÿã­Vÿã­Vÿã­Vÿä®Vÿè±Wÿí´Wÿí´Wÿí´Wÿí´Wÿì´Wÿì³Wÿì³Wÿë³Wÿë³Wÿê²Wÿê²Wÿê²Wÿ̘Hÿ ÿ#ÿ#ÿ$ÿÿÅÅÅÿÃÃÃÿÿÿÿÿÿÀ—HÿܯXÿܯXÿܰXÿܰXÿܰXÿܰXÿܯXÿܯXÿܯXÿܯXÿݯXÿݯXÿݯXÿݯWÿݯWÿݯWÿÞ¯WÿÞ¯WÿÞ¯Wÿ߯Wÿ߯Wÿ߯Xÿà¯Xÿà°Xÿá°Xÿá°Yÿá°Yÿâ°Yÿâ°Zÿã°Zÿã±Zÿä²[ÿä²[ÿå²[ÿå²\ÿå²\ÿä²\ÿä³]ÿå³]ÿå³]ÿå³]ÿå³^ÿæ³^ÿæ³^ÿæµ_ÿæµ_ÿæµ`ÿçµaÿçµ`ÿå³`ÿä²aÿä³aÿä³aÿä³aÿå³bÿå³bÿä²aÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿâ®Wÿâ®Wÿç±Xÿì´Xÿì¶Xÿì´Xÿì´Xÿë´Xÿë´Xÿë³Xÿê³Xÿê³Xÿê³WÿÌ™Gÿ ÿ#ÿ#ÿ$ÿÿÃÃÃÿÀÀÀÿÿÿÿÿÿÀ˜IÿܱYÿܱYÿܱYÿܱYÿܱYÿܱYÿܱYÿݰYÿܰYÿܰYÿܰYÿܰXÿݰXÿݰXÿݯXÿݯXÿݯXÿݯXÿÞ¯XÿÞ¯XÿÞ¯Xÿ߯Yÿ߯Yÿß°Yÿà±Yÿà±Zÿá±Zÿá±Zÿá±[ÿã±[ÿã²[ÿã²\ÿã²\ÿä²\ÿä³\ÿå³]ÿä²]ÿä³]ÿä³^ÿä´^ÿå´^ÿå´_ÿå´_ÿå´_ÿæµ`ÿæµ`ÿæµ`ÿæµ`ÿæµaÿä²aÿä³aÿä³bÿä³bÿä³bÿä³cÿä³cÿä³cÿã±^ÿâ®Xÿã®Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿâ¯Xÿâ®Xÿâ®Xÿâ®Xÿâ®Xÿå°Xÿê´YÿìµXÿëµXÿëµXÿë´Xÿê´Xÿê´Xÿê´XÿÌšHÿ ÿ#ÿ#ÿ$ÿÿÀÀÀÿ¾¾¾ÿÿÿÿÿÿÀ™IÿݲZÿܲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿܱZÿܱZÿܱZÿܱYÿݱYÿݰYÿݰYÿݰYÿݰYÿݰYÿÞ°YÿÞ°YÿÞ°Yÿß°Zÿß°Zÿß±Zÿà±[ÿà±[ÿá±[ÿá±\ÿâ±\ÿã²\ÿã³\ÿã³]ÿã³]ÿä³]ÿä³^ÿå³^ÿâ³^ÿä´_ÿä´_ÿä´_ÿå´_ÿå´`ÿåµ`ÿåµ`ÿæ¶aÿæ¶aÿæ¶aÿåµbÿã³bÿã³bÿä´cÿä´cÿä´cÿä´cÿä´dÿä´dÿä´cÿâ¯Zÿâ¯Yÿâ¯Yÿâ¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã°Yÿã°Yÿã°Yÿã°Yÿã¯Yÿã°Yÿã¯Yÿã°Yÿã°Yÿã°Yÿã°Yÿã¯Yÿã°Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿâ¯Yÿâ¯Yÿâ¯Yÿâ¯Yÿá¯Yÿá¯Yÿå±Yÿé´YÿëµYÿëµYÿê´Yÿê´Yÿê´YÿÌšHÿ ÿ#ÿ#ÿ$ÿÿ¾¾¾ÿºººÿÿÿÿÿÿÚJÿÞ³ZÿÞ³ZÿÞ³[ÿÞ´[ÿÞ³[ÿÞ³[ÿÞ³[ÿÞ³[ÿÞ³ZÿݲZÿݲZÿݲZÿݲZÿݲZÿݱZÿݱZÿݱZÿݱZÿݱZÿÞ±ZÿÞ±ZÿÞ°ZÿÞ±[ÿß±[ÿß²[ÿà²\ÿà²\ÿà²\ÿá²\ÿâ²]ÿâ²]ÿã³]ÿã³^ÿã³^ÿä´^ÿä´^ÿä´_ÿä´_ÿäµ_ÿäµ`ÿäµ`ÿäµ`ÿåµaÿåµaÿåµaÿå¶bÿæ¶bÿæ¶bÿäµbÿã´bÿã´bÿä´bÿäµcÿäµcÿäµcÿäµdÿä´dÿäµdÿä³`ÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Zÿã°Zÿã°Zÿã°Zÿã°Zÿâ°Yÿâ°Yÿâ¯Yÿâ¯Yÿã°Yÿç³YÿëµZÿêµZÿêµYÿÌ›Iÿ ÿ#ÿ#ÿ$ÿÿºººÿ¸¸¸ÿÿÿÿÿÿÛKÿÞ´[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞ´[ÿÞ´[ÿÞ´[ÿÞ´ZÿݳZÿݳZÿݳZÿݳZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݱZÿݱZÿÞ±[ÿÞ±[ÿÞ²[ÿß²\ÿß²\ÿß²\ÿà²\ÿá²]ÿâ³]ÿâ³]ÿâ´^ÿã´^ÿã´^ÿã´_ÿä´_ÿä´_ÿãµ_ÿäµ`ÿäµ`ÿäµ`ÿä¶aÿä¶aÿå¶aÿå¶bÿå·bÿå·bÿã´bÿã´bÿã´bÿã´bÿãµcÿãµcÿãµcÿãµdÿãµdÿäµdÿäµeÿâ±\ÿâ°Yÿâ°Yÿâ°Yÿâ±Yÿâ±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Zÿã±Zÿâ±Yÿâ±Yÿâ°Yÿâ°Yÿâ°Yÿá°Yÿá°Yÿá°Yÿâ°Yÿå³Zÿê¶ZÿÌœIÿ ÿ#ÿ#ÿ$ÿÿ¸¸¸ÿµµµÿÿÿÿÿÿÜKÿßµ\ÿÞ¶\ÿß¶\ÿß¶\ÿÞ¶\ÿÞ¶\ÿÞµ\ÿÞµ\ÿÞµ[ÿÞµ[ÿÞ´[ÿÝ´[ÿÝ´[ÿÝ´[ÿÝ´[ÿݳ[ÿݳ[ÿݳ[ÿݳ[ÿݲ[ÿݲ[ÿݲ[ÿݲ\ÿݲ\ÿÞ²\ÿÞ³\ÿÞ³]ÿÞ³]ÿß³]ÿà³^ÿá³^ÿá´^ÿá´_ÿâ´_ÿâµ_ÿâµ_ÿãµ`ÿãµ`ÿãµ`ÿã¶aÿã¶aÿã¶aÿä¶bÿä¶bÿä¶bÿä¶bÿä·cÿä¶cÿâµbÿâµcÿãµcÿãµcÿãµdÿã¶dÿã¶dÿã¶eÿã¶eÿã¶eÿã¶eÿãµcÿá±Zÿá±Zÿá±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿâ±Zÿã±Zÿã±Zÿâ±Zÿâ²Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿá±Zÿá±Zÿá±Zÿá°Zÿà°Zÿá°ZÿÇšJÿ ÿ#ÿ#ÿ$ÿÿµµµÿ³³³ÿÿÿÿÿÿÜKÿß¶\ÿß·\ÿß·]ÿß·]ÿß·\ÿß·\ÿß·\ÿÞ·\ÿÞ¶\ÿÞ¶\ÿÞ¶\ÿݵ\ÿݵ\ÿݵ\ÿݵ\ÿÝ´\ÿÝ´\ÿÝ´\ÿݳ\ÿݳ\ÿݳ\ÿݳ\ÿݳ\ÿݳ]ÿݳ]ÿÝ´]ÿÞ´^ÿÞ´^ÿÞ´^ÿß´_ÿà´_ÿá´^ÿáµ^ÿáµ`ÿâµ`ÿâµ`ÿâµ`ÿãµ`ÿâµ`ÿâ¶aÿã¶aÿã¶bÿã¶bÿä·cÿä·cÿä·cÿä·dÿâ¶cÿâµcÿâµdÿâµdÿâµdÿâµdÿâ¶eÿã¶eÿã¶eÿã¶fÿã¶fÿã¶fÿã¶gÿá³_ÿá±[ÿá±[ÿá±[ÿá²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿá²[ÿá±[ÿá±[ÿá±[ÿá±[ÿà±[ÿá±[ÿŘJÿ ÿ#ÿ#ÿ$ÿÿ³³³ÿ±±±ÿÿÿÿÿÿÄžLÿà·]ÿà¸]ÿà¸]ÿà¸]ÿà¸]ÿà¸]ÿà·]ÿà·]ÿß·]ÿß·]ÿß¶]ÿß¶]ÿÞ¶]ÿÞµ]ÿÞµ]ÿÞµ]ÿÝ´]ÿÝ´]ÿÝ´]ÿݳ]ÿݳ]ÿݳ]ÿݳ]ÿݳ^ÿݳ^ÿÝ´]ÿÝ´^ÿÞ³_ÿÞ´^ÿß´^ÿà´_ÿà´_ÿàµ_ÿáµ`ÿáµ`ÿâµ`ÿâµaÿâµaÿãµaÿâ¶aÿâ¶bÿã¶bÿã¶bÿã¶cÿã¶cÿã¶cÿã·dÿáµdÿâµdÿâµdÿâµeÿâµeÿâµeÿâ¶fÿâ¶fÿâ¶fÿã¶fÿã¶gÿã¶gÿã¶gÿâ¶fÿá±\ÿá±\ÿá±\ÿá±\ÿá±\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ±\ÿâ±\ÿâ±\ÿâ²\ÿá±\ÿá±\ÿá±\ÿá²\ÿÅ™Jÿ!ÿ#ÿ#ÿ$ÿÿ±±±ÿ®®®ÿÿÿÿÿÿÄŸLÿàº]ÿà¹^ÿà¹^ÿá¹^ÿà¹^ÿà¹^ÿà¹^ÿà¸^ÿà¸^ÿ߸^ÿß·^ÿß·^ÿß·^ÿÞ¶^ÿÞ¶^ÿÞ¶^ÿÞµ^ÿݵ^ÿݵ^ÿݵ^ÿÝ´^ÿÝ´^ÿÝ´^ÿÝ´_ÿÜ´_ÿÜ´^ÿÝ´^ÿÝ´_ÿÝ´_ÿÞ´_ÿÞ´`ÿß´`ÿßµ`ÿàµ`ÿàµaÿàµaÿá¶aÿá¶bÿá¶bÿá¶bÿâ¶cÿâ·cÿâ·cÿâ·cÿâ·dÿã·dÿâ·dÿá¶eÿá¶eÿâ¶eÿâ¶fÿâ¶fÿâ¶fÿâ¶fÿâ·gÿâ·gÿâ·gÿâ·hÿâ·hÿâ·hÿâ¸hÿá´bÿà²]ÿà²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá³\ÿÅ™Lÿ!ÿ#ÿ#ÿ$ÿÿ®®®ÿ¬¬¬ÿÿÿÿÿÿÄŸMÿàº_ÿáº^ÿâº^ÿâº^ÿâº^ÿâº^ÿáº^ÿá¹^ÿá¹^ÿá¹^ÿà¸^ÿà¸^ÿà¸^ÿà·^ÿß·^ÿß·^ÿß¶^ÿݶ^ÿݶ^ÿݵ^ÿݶ^ÿܶ^ÿܶ^ÿܵ_ÿܵ_ÿܶ_ÿܶ_ÿܶ_ÿܵ_ÿݵ_ÿßµaÿßµaÿß´aÿßµaÿàµbÿàµbÿáµbÿáµcÿá¶cÿá¶cÿá·dÿâ·dÿâ·dÿâ·dÿã·eÿã·eÿá¶eÿâ¶fÿâ¶fÿâ¶fÿâ¶gÿâ¶fÿâ¶fÿâ¶fÿâ·gÿâ·gÿâ·gÿâ·hÿâ·hÿâ·hÿâ¸jÿâ¸iÿá³^ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ³]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ³]ÿâ³]ÿá´]ÿá³]ÿá³]ÿà³^ÿÆšLÿ!ÿ#ÿ#ÿ$ÿÿ¬¬¬ÿ©©©ÿÿÿÿÿÿ³CÿͨSÿΩRÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿΨRÿΨRÿΨRÿΧRÿΧRÿΧRÿͦRÿͦRÿͦRÿÌ¥RÿÌ¥RÿÌ¥RÿʤRÿʤRÿʤRÿÊ£SÿÊ£SÿʤSÿʤSÿʤSÿÊ£SÿÊ£SÿÌ£Tÿ̤Tÿ̤Tÿ̤TÿˤTÿË£TÿÌ£TÿÌ£UÿÌ£Uÿ̤UÿͤUÿͤUÿͤUÿΤUÿΤVÿΤUÿÍ£UÿÍ£UÿÍ£UÿÍ£UÿÍ¢UÿÍ¢UÿÍ¢UÿÌ¢VÿÌ¢VÿÌ¢UÿÌ¢UÿÌ¢UÿÌ¢UÿÌ¢UÿÍ¢UÿÍ£UÿÌ¢RÿÍ¡Pÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢Qÿ´ŠBÿ"ÿ#ÿ#ÿ$ÿÿ©©©ÿ¦¦¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ# ÿ&"!ÿ(%$ÿ*('ÿ-*)ÿ0,,ÿ20.ÿ620ÿ842ÿ:75ÿ=:8ÿ?<:ÿB>>ÿDA@ÿGCBÿIEEÿKHHÿNKJÿPMLÿSPOÿURQÿWTTÿYVVÿ\YYÿ`][ÿa_^ÿca`ÿfdcÿebbÿ#ÿÿÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ&ÿ"ÿ#ÿ#ÿ$ÿÿ¦¦¦ÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ# ÿ&#"ÿ)&%ÿ+)(ÿ.+*ÿ1.-ÿ40/ÿ632ÿ965ÿ<98ÿ><;ÿA>=ÿDA@ÿGCBÿKHEÿQMHÿSQPÿXVVÿURQÿVSSÿYVUÿ\YXÿ^\[ÿa^^ÿda`ÿgdcÿifeÿkihÿollÿMJIÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿÿ£££ÿ¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ#ÿ&#"ÿ(%$ÿ+('ÿ.**ÿ1-,ÿ3//ÿ632ÿ865ÿ;88ÿ>;:ÿA==ÿC@?ÿFBBÿMIDÿWRIÿZXXÿponÿSPOÿRPOÿXVUÿ[YXÿ^[[ÿa^]ÿca`ÿfcbÿhfeÿkhhÿnkjÿpnmÿ*%$ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿÿ¡¡¡ÿ¢¢¢÷ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ# ÿ&#"ÿ(&%ÿ+('ÿ.+*ÿ1-,ÿ40/ÿ643ÿ865ÿ<98ÿ?;:ÿB>=ÿEA?ÿGDCÿJGGÿLIIÿOLLÿTQOÿURQÿWTSÿZWVÿ]ZYÿ`]\ÿb_^ÿebaÿgdeÿjgfÿmjiÿpmlÿsppÿ[XWÿÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿÿÿ¢¢¢÷ŸŸŸ«bbbÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcccÿŸŸŸ«¡¡¡ŸŸŸ«ŸŸŸ÷œœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿŸŸŸ÷ŸŸŸ«¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿøÿÿÿÿÿÿøÿÿÿÿÿÿü?ÿÿÿÿÿÿü?ÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(  × ×  ÆÂ¾“ÔÏÊÿÝÙÕÿæâßÿìêçÿíëèÿçäàÿßÛ×ÿÕÑÌÿÈÿ’wqjš”ÿŸ™”ÿ—’ÿ•Šþ’Œˆþ‘‹…ÿ‰ƒÿއ‚ÿf^W&ÄÀ½ÿÇÂÀÿ Ë ÿ ÿÿ ÿ ÿÿþ þÿÿÿÿÿÿ Ë ÿí5ÿâ‡4ÿã‰7ÿå‹9ÿå‰5ÿäˆ5ÿß…4ÿ܃4ÿ݃7ÿÝ‚9ÿÞ;ÿß<ÿ߀<ÿé†=ÿ ÿ ÿí•:ÿÛ‰7ÿÞ‹;ÿàŽ=ÿÞŠ9ÿ݉7ÿ܉8ÿ܈9ÿÚ‡9ÿׄ;ÿÖ‚=ÿØ?ÿÙAÿæˆFÿ ÿ ÿï›@ÿå•>ÿÞ>ÿâ“Aÿä•Bÿä’<ÿâ‘=ÿà<ÿÝ<ÿÛ‹>ÿÙ‰@ÿÙ‡BÿÙ…EÿèJÿ ÿ ÿîžDÿæšBÿæ›Eÿâ—Eÿå›HÿçšBÿèšBÿçšBÿå˜Bÿâ–Aÿß’BÿÛCÿÙ‹Gÿå‘Mÿ ÿ ÿë¡HÿäGÿè HÿåŸJÿåŸLÿæ Kÿê Eÿë¡Gÿê Gÿé HÿçžGÿâšFÿÞ—Gÿè›Lÿ ÿÿè¤MÿàŸKÿå£Lÿè¦Oÿæ¤Pÿç¦Rÿæ¢Lÿê¥Jÿï¨Kÿí§Lÿë¦Lÿê¦Lÿå¡Kÿí¦Nÿ ÿÿä¨RÿÞ£Oÿâ¥Oÿæ©RÿçªTÿç«Vÿè«Vÿå¥Nÿç§Nÿï­Oÿî­Oÿì«OÿêªPÿô²Sÿ ÿÿæ±WÿÝ©SÿàªTÿã¬Uÿç®Xÿç¯Zÿè±]ÿå«UÿåªRÿä©Rÿè­Sÿî±Tÿì°Tÿö·Wÿ ÿÿé»^ÿݯYÿÝ®Xÿà°Yÿä±\ÿä³^ÿæ´`ÿä²`ÿã®Wÿä®Xÿä¯Xÿã®Wÿæ°Wÿø½\ÿ ÿÿõÉdÿæ½^ÿãº]ÿâ¹_ÿä¸`ÿå¸aÿå·bÿä¶cÿã²\ÿè¶\ÿè·\ÿé¶\ÿç¶\ÿô¿aÿ ÿÁÿÿÿÿ ÿÿ#%(ÿ349ÿ348ÿÿÿÿ ÿ ÿ Áàààþ‰PNG  IHDR\r¨f€IDATxÚí½{¼íÉUø]µ÷9ç>:};î¤Óm^$0c À@@3Œ¼„ñ‰|eü¨ ‚¨È‡ññD˜ " D>3„¨è 2HD“€t„„¼È£“N§ß{ï9gÿjÍUëUU¿}ö9·ûœ¾Ý»îçž½÷ïWÏUµžµj°MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´M×cúÁüÁ³îÂ6mÓ6áÚpqy íÞüÚ×¾ö;www¿h±X\"¢³†Ã6mÓS&13¦izðààà§|€ûNRω°öµ¯}í+vvv~émo{¿ñ?KïßÀೆÉu˜D((%*C„$¿ë;" 4ÏôY]šOÚêóùÌõ…Ö=Ó²®­Úþ¨^°š&¼ç=ï>ëI¸.SJ <ç9wàü‘?Ê/{ÙËèðððúʯüÊ7·žc€*jܼ\.ï}Ýë^Ç¿ð ¿@—nºÙ®NöÉš__nþå¸ÜѰrÇ£ƒÇ“vH#¥„”@ùL‰@”@DH)„×ßön±°ï”,QªùÊ3$Bòu,¨É—S—ßò,ÜwPBéjªïjý”Ê÷Ú‡øÞõ¥¾Åb·¾åWðÎw½ë1œ÷Íæå¤óþDJD„Õj…Ýù>|îç~Ù—}­V«g¸ï•¯|åÆõ¤ã4úÊW¾Ìüo{ÛÛø~á覧?£É‘0˜7•b¾õÅrÍßg—;ºVn¾îq¹Íó<ÌÒ&»öYë$p•¤8¼ËÙu–kû̲{Ì5{iÁµ¬>¶¹‘:Xž±¨<Ëå½oíÕ%ݪíYþ™ës®ãcÆ£<ŠßzûÛu|›Ñ¼Ï¬ˆ®Üfóhå®_©•™‘RÂsŸ÷BüüÏÿ{úµ_û5fæï<òÇ$°··÷Eo|ãéÒM7—EÈ0Á/è ‡Ò l.¹¼5º7åA××ϧ2QXÚ®ÏX5ïvã/jÕ|,%¬ YòÖÊ–:n¼t#^øÂÁr¹„´àZÕªÈ*²¾©ø/„‰z â?[¥D Ëþó›ß\Û­ã“âHý¼·plË­_#ãr×/ "äœqûÏÃÏþìÏÐÞÞÞ·Žc€åryé}ïÐéšná,‰@_öhŽÐ/ž£RÉ»)~PEZfè÷ÐO% †¶Äìtl |÷½ %¾êò€S°»»‡gßö,ÜrË͸íYÏ¥²DQ" •Ú ømˆ/¤„C_ìýݹwÞyg˜›õD`ÎR.ŠõO-"°\.ñ܉åryé¸åM‹ÅQ²:+"0.:Ï­Ç èèÅË<¶D ÙŒ {¸xb@ÊÙ}­Âu®D€;©BÐÍ8·ÖW;?ãv\üô/rÆÞÞ.Þô¦7á½ï}/>üá!Õ>=øàý¨±ý̬}fŠ'Qþ/—Kü§ÿüf•:|+=2w³4ãvΟZD€™‘óTpó˜éØ 5ø­É O6ƒ/»2ŸsuǾÊm¶b™Ç‹ô¨øÎÁ”·Uä"C¸wuÀ[ýÕyï‡pùÍ?¤„G/?Š—¼ô“0­&\¼xrÕ)o¼ñ¦hÙ—¿ÔŒÑÁneölíÊÃúè]ïz7~øáٹ鑹›¥ æoóy²2–ã5íàlf­EA´uŒ³så’Gq…^ðùÙ!‘¯{ñ²2›ÚdŒ¤\Øê*H%póuw\ŸmR gOÎŽø2ÊaT|î[Ë TtÇ{?z7ˆH¾=ø¶áÔZÞ«°ßq|vu.Ò¿ú«ÿEaâá×ÎÍÑ’ÀøåXX?ïqÍð‰é‰N•”ïU$E†n>¸ÚSS¶E±A+M›ÇË¿¾Üc³UDƒÁŒ¶¥8ÄËu+,×-¾L¢˜Ðíº²mÆ ÝVãúœõw!¦™d+1!l;„¶õÜö!l›.%Û6 ÛƒnÛ¯-¶ûd[0%$ –ÑmL©;a‘ÿõïÀá•Gý¢Ìͦ#&³~1Źà#ók®`8}%"¤½#²œˆÔ»p(fãùà*^ðUß…›žy+–çΡ²©kKsF¡Y‘7«ƒxÀóË€«ΑömÐ…£$ ’B>ž©mX·ÎDÁšÖµy!X˜Àä8êLiüxñ±¿û´Ü“ôCÆSLÌ«ƒ}\¾ï#¸ëõߺ–´¸¹Iº&P…õ@˜—žy+nyÎó°{áB/›oøá£Gƒì39Ú»v‚ihÄ üØ[K(¶Ü¨ñíöÏõ»ï©¨Æ:"nÞlÏéæL€Ã)h=@çh²Žvv­ž]é8»I$f\½‚(ã®#ª=Њ-€år˽],÷Î5¹7õð«Ê¸È „æŒ;G¬ÖDó 皣4$M³FzWÜ·%r*a\‚Q¤¢a ã_îùÓ´–dÑÜ;ÂÄŒGóBmÚ þ ¥¶#« ënŽˆ¹År´•3–dF΋åŽ",§nð°"`«µÜ·6q·ö½ÎëòÊ'Uvî2ucyèÛ÷½HÅB%<û%+”6™4Oùð[j½¦rýÁ(N;V½Q'gz‹½#3! HŽÔ0Ç+zÇ%[ÔëËÑ€pX9på‡^ qîf)ˆ¯ò„iH·¦éµ©£z4Îäç5ìö8«eXÛ ŒÖQWÉuº6›oŽt €x}V% Ü/€Ø¾FØ–êˆG×TwœÏïÍGªî-ÞÎèDd¿ NjPHB’:¡Áª•!Z`ÕrɦÍv@€†6›£ËFôRY&vÓÔ´‘6êšæh`ƒ Üœ=.iÎX¹¦k­'m ‹cH g Ä…¡¯œK6wyç~’שÒP³Š¼à y‚1”hÐ;SqæÑ¡,0î*®è-:3"ÂÖÜduxŠl žx0Ê.°' ÌS%(²ªlÌA^èlO|÷_x!××[N:^Lè’ÌÝp.F)¹‚o-mX÷µ¤‘g8Øù~×/IoÐú©ªŠ!=:0™0í`-Z 6<»ÿC5)HéhËeüc% ÕzÏk_?©W05)SÕùk›LlÈÃÉ!Cò–øyÎíY.Ûáê¸#‹†áñÚuì}Yf\|rÖúæàºú€£Ö\S»y`ƃ©H$ë$ä£Ôó.™;äc—2)k¬2n¨³´RMX^2;ÂP=(RÓ©«c"P¦žÝ§ˆà„ž¡Éî\àF?gÝïŒkòhoaú}(ÛŒQ{k¿<»µ1I}2±Nßw0§$ùžÀôÿ’/7–ZÄpè×ùv[©¨>$rCx 3k‰‹Ù íƒ¤ÊÑÌ;Q]L%¼²âjºq;²×el <îÞzý¼¯GþHž¡®v}7o}Æž®®ëñYìôDÀL˜¡G7Tg'ˆ8Üd¤óƒ ^8ë¸Êi²6y6 7ž:>Ǩå?˜T -V÷Û¦vh]"”ˆˆ,uý˜ÃµCx¯ö85Åæ€¸µJ WĆ ž~ -Éïîxi/ùQQícb`ŹÇUö”`nŽ×¥Çù7áàtŒçsyã: pk³ -Oçõà,<µ*®º·‹ŒÉKˆnáôgéAÒœ™Ôí¸§È´ ®"àDMcµ±?†‘ì믛p&K˜SÓŸÂaÊ£dêÔ¡’µ?Õ=x†½tȘ³Ž™URш‘éÁÚÏ Þµ9We†•ê,€Ù¬/»I}Ô¬O'ÑùìCñÿ8í¶ËÁºm%U¯Þ°HÉGS€SVŒwÉ/hoÕUv$Ïââ)3†À?=×XcÉ×·:? &¼@ÉÆãÞFÙ››z Ò ’*z52FBâØj/ë56 Ian ƒþÉsÞ0^Â:Sc*ŒÏu~£dsÙ›3ˆ^Å~÷0ßP÷Æ\½í D„i µÞ¨p×s¶v8´¦Í û˜hU¢ 8âp&€hËnšýœus5’{¼1ÌÔ„Vbê«XcŽ=BÇ×g”#+cg¿­ãgvö§*ÔgDÆí{þLýs1¼P4w¿Ø) ·Ð=à©ì#%`Êc½ùHu:­?W7^¿¢“Ø Ì'ÀäÂZ_rî€A¯¶1¥!ÌëÈò¨2£am»–?Ìe£¡µŒ‘dtˆpœt½˜/3’ØÐ/¿.Ôê?מTPͧ‹% †=ón°/ãšÞ·áxÎà80Ço¢nR±'Ñ#’í5A`vˆUN²ýRt]$Ò{¯ÃN¿£¾̢ |ûÜxj|“vDÔ õ–ÏpæPÇ*FÀ<•<´ ù¾P/œø…á¿ÉÑeÂÆ¥ØÒè:©el•Ø1ã süe]š‘ß[•æqK-µÙ$D|€°R#@-w@‹]Õï‹t瀩_=s‰ Aq†ÇaNDŬÈÇLƒ³CC’xƒ•â«éÄ<šm˜XAÛjú_‰A2 _ˆ½÷èòŸbtS9CŽÃ2gë °eÇ-AU˜½59=!«ÑƒØÍ›ÐµW¥›¡¹šX`Љý‰çÂv°jáó<žH?ä‰tûŽRFì6ÐrX.ÕЧÜqF%Äö,ÔªWøÑ=:WàH|×ëRv½÷lg@éÛ6‚4ƒuavôä‹W^Ûgês·ÄÚów£:„€%‡ø ©%6•›Ϋl;1EÝ¿…“î€8é†ÌµÚC£ôy&ÊF8WKý``F4R "pâö˜Ó(”voÄ\ŸÖ¨ëÖu‹»^|Ÿ6C›íÃãz‘~ âϭ3 ñ|]Ý;6ûàét%aÒΈ¡ d÷_åMe-ëáéExÀQÍyÑЦÐsËäúäÅråD•Ha“Oþ7H¤¤'Äø÷"¹ónëv5WiW¶ +åñ‚dªÝV§’d…qÃï=‘4f^`@Üæð9˜¤PŽï˶—8<(ÐV?ž¾õ)¨3ïýÔ·ÚäH` ÃðjبÂ6±ûVöïÓrHõƬ© ¡*ëCŒ.#‘éé[5;ŠS7€šÙ¨Þ\ñ ±ü ›ùÃ;Y€¶æ¬´«Õ¾µÚº´gõ_O²Ñb²ù†:ÇUcw»»U÷î;B*9$Då¼’£f¢Ô‹ R‡è”* ¼ŽƒüØJG¼ËD„QyöF5#· ¿V¢^†õ|DÎŒCïãÑâ̱֣Ç[|ô®y¶i»Ã¾’«Îl1ëŒ$´X‹~JÕ‹rd„iúìUªaÇ8¼*ÝÙÜzº7¡â«Ž±¨À$PÙ*`Žæ°³¨Rü>›zÎÞJ}ò6‘^ôzËjæ6Ëë»ã¸%èf‚nw¢Ú r­u²”ACÏªŠ¢6?· +G  oLôçl^ç#)+åÄÀˆäÉ垃˜ã\5Ÿ'NWÂÔôÞ(³fNhÍûQà jÞÍ­ Ì×Û™„؈@§³×ÌËeA|JEÔÏÞ;4w\¼JXïC"£ï׆4àÔmS…`Ž×v÷8£È¬ý¥Gê>ùiÙ°Œ 8œ¸J Üg§ìZ/ˆYG Ž¿ðçÓHBeÐÎ.°Ü…€§¼oÖ@‹ÌGµ³aº± 8eWà"ò³_x8²îucHkú”òs¦Í‘"·.ÏèyÿŒ20±Éuâ™\r¢6 W7ý¢¬ÜÛÔ rTÞs/—Jü~8›A³!=‘àæ½«³5Ñ@'ƒpºª²$é¯Þ$µpcŸ"\]å¦+ëõåÍMYGZ+š4ùp¶]çÝ=`±[çÕËǫƤiŸcó t}ᘇ™ÁÈØÄàL¶I¸üHâV©ŸšÀ<‰Ü„ûÓu=â×gºøýkêo4$ ‚ëdˆB±T¯:C¨×%R†SïTýú-ßnö퉰< Þ$ ý¨Ÿ’æÊa•ëøqDz,9óµ&„sÄŠõrФ}9ËÙÀHlT£j†;" œ3ÐÁ¹»Šè`œ\3³¹Äg®ýgH;ˆ£ÁlZhêðI1ŸØ qІYøäŒ„¾Ru éËÁ ¶+¥?æi%i’CŸI™±ùWÈ‚¨ê Ê Í1q]_c¸&]»¤[×Ò‡ìêÐ~0Õ#ÁUîaÆþäæ S§òµ/×=Û@ŸŸmt>#vÏ‹¢Þø¥2J<óÀÇ· Ðõë²6ÐÆoPä¯å¸X«6±žðHQÝW•ÐÚâÔ2茛\B±N" q¾–qÂcûþX—Ø!ÙxÕýÓß‹ØJ!¢? 77.-D tÅ÷ÓàB^ï–îhÑäúááiö‰Z‚ÀPiö ¹©1/Œ÷ÊjÍaŸYÉšÇyƒdao߉omhðVÈ Äs`æd.7ïÄçzäœ\;£Õ8/PÐ ó ¬FïCY>=]# µHÂõ³¹çÒˆ(¬C~Wn<÷mP©Ï¸kÌÂ(Ñzx¾aáäcõ»ºªBYtu©Ër‚E£v‚ž1°"[žax/¿KàŒ~…Õ ±Ú%¬/+¦Ìó -w}3 Ï-ŠuóÝŽyF YzÉ¡8ï,öΩZô¹ÙÃg‘ÜŒ{wË·ëþ@¬ï0gʶðqâôéômà (Àe83X®¨R狹sè0ÛÏ5ÒÍ<Ÿ!Ç %v¨îý+nX@¶l‰Û6 Ì^_W·`uÂëà\|J^'/i©mG›n%†ZU´Î;Bla¿¥¿%>˜<äœõgV½µ¯„ïs„ƒ2tÄ›çï$Å™®èur¦ÂÐb‰´»9œS¦½©ÇÙâúQr¬>¸cÙ‹G„«ÿ1ãЇMÒÙ¸ˆ@0z‹±ƒÛ÷›";0žìFÄPJ3uûvEÎKÎV–«m`,K’Iy²°8A¬u&`X¸ ¨ê˜BÝnA”M”.%/¾Ö,9„ï<íuº©úuÌÐbéÍÁTˆEDÈ1~l­}ºa;Š™¹|].ÕkO¬úæ%:î?uˆÚ·o¾±ÇýÕð#É¥W¯Ùg?"~T`Êh}Óu€„r{gp8ˆï³bÞÌçpÎÖé’NÑ6}’LPv­ ’’ïË´jƒ\È}/°§²7îV]AìÒ'vcM®O’¨\ǤÇ嫨i?ƒÃv¢º©¢š ñÌ’'W¦G€b BQ Übýµ¾ D¦ÜK«¾ÌH²óÒÑF‰ÂTëior: wUíì‚vvÁzF"7[©#ø­‘³)78ëÖ'£Yz®]8£zsŸÏ6˜è%{kÓ™lZttg ©ýf‰ Çeç`d§[«¸úÃóF?”™Ìée(QÄgz䇨éÄs—pä\ƒãÂößxàiÒÀ7Aöu‡çm&#ÝjÐîL}âòl‹•üÎe¹Ýgÿß 9/pMf€Á¨`¾M¶rÃãÖ}:ÎÉAI'¿¤‘¸½iÊ•ý ý„z6¨ÿ(Rcó鎇ö9Rõ(ȇPUÏg'miÃr9CàÔ7¦þy—Ô€iÕƒ,¢¸ ÷Ý©½¾Ÿ>ì·ãlÃp =lk³ˆ J]´9ë?”6¢$'L!¨ªï­ALž¥Ý½¢ãƒtVÅCs\Z€5€¬NõhlØl®ßºÖÒ0ª“ÜL›*@Ï!è8éÚ$€Nì‹È,·gÔÞ/ݯòVõï¸zE´j‹^läôï’IlÖVƒ!VÇÀ˜«õD¡ ù-êûK0âÄÔm¨X'*ûÈ=¥ŽN@õD±È÷è ׇÜ,Ö6ÉëLjçØÏŒœ7 ñýX§¡˜Øöìw÷@;{ÕÂ] BªkO3g BóL?t]5ÜqVº¦xüzÈá«Ä›×/›Þž†Ð5ÒIߤÔËðˆöf\¯ uU® t{ùªŠÉ¥›Ö?Ÿâh#÷ñäïT„9ªïnêÕ€3º½‚îrIOãÈrßéz î ­õm~öÆ=ˆà‚ªÂ>`®Ã®ÏÌ8˜š >:ââëÁ‚ð»Gv|TGlƒ™‘vÏįœBg˜š²nËÃ4?é‡Cè x̆9ûûuìŸûjæ$›Buì³pj²Ÿª € aQI‡¼í9Q£‹”@púVD(Òy%Ÿ¨'û›0eÑüàŒTò“}øïØTâ&[ìÉÝs(ÄÀd0ërl>KÞœåè4×  ­¾X>ôÞ?ïÁê9nÏ“]Êr¡ˆW·J-)GÉDà\¼÷W\CŒ7Æ?OA¾j5'ë0Пœ›]§»2ÒÎÒî¹p{ÎlAŠôÝwˆºV ²Jt¿¦PÅÍ8ñˆ–9É´¦ÁÓµžƒªZ\ç’ùDƾ¹tb @hpµ^\|^Ç—›kµDj •ŸôþÖÅ’J¸nÑùÂjж» É½Dw“â8“É~zP¶¢ò¤jJ;‚–Ië™X{©§Ý[ãè]jÔë(Kr·_£ÍJ´ËkÊ5ÍFQ1NÉΨ"¾-‹u‹_ÒHwÈß?‚cñ!H¬¡^DF6ääRw£Ö¸­D3.§ :§â’¨@&¡ˆÀ)K~á±M6 AŠ«½¥ãµHî»i÷p\ìÞ)@;Öh@ÈÕÒÎMÌ X ™Ù®:â_µ7'·²mßQ•üÐê³i ŽøäOyy‘›cŸÍØÆæ-ß_x| è×Êi€+‡EÜ`?o^”më™M<þ-ðêá%¥`÷JPhŠ!4Ápœ·q:µs8wŽs†Çm!ô¬qÎã¶M–Ô>©{ÿSnNû]³¤ÙÚ æ8e]EKáø {=F»!x2‰ƒëÛü8c ï¼ñÓé±sõÊ‘d‰iÍ-B_˜3ÊžqÖ÷!u#b‰pDÔúï`¤Û]züÔ”+ÄX¨õÅØÍvÍ«F‡ >žǺ îWâÿ‰8W&­ª,ÌaÝhl­Vå÷Hø‰ÀÓªHÜ™šø•^¯i?ÝW¼›Kýw”%>¨ª3öWnlYìq«ÎS7!EÔO ižÌgÿ Ÿä¯uPìC4LÅòa½¸òä÷ò}Ù°^Þä_ÊÝûhÐQЍ⥙©{Í Ê1œÓV<ˆ½xª6È¥Î&NÞQ5¸»ã-íì·}*Å­T´ –Á-Ežgî#®þêÏïwÄx':˜£j,äê ÍC_f·³/¶аj S¿¨ÛAõÃ]{HÍ#Ÿ¬.†ÍV“…s_§g÷rÈ(ùD½¾¤âš›–; ½‚øæC¥À@ÔuÝ8ƒewäÑ1•:ײ£w<¨×C¾›»ÚÛ#û F«&Ø„€UÎOëfrLŽ›N.4 fø©L•³ëâŒT»\…]Ù ºefÔĤyäWŽí;cÖjƯäO¶;ÆÎâ+å$lXíˆ?@Èúê¥b¸Z­êš2Ö PPY²åMq„ÙRnêZ×N"õÿ9¨A>Íw£]¶ÔNùiàÄ/{ù‹{ Çg®R! Ûìï0cŸQ~ ‡nB7@zTõ’&úw:Âáå³®9–[æz ŽÙbÈPžàŸ†£Ÿ¼SWDd·w‚ á:?À‰ölXsËÙ[(µú}àð-2yQÉ+ëF4Ì;Œ‰ˆ±‰l>Ø0† ­ÕÜÌ@En+:\²KFÚz}*P/&‰í4 NsÚ Q ÖWW>¦#¹ …+‹ä$ð â¾~åÀD Ð9‰¹ÇM{M= „ãæþ¹ßÑÃd@¤”-‡^Óž iærÎG J¤>P¨®•èmü^c4(±¶­†çìäù2nîÕí?[Ÿ4ǹñeõ1ëëñ=ÛN¼ææ¹[_Åa;U»±Í‘õoŽ®+"ó°]“1 òCŸ,Ù#ÿfgNUˆ42rf®Ü¿ˆ.‚,~Åz¹ÕéXˆðY%Ï€xTÇò‹ÁÛ¤?Dæe'/©P÷jÂkœ>‰w[)—ØÅÿká2­ B<­g °" àb 6Ã¿ä¬ i8ÝÃw{O‰Ûc„œ«N'öØ5,ù‚ÛêÚª– 5vÎxË^ÇGá¯Ø€`àú¬6#lþ½ëÛH‡ç8&‹˜ì–´–huÛ¦/>eÇô:¼¬H݆õõ 0Zšþ§ÇÀÀ] ¸<ô­éXËì<êp‡×YéÊv|[#ºš óe›*ÀÕªýLOS†âê7ö8&Y7J|¶‘húË5´'nÁÍ+ ¶@[Ü& ‘BD‹¢¶rÿŽsQªc«¯[ˆ²ˆ+Šìî;åL>±?O4ߦ)6Ðwº8á‚ýó5·‰¬! ó3™T@ý æ­6˜é‡ƒƒµæÉ7Ù¸Ûñ ¶“ KæWÆ™l*Pîè)XõÝnnÏ­^Ä{Ž)Hµ^’ãêq›ˆ8¯9§Ë[“ŽÔ ô£ÓD… TîÏ~Š˜ƒ3ÿ#±>¼ê±Ü¶2cóªycWàz·ß¡9|D˜û,‘@”¸{çÂ-QÜÕO®jvߨިÕJHÍnÜìó <8kÛ!Le3wâGÖa%ø‘\ͨÀ¼0Û\Eþ¨Á8 Ǿ¬E×ö;Š=']“ ã†p·§ÒÂ8" È-‹Žó ’—™u—uÃ[]ÛË=,d—5+‹ìÐ÷òÌÆÖ›sj[Ìà<Fç7ô?‚Á2àlú³¾¨>oÁǨa¾ò¨$­¯Ù!]¹TcQ |»ç±LÌa…«g›ÀVn@îÄs¢{¢'.Â2BY3å3[ë`° $rk—c/„IöëºP;f€sFžd‹¯‘RÜzóÈm-|ú^žr@Xޏ:ÉñºòÅ!±~7d-Èi¤Ze61nì³=Šû6‚éE` SÏ…ÉíÖsÍ£‡1œtѨ4jù7ù~õˆKíöKzýi|¸†5žWŒ8X³RHxæ)¤oqîZœ;^,õœ~o#õÌ©L!‘‡‘Ÿc»ËWMjôlê:i€«d¦ËË)m3c–XC®¥1¿mv¿0*!YòdíVבÖÓ+LJÜÍÅ:^ºÆ€ ^¼îé”MϹHôà$«ÞÄÛ[‡üh‰ûY.÷hL.¢“E÷¯ $Dˆ¸DÕzÁxÓd¢+ù›&pJQ<‡\$Ò'ÂÈÃOˆ_¶Ae%†zLgmcì-Ø>çL…û‹d¶Ë½Øb)A hï<°X–S¾Ü©VÎnƦW®±ìû9õË#»5!Hkl†Ýzñ[—ö×$RqÌ™åš]¶CËÜúÍ;¿)¨DNk†¹3>Ü‹•ˆ«n*lÜàÄöÅy°Á1&g$ØIÑávÕBNS4üv%§ R£ÄyàlêbÐ2Þ¦Pëínw…[¼²PTÇlömeRÄÓ+ˆ«µ·Óaé{°ƒ ŠÔÖïàÖ9”Sîæ–À\É0d.N?Ú›ÇOjiBV¡’BËþ®ãø¾l£®¹e¢oC;e>½iRI¯Ÿ¯¶ªJ×]-FÚ6;y8¾o¬TR¶R¢ÖÂ/ßéë'@àդϴŸ¹ïogÜËpwg‰€d?MÀwBî£"gg÷>|¶×aùñ ±¨eÝ…aQZt±Sš<çöÈ_WJoRy+’%pXÔ±ïÁ Â(Tzš ‘ W¡ÇEÔ¦ˆ;&iÐL™@‡úYX¯.001cRg+çåæ±Ù÷G˜׋5ä4¤?«ÞŒÆMw£6tRFyŸEúòz/5=µŠ›j¥²@½nÍ®Xý2™a lÌõ´ŸÅ׃[ð¹8òÔû:FµÛp'¯65PêÃ-^ªþñí1ó¾š6okpR›å£q}.1Ç~uº…[åäSÖqÙŠEÞ@èü¶wöe½K´”ƒÄg`õDà¸éšýˆƒ¯.ªŽP?'v]—ðP®ï&Á¢Ö›t•ó֡p WB[”0½ˆÈe%;é%s%Ô ÷Ð5îOÎÖ5ç@mòÏj¬b8B:¾FǤe”Û}œä¢Ì…Ú9Ô óԵ߾üÉ·5[QÂé¯`›u¾–'IBN®Ô¢û-‘TÙqÐ.QIû=@°:S<­@C¯¿.3²%·‡â²Qëtöõ‰–FVä³Ö%úhÚÙ;Ö™™ðUöÎwz&õ}à^M‘Ú¾0CÓr¯¹ä8¨·áU¬Íð‘6­ ÌLÌóÕ¹…Ë«ÀÏsí³ÜàD@™Í$yÕ3Ö¤4Cì:réÚ·+’Š=26ªž€^|"p½´B\4 dg3(€geWÂá%’ö™á*6¡ …Ë0JÏ«=±çø&*â4ˆÀ‡+0—=ÿ”ì/!•&‰íò‘Ší“Þ[DoŠÅd‹]Ô/g‘Њĕjÿ0WRLZ,AËÝrô¹sIuS*ÈÄþÁ&‹cðÝqIëåÕÄeÔ€÷ µ=[v^aÕŸí5S9ƒ³»ÓÑ/–°Þ8Vï¼U‚g‰ÅzÈ­l‡¨BÈ=‘|¸xÆÜæÝI0d³ÚÚk‡¼:Çþ j «C)0µþª‹·º¤“2Â1_{N©5†ºþ*áh†å\üÐ¢Žƒb»ÙÑ¿ªSêAìR:z\ÂN%àpÅaŠvÎ#WWçtFÏÉ7Éßæ#IY\¼ƒ•ÜIluÄqÝM)]Y¯{ôY³)r,kZÁ#«®ÏŽë×:ä(9¬ÆlYÎhmC•ˆÜoyÏf]ô,CvÂô8ù>Õ…ëôn½2+èãšË‡äÔ"çÓï÷:É„ °ñá–˜$=$G‚rV™Ð@U…Û6HkŽ%€(@oü§®öBã ã¹ÅÃö(:è{Õ¸çL쉣CÌè‰ç$fìtZîT¿}ŠíøÆáj$…ó \ hÁ Ü^Éq.˜¦§×¯´A”7×·.™½¤-Ú]]ÛyªÇv½äÉ¡ ìç‹t¥jê;©º «+U°Ç¨H¨ž™bWs»6&ŽæM§á%™oò”]^»€(r2ǽj Ðµ þ¿_¬uÒPtxáø¥ ‘D(r\rWƒ‡Åë8yXÍ ¼B®Á-@ò”ß}M>|°›®ätëß?â~;·4?Ùû« Z,j`ëh]G¼(ܼM[Fn=Ö™_˜”la³×­®N)ßèU[‡SuHpÅt• ‚×ãÜ%S…¹rfã9BH™H7 ,ˆQY½ëÂKgj;€J•‘Õ÷ênóÖåk—®ÉÀkø² ¡2 °Ž„ÎÞ°¦x³²jõþ31˜˜‹×¾ºƒr¥ B$܉6Å-|aSÌJµõy¶e¢|—_ÏÆuG®/ÃIK~Ïá&É}€ÆÃS陪üÁm‘Úa•v”@9»ºçDጾ"Ç¡Âj~»ù§ôT¹cÕm Lhó ÐO;<Ÿ3gîaäU9ÃO¸²÷ÄÑ ©;O“U¦ÚTm–­ÎäújöY¿^9v´éØÖ—ÑToé€×Ð{ƒÎ©ûˆÅrn—IwÇgḄâ5.×z÷ùÐϺáiKÄ쿼(>3ÔIM'èuîy£_ %Ϋƒj4Fã:‰ÅPŠZhØA/Ç=ZÚ¦.ëÉDöR3@Ù-výe¤å®ä„è™6š¸u\cÒƒ_ªó“›£mÓM_°y˜Ç¥ k†wÔ–ø†á‘Χ±ôLz kETC„O±­ä©¸r“¨ZÜìº(¡f‚1½NWÛÌGåÄ"ê¤Î1JãUjÍ ½0Géøˆ/éØ »Øå*Ò·P‡ æîz±¶‘ã¤.!àLÆ-Ií •ê$Ph¾¿Ø …^<Yé4Íj¥ÄÀvмÁÀz”ˆ|~÷\ÿzÄ;òê9±ã@¨ ‘Ò´ÜÁŠÓtÔõÑ^ X§WtL‡N"æ«ø /a‘óõˆ*¯ŒÅH‰aµ ¾’tκd¸ckÏP½'rö‹ny•!.áE¢ôõ¹5-¢¹ˆ1­$©óV‰˜ÂÃê!ÎæÌ%0t;GR†¼@–ÙÚã£9¼ÇÍMÓ± Àhq•£µÀæUæ'Eu%ÓäHåI@ƒËž_žxkÝìjò7õôr‰|“÷¯h°HVl±µ¨ÓÁ²FšEàþÂ-2JŽ8Ï2ápₜvvÀ´ì¯ „rÍ Î|Ÿ׊ÐìvfX9¿SÓZ¸;˜´g+<Ù Rð¾S¯EVðÉ y´NÌ«UÕÙËV­ÛLHGÿu­9b¬±ËK¨æ1ƒ´%ÖgU¤w*ÅH‰»À)ÜUÂ…YûÉzÂ?N×$XË"Õ×NB|à #Þ²/…"ç÷F•0—ÃxòH¤ #*ÁE&¹Nvj³Hc~W@VÈ™k”_G¸jA&l­IFÈ’E®U„,6A΢½XiGfá`UühØ4)TÝâÖ’=0[ßæ5`ˆßÔÜ‘Ó`*r¢¾œ±ðOGž(Ò™,¨”'p¶#Xzµ[ଂlîJ2Ýhl!Ù!9pu؆ÝoµîK %lòÞYCDõóÉ 8 ÀI’¤‡rš—êé?Ëqïè]ç¨/5“ݯP0(Þšã'ÌOŒ—>‡1bRÜiòá¾îùÏ-41µz´æ¹š ÕÅ(‚–;.vbY‡GŠþëR˜€A<$ÍdáÔ=ÕÙk ŽÄ¥õrOL½³êµm•€ZÙæˆñ ¦dFÎ+uµõ ·9¯¹ŸÔ£ë…![zå ›jç;]‰¤t]ÍÚ^Í/¸w3ós  nôC Ð8K @P/Ùøvb>LÌwAU§ AÈó¼ÊÈAš&d8šÛŠcÚ5Ým¹éž?©1 ¨Þ‚dýiÓ®§fëD\Âá¦ÞÝòœ%ºŒi¹ ¦ä|¿ ±ØŸDlæ5½q¹øÞKD:еçPºK@Ò ˆ\5rê¶'mJp '2‡±•š|UÜ÷–“b£`kÑsä&’‘Ñ 6[‹ˆ^{ÈÍÚTiÅ;Ïf.—kè¾xÛŽ[SU∶7Ò†œŠ§®¹}U]D|®‚Œ\ð©±Õg}‘î¦e?Í;¯ Ö'ß»^®×öuï…÷êÂSñ÷§E'¦ÎeÙAcÜ’ßöóHêŸù vúº½¢f~…XÔÓz¡3¨xŒªn@X‘oÚ¿Pý9‹qžzó‡ÇF#ùJ=~1c¥ðbd™RO{±c5ÙñäaªRmPOe’ÌËÚYFDÑ™³›Çã {SŸ²EG 7Õ¸ÀŠ«Ä`¢¹æ]_ÅùJÙ].[ÂToìmt{Ñÿõ²rTû£º:9ž®\žŒéHl> Âçd7¡t‡¢='bzûÔ©H¾'Ê+mè)!Üïç^ ƒ‚Àq±0ñ½@(nu4Ä‚<Ê÷ù©,ë~¨&T*™ÿBíO8oठX+ ¾z®ŸrâÌŽM‹'_ÙÚ믉Î.õ—Û}ÖmûH|+Œ­t „p˜¥Avéð‘ˆÚT$ ´Ío_Ÿ_Ôܽ<9Ÿ'öm” ¿÷Æþ5{q¾æ“ýw Ü¡‡›ÜÜꎾ ¾´åaÃ…dûÓ¥jÓ [„îH:Pü ȶs½ kÖDÆi€A Ñ5"À~+P'›<Ô€ n’Ô ³hËV I#­O4¹wp7û^$Æ4Ýl ŠŒ\"ü.ÊäçfªHFým%@å<ÞqQœh± N©-¦AüÇ,2‚–? fgVUiŒÜcVé«Cz@Às戕ƒ­¨NñQõz¢éê«¶jžîXq,qÙ)5:þÈ\V®ßª.ú A¢î$7Y§6B¢K¤ùR׺ð<?9õÒ 7ãásÊ6€(˹;œãŽ}j?]‡•£xDÝ”r6€À…ü"1f› .ªóÒ  LW¯Ñ_\~[aFÙ‰°0ªÞ± 7{bP¢ºt -{'ºŽ#FgÐâô“„óX#,dʵ²õK¦5ýè*rßa«Õo³zäôÛÝ<Žê­ì„ ÌÆñ[õΰ¨èaªŠŠcÃÎè.Ë`rÙòôQ~­_Ò݄̿Eû1QßvÿL'Ä®@þ2¶¡u]é’å:uÀˆÊ±Z¸Ÿß£wœ^'¨b*ìþ4RCå¥YÕõ*÷oÄT¥¸Ñ9 ö³ÎD>Ø/í¦ºçïmžài¨]FÕbä¹Ww8„ð¶I¬=Òï€8ã‰Ön°Èê7îÒbÜ Ò“Ÿ4“é¸'NžK»ŽNA{±<¬›¦¼e媬œsåÕŽ¸x£^E> ÌáÅq…¯?™(â!\¡‹ÙŽ‘»|æñ×À’ &]ðCÂÇØ|«×&ÇuT¯ÕªÄ>o‚üÍŒœ†»Fz" Ì®ànKöMl÷:œ­éFô[„¦ÓÊ«B‰ÍXgEïo¶î*‰U“ež0­ZB=Û?(™]ÿ+7MLåX° =\~•êU[‹(-1¹sçÔÚIü„ÂÑM”_›Ž¨Î(Õ¹ÊÑèB§0£`]ê ƒw2ÙÍ«Q¾®9~ñÙçêÕV°AE}œCšê3±Í˜ßFÉ£ž¥Áö"LCÚ,j‚-mÿÅðÇf\v­Š?Pu &/Ò xD´—£Ý25²þ²I¾¬Crü‡ªÛ|ʧ£T”€œÉŒbãÌ&œzO7 ÎÑèïZq+‡õ&º¯ÑZ' ˜@"mdÓÁÂ8l‹„˜ö/WÕÁáKR¥Ž[̨ãð{ÅÕÇ—M\.!=ª‡V¢Qh‰pŠ1,‰ŠÓH6!P’èžÁ G>È£ß]ZçVʱÁk«ƒŽÊ¤,ˆ?9ÆÐäu㘅=rñ¶óÜ:„â–î˜WžÎ­?|E6€­Ípþ‚ê:teD¨ñJŒ_ÇÁ&éî…’>Љ ®ëÿœŠæÊ¯Õä,Ö¨¢¾1¶˜bÜŽþ»5¬ y…¼Ziqjjí J<n- ¸ËObÐb§kîQX'N@ʱL@š÷W¨b¦{Ë`yð» 5¿Û@øœËî*ªƒzB5>²8ñèì¨Ò&Öw¨ÀÞ»Õˆtà¯;'uêR›œ´ÐÄ-`–³N¥á¢>P6”TñF RMP—7‘“ã=¤ÔÐÀK‚Öz{DykNר 8uOÀ6NB_MÌ®r¸U6?g8¿ÉÜÆõ8ÖmÙÜÁ _· &MHÀPqøÑ½ZŠà“þ–ìæ†roA ´kþáë%·þ½ÈI„à H)™t0w9÷Q°Tî]ÃåÁ¶gVúõ ’H~`'ê½…!ósÐí܆«bä|8—²!H§[wÚ¿j½}¡ÎeI"î›þ¯â¾gÓr€}T5ÑW"y̱;Lšl$%Ô3ØpÒ»2ƒBýX¼«Jzý—§Âl‹ËËØÎXâo’m½È¸J¢ŽÀéãTÍhZu-?]y´¾wñirOÂà'ÒËlìèµ³/01Òb§´¬G9}ð«¦öTDÒîy]„Å0U€Š‡žB©nëËÏéîGpwøºœÎM0ÿ€a0“Ù•2|êȤÔYP½<:–çz‚NàT–ŽãøR˜% 7)â©zPŸ‘›9°Õú¸HYÌÚñ§K‹®î`„v·@úÈ®M/Ý8ƒaˆ¡1X#VƒkU<"p·³}ó¸ ô˜£?e2œ£ ÚÝÛG€ªê“Ýæ/H"~õš£B—ô²A)\xÒ~G!Gúr¸àQ2VŽÃ¬~¦v [ätÒˆ6ë%‰¨_¼÷WìºÏ}ß”} Ú›UóE÷vmkqÜ¿MWq ˜ÅNκCO:nvüWÅõ:.&µw7Ý຅gê‘ËGNt‡Ð8nK9tEú쥒Oé²A€¸KÿI×bqSަˆ@$ô—Ú츴åñ°kAu\OÎÀ0 òÆï©¶;0R§„ *"mø yÔaR 5öÈ_ðÁ>–&t9}Î rfðúÇå)º>B¸ð¹ÔpßFŠÑ¨Hõ爵öX%švFm ’Ëêuòãh©ÄúCM9`V¼r߉k˜²1 Beƒ?{ØÖÖ|wFl7´rÇ0Šî•Ó*'×Û} „‡MüöuZD¡Z·ÑK¶B°ü.²ôÖ4ï´)”.h˜„°âÜËøl[øLŒ€#" ƒTâÂèR()lÓàæ»á6ŒrÌ®F–‰°n…kØáµª÷_}D‹"Z»¾WY!¶©í%b÷¼ªrT3% íhvůDïæßÔVX,Ü¢[šþG(Û~ü²¯-L YÐòȞݪê–\/Ù5ŒÛWGhTM,¼¹Ói«¡¬Ì™SkÄë»ä½÷Ô"C¢=É¡ JêjȎ骦éîY^"ê»™0±».]â\Û)m§ŽŽ>ÞŽ¨&]ÇhPÙ˜ž3+(_Yh¨¾uþ §k][¹p/¶úŽÁìî†uâwg#xæê! óË7©CWM#-¦«Â’QTv6ø›_UnlÆÕ‡i±9€.º@‡6n&3”²å>œÖûÄŠàÅÜïêµß#Ñ}ÝZÓUó¤¼Q$8ïÞ*dì"U·®±H7êâ Ç,­ï” ]$Ä–´­;(Ù¯¡¬F<©~oãSAÑlë×|M VÆÉýv ‚·4å\™À"™C¿ú9±ù># »ö"®sGØòå®÷•³Â_páÄH¯ü¨®oÇIÕÏu]*N¾§‡ûÈÓJÉåu"<¸¹á`/RG0.$-ëQ\=‡¨Þ ì¥3sé"½-Á]¡æe&ìO9Ò„°(äk£ËjóN/Ý‚éÇßÎð`Ògl :ÙªO›÷šèÕ\¹(;NØH(þ™|gW7y$p—r8©Al)²ó"a=£_ë•ø ¨Ü[Òj?ä,8‰ ÉÚtLj…Ò¸#~‡‘=J4~Þ•ã«R 0ÉkÛjçµÎ[ãt|ÐØˆºÓyÍwR©và ÛR’¸bu ×@”Ú¦9ªà Óþղ߯ÜVf)¹9`Ö=`O½Yœz$ö@ƒÂ´hh3k³ìå«7b7±ŒƒÉë mņûv‚Юę¾m”$®™â)›ø FfŸÍŽã‰§Ì˜éÛ¹vÒ[ä £]¬üS˜Y¥%R#b®]pv•"¦h$+ JËÙí‰O¿ìÏë\Ë6¤ì4@ûà[[Eædè nÚ¾÷#°c[Òw[‘Çëùøøÿ9͈'^-$µ‚$V¢®LP‚üoµø×º1XºNÏ’NåË „õN¨ÀQKt â‹º¯OˆõÈ zu(ø ·‘³ßEJ‰}D)ãZMnßXƒ°³xë‘=èi}¿Ä‹ÆA²lLªŠªïy«“Ç€àÅ$sØúMø¾šÂ-„Eut•D"t}vk…ô®‰ì"L”,ÅîàÏà›}@µ˜¨ïmÕ¢*(êe½ÛÙ–„=r[n|>!Ñ$mˆµ ™>ƒãÀFòlÎ)=2×ÛrEwƒ¨fù¶QKÛe«ypëß`G@„|ùad$}—@7ÿ*ê t™ˆœk°Jvfœûnƒ+ è¤éêØAbà3á ^è8û«ºÞÅo"@ 8bo<¶®+[á:<:ï¨@ˆHÓN äŽÇ Üží çcÇÝ+± 7O†~¹Ð[¢^x„U@dÍìônW·÷TÕ¥–/MÙ6j Î@n4 yne-¯¬zIx,“ÅUÁ"ãà(2pJŽ@m—«ðâ%öS¹ƒãÜa,eМlg-€rPµ3ôNÙý+å(iZÂÛb ½ºla£¡pK;³£}á ,÷Æ­UÜ„‰üñ>ëK%*×»ý•§™æ{#ÕøGª[Wøx ‰sÍŠ*¹È9|ðÄà Ž{zF¤)×ï°X‘Q‚¶hølÝÞŠâô iÄqW.*\ô"D@j8”Ž=¦úI]þ ™Ó´ÃZÙ[[Ä‹1Cö¾(á$£J²TƤhI®Œè'0öÉ»hÊúð—,r#¾r+$)Ð%W=,ÉP}£ÖF @y:@>Üh©•åqGQݵŠO ”Ài¡0lCwS[±ÒóT町²q¯±Oû+ƒæpeµƒïúâ¹µìaøª¼Í d†-]uïäY.ävrFjFýôúy×®ÚüX{ž Cç‘qóvö¬ZûäÅ7oÃpÏ4‘=”›;ë« ºÀƒL](C‘§Ú“‘Цú?±P¥*§6plÒ €Ç&$˜7ë?m¦ªû;à·^zWz=¹aÑþ±u®ˆvW/z—p%ƈ‹yòÎàêÍŽb¬»[ÌKp6Îe.m¤gÝágc¨™C;s"Aä`ÖY/錅KËï[mdŸùy`„ˆVÖão>¿UG¾.DVŒã‡ª·³á·íØwµXè]è9ñ맺µbiJPwª*)©êû¥ä½ìÍzÒ¾F‚Á®)¦Û—rd|æþ™±ë’ürqÜŠú2íb¥ŽJ Rk¤ª$ŸðÕGP® #m³ˆžÛÂ}ÓrÒpa9£^§Þ¯v¥aâ_ Ã ¬º 71~™\˜/?Hi¡~¶—¤èsØxCÓQÂ`r8o<•¤D–5Sâ`’”¢ñÖuIA|€¸ èµk[•žD '¾‡K<âÙK Ù¾‹Ã‘Je‰”X²Q=ˆãN ªÒ¯–­~(_©*¨›y®ñ¼¿G~̬0£ !ˆí;Õ€ ‘{L”ŒåYa²à¬%Ô¸–Nõ^¼¼ŒÖPôþ+”u)7ùÖCHÆÈ8ÒmºE˜§Ò>¡îçsl¿“àS=!V¹„÷Ûögºt¥¸£Ÿ~«2©Ü´×}'DZu}·b}Ë­=¼XçÏnr’9báÕ6åoè·ð˜‰ ÉnιeÙp@[åÕ캡ÁBi¶#å<á`÷¾!‰Ö6™44"§³ àö739 Îhëñ¸§ÄFvà ³‡‹GW9ü1ò17íÌKï!\çUëRЫ@ýª+/!&6V|”âZ—X÷õ–¢f"}÷[§^FaT«Ì 6sàBŽûÉoׇ!±ÜÑÙ¼ªSáêèî1sªÔ^ýä ÉòEÏÛsÖ]á²N“2DLC!§€Eµ³$H8´>6ØŽ®ã`Ök» h@ÜÌœ'kі̓ԫú=“®%vmýÞ–Q §ô%7ìSñp‹ŠÄ“=èPÞ7Æ)û”3Õn’[‡Ý×üa[œjHïe¹e%é,N!FE-Þ=ÓR[4cGÊœÄ"Ö_ óMÉÙ:‹À †LN=÷+âàm~µá¬Ò‹Â5à[Ï-­óÔVæV†çܵrïݱٺRµŸ±}wg@ã¤#b}.âð]û–íàRZ€RBAtªA[ZÀZ(5‹ÅnýµO£±‡}®j…Í¡:fÁ5J˜®yY0nûó%=×—>÷¡Ú{«B$ÜÌ™'NSUˆ/]ói@‹»Ž€@¬í>#‡WÊYŽº²P–KPÏýË@ZTãZªuçÊÌdK®.FùE‹šVêgAK([“EÌl‰TƒtZÔ¶ ŸÙ–Ìœ3‘ös$Þ{D‡qðpuQ‡ÁF$|›>Œ¹':!@‰{çׂŠðYß‘®—ìÄný'¥ÂÅÓÂæ¤vƒu ŽŒ08;øàÇ[ƒ—0Q½ZËõѱbb7nŠChåv?«ÆÁá»Ö­Ð™îdÐxµªdÌà´!¿[c§}°W9‘C^É8ýü"n¡ÞU瀕|¾u€÷pcä«ÅÓ‘&äê…aîš,ZFáL´g¯¥™j@¸¤B¾žî"–óuÌÞL±ï)ëÂlżƒCg2jð3² (BGQŵ-%p¿(2‚„¤ ‡!ˆª“¼°uúϹ¤ªÎž€„´(Ÿ$6_–åÄ:Or²/H 6~qôQY¹¸FÙa×wD뺩¬Ižö5¼«]‰Œ2­ž°¨+ò[æW‚áöq$g@¢`á“|_½C›lÄÍšEþò.¡p€éêÃG ’íÍæÒV ÔÂùéÖ«´åÎ'2ïE¯‘¿µÇ>“¯[‚Xæh×\MÕ{ÎŽŸ!"+¿{Ý^9cÍ3Ü`6]9ÄR_üC޶²Ú*‚|«yÍêÂfˆ" Éÿ\‹ó›€î´63 ÊÜ8{•¬ÕÀ“j"4ë!…]úv…PeQÁDhh¿Ÿkñ…av¤ƒäíºg¶ ‰€ƒÛºfËnÀôÏò À–Š£E¾úp«èXƒ7rƒD oÀ\§ÖY_ÜÕJÏêÌÃHEœôúž ‡˜\/Ù&ݸOy!];\e‡óÔWú¦ìÊò)·oU8Œ`àku}©»•dTLmtõª×#3¨n¥qZ€hQ=.Ä@ÙZ±u2êlŸJ Ï ×>˜ü#Mr‘ƒ@vð‡kK¹ìÖ\£s×:ˆãŒ©o¡cÂÞî9æÚc¥0´,"ûà°P,ÉÝ´•Nw0$ü ‚gkXS:<’‘‚,´N`Lû–Å£º¼x!V*¯¢1ÓÒlHHuí‡hFz9¨8§ØKÏ Ø÷ÕYè½7i7™&À\ˆÛñz=ÊéM‚ª‹û1DŸ†Òo ¨ñ\‹]qÎqxqµM H )í‘^ m\ÇÂ}½4jÓÁ×.g§¿û~Ș)"¼.;w&¡~a…—áš_‡ò<0$·:M&©‹ÂÇPpìà´Ó$jŸ3âÕ`˜ÃmGLÔãòhä>ý€ M{ÁŽãÿ2-u¯•tƒtÞpðÁðªœí±ÒƒUSvj@ Ò¢—Q· b,ôy”ÑJÞ0ò*zj¨pH5PQnµ Þà5‹ß&h$Ïå9¶iz»Ÿœl°ï8½‹Ï§ˆ–a±îQ+-Êý…âÝÛƒÇÔF6Ž·gêÜÉc ©¢!ú»Ù"¨«[ª¯<½D$&'²KAõtV¡ë$GZCÜ:öäg<äs†K[¯c9¢•"˜1k åÿ×T6QÛ¡ß+’í+õ„`¶å²ÕwxZTÝ2H åýP×µ ók|üQÈ¿NtsŸM&\Ï»hoµKZžãªÓáOö¾áð,ÜR½ÀÄ^2%8÷ãöˆÝV@Ù¸d¯\«–‹4œ¶à@Ùl­Ê#²VKÕž©ÛÉ‚¯Ô3Ø7Ü´ °¬>¬¤5˜…þ¸fTep*±>w¥í >~G¨7ÁíS5ª¨Ô‘:Yc¬ß«Ì¨FþºþO‡ÈW(!Ë]€¢¿ÁÜ)h±Ð>&0rwÐÈã£Øfi¶}<˜Ýš‘.)³–~Á5g`ÊŒW9ž‡OÓ›`…§øÌ#»r_9ÕGºÏžÒÒ5iÒY¼ Ö¯Ë\­»R®!~ÁP#9ŽÎ!:q©²¯­œõ@’GÖìúªt[¨‘¶ß‚t xAŽkƒ©3¾{ÚÊ3ïàßçø®DŸò¹¨«#@’7'§Cü¤R ¯4 2&ä`¤55 .OÈû—ëvŸ÷~’‹#ËA êSŸ«[¯×%c‹vøphÎBYIw«×‰Þš†¥%2-á@îöóby·9”ŽÀ•ÕàØ¦Šõ‘Ãñ¸¸9SZi§FAØ ô¶*¾ñ¾Íe^|ÿ;úë†à7Õõ|EÕÿuÈA? ã¡°CÀÚÑñEC 7·­´fnØìÚE«°Åº™3 ½Dë›YÕÝ”†#åÍš h¤ÀÍïäTrõ‚ˆìÞ;/ýUNB,A7Y·CÉv ¯3ò„|å %È©¬@Å9i©[La[L»jŠ êzá yv¹¢q-H¦ªÃÆ‘ZæÉÆG°Ó~mƧþŽÊÇŽËçÀé©êïi¹ ›\Ö"|ÈõÅ\HšÎ™Œ-·‹µÑÉs³8¹ñôc˃EÌr"c¯œM¡½˜(ÝíÚgƒ>d:¤ +ãvK˜GÆ>[ÇcI—ô}XoAèL'=‰@]j{D:6hÝt Á”øäƒñ bêÞ 9 ²”sTP¼úu›Ñ#™˜gű§YäúZ©ëYý8D•Ú¹ ±:P2“–Õ—5ŠÑA8í×ðç¸z+Z+râ+‡_ìV)È[Ýdåàˆ!–(?fäbˆ‹¬PêàÆš&pá:×rV¯˜ývj8Ø$,ÁIvb&»Ó|ü ;+£ͬI½£_ìNë›Ìbøªf÷З59÷nH_Œõ€Ìb‰V»TÙf l<}ê¤ U­*2´‡eÛG@îìž+€Í^ 3ï‰Q«”U¯Ôå¥$?Ç:"ׇh}ñ„kÀ[ydºkV§óÑHp—‰4% å…i™ê8Ú':£hýâCÂÄRAÌ„°*k«Î?ÍSòÌ“£2#[„;Qs \~dž<„˜‘÷­•%g"€…Ê9îÅ€0dN¤“ÐÆÌ56öŶ'o®_;³Tm7g.ž°á…k’ìÁCDû"Õ¤ÅNõnÔŠ>æm¯Y#׋IWWŠÀ‘žhÆ6Ž ì97Ùª þB˜²õµÅSe¬\׿¥=O!‹ˆfç‡\¢:Òs+y„ xFkÝô¾'ó¾e×A-X\«á ên ±H`u­¸Ìc"Ðàæ†éÚ/mVd0ìuÀfŒ ±ø>‹‹/-\{b´ȉøF2+‡ƒôk;Êýj×ÃIѹ‰rœy ¾sˆÀÁªˆñâœÂS%•Ë—Ã2 SdÀZGn«l~˜pê»2qöYÝ*åAŹÆî]Žy…žt¨Ú±‡,ç5h‡ ¤ÜOKÛÉÑ<:¹c~î×âoU?¦h†ôh¾¶F1ƒ¬n ]ƒü@‹››¥“m 3—?-L¾%!WBÂÊû|påFž-î)Å §ðáê'ýß‹èM™ÎÍù[1ßq)r™Vt/Âëµb>J¬Uaèõ]Û³v€hDwUq‚ÕÜ‹ðlD· Á#ìñW6-ƒ«Ÿ*AuUqåëm:äa 2w?XŒBô»ôMU;Œ’“,­³ô+ŠðóÉ”V3kJJ‘ºY³íDöam31uÀi3OQHQ"`R¸ö[|† Þiùà 8OåTYÕ/arÎñx-ÀrãlEy=¼CîÆš’ÙÌ)­¦ß^R~ÄØ¶¢K–×IÈeà‡Sµ¥-€´ ]Å"þÎqá{NÚv¬×Ÿ¯vð,h¡¼—~BÝ­Á/Îpy¦€‰Û‘”ÍBÂUwH/þZ®š·5Rz®o¿]'•#Ú{!ý6¿Y÷ÞÈ{ó5°±ynaà7/[?9„µ °à¯Ðñ…‘]¼éõ‡õ‡V†‚›ÇM×t7 ‚D¼Ä¨YÐ,o; “é¶Ä„|ð(8çz†N·LàÉbF¦RØUß‹ÁÏ} B×!;€z0£=“Ùr\Åë>Ì´ì?f-vÿˆ*2;<[àÆÙiD:1£_(&|0übŒ‘—\+-àC[¹zÃ|f%Êf­\ZûÎèŒ-äŒ!~C|'5‰A0HZ¡Ñ±è/ÊÎ18ɇxXÒ·õï 4`dNŒ;X^êh‚¶ê‡1kÁO°;íæÀk°¹ŸFLÀübÕMÝb² I(¹]÷l‹Ç˜¾Åc4»·š§=¢d“«çµëB/¸nÒs6Þ"…îšãN\dëYu§fˆ‡ÂîïtóP…+§—¯ËàH¼á¥L4¼èoùçôÓ§T_XžðQÎB`­ÓÓz<ÉE´QÂñ·H{¹Ëj¢f›Ï·aÉä„(IÚ8=ŒÚfÚpdR6wy콩¶\%ËèF>c9 ?€É‡nvŽºí0]h)xÿrÅ*G”ûÆ®œÉEUmªB%Zkż–g± ,ü,·Êpu@*ÛuŒzTÔé°ÓÄÎ5"Š¡aUøP^ÁeÍ-lu¿õ‹ª%äU;DqåÄsÉà¸zpöÉÙ~kî 9Í¡Ü[¸mÀC§MwÑ·•ѸýáTF`Ž¢¼‰Þ™+‘×öj_ªËwˆ p€foÚë[l Ùen¿"yxÆ(Ï ! PÛˆLÙ5b-UÓñôbF85eÝb@©sR¤$¼ÿh]ËɤƒêTäEA?©D{-º;»K¥Õj,äJ™*ÌÌP–y~‰è_¶ïD¯¤z|Ö˜£Iâ÷Oœq°jUZodœN±2 — ˆdgñ6ä¦N‡°Þ˜×êÿ3´²Ž ³‡5û~Fqºt¡©3ôÝÖà‰.mÁI¢±›G˜D*„;{½ß­#å¢ÍŠòT¼;[ä‰ÄЧåÊ´Øßmaõ箬Gæèm`ïü[¬kjÖþ!ONCÈSYáÏ}'2ÎEâ\®ùä`7xý•œ+\AbJŽH‡”<À )ܱ¿’G.hL%"Ž+K<–ºWYÁ¢ñg$fëò(1ðˆâÙ÷Ëq{ARnu‹O%V¤7+ˆü¢Ì–×t×Ví¦J6y ,§]H5~ÊûV€†‹šŒØD²!ä2b»7º_)Þ@×ve^à– ¦ÖhoÝ|ÑL=B<¼«|ì‘ÿƒºÖöÌj¸¹a:A<ë²x<¶ ¹ǘMäR‰×Ä `8°Z»àƒDþÉI;zM(ÒFCsCÏÚ8ŽãSOÖ‰dœ³ÕÝ´(7³H5‡+1ò4\V¿ó àþ«¬ªp\^Eq7Â6`°ÒfÛ^tþ!ñVêøü™ƒNÁíBkõ†ÅØMÏù±áz s`I:—r L/‹$âÝ•=’ò-‰`kx•@#¾­FÕ0S(ãäÄÒ WwÃéÙïá ùøXïõqáæìêæžØxé¢k7r}¯=y"#ÙWn·Ñ˜×Oƒ©n€„ˆ uV¹)⌑L4sX7öÝ{/ôðkÌ ß>§SBØ=óž8ô—ÝhZ(åÐ#ÿ\Ô!¨ª ´p8 À8ˆÜN"d 38OàÃýlS¹É {×B´W \ÂÑŠóò+¡%@­:Àµ\ÎwW\e´ÁO>Rñ Sek83°šr¿¦[éÛ[ÄÃõ]6õñë`¯™eËÁƒ^ï*“µë¥„ÀºåPal4s¤…íH‚ aÉîKlšã2AŠ™ãÄ4ó°x„íiB‹HQñ˜Ik/eÿ²ýÖß!‘Uå4‚æH±Ž¯ØÒ(€;Æm¨Æ©„Ëqa¶D@hWÎÒáp ã°UœÛÑ0dg S™É·:èWÓ€#´ >äœ ]µ^U(6IÍ©¬Ò]»2û`å÷i]jÉGn-¡;¾ì|(¢z{?²A´~²yÊélrAfq:·ûë7¶‚'¼Ú&Ü|‘÷ªk&3¤Þ&Ðû34ö…¾Ñ¨xävò"1jç£Ug\i¯e‘[œŠÔÐÌŒéWJìEì»òü°†!ÓÕºNë8peóPÂFîé‚Ô Öª“Ë¢¦°è[7ê!M®kìR ylH_DüŠl}öõhwÁ¬›ò$DeÙ›˜‘'ñ[ok›ë°ÎÂBêÄrB :\8°¦œfå¦ÞFp*Zù½üú †¢TQ$®Žì•ë‚‘‰^gOV’¸EÆ‘îÛõ¶7šTRA»-×Ûq¿€èÅñ¥*‚ž‡›¸Om=NiýR”<0^9GNç8°D‘pä§¹`:HnÜu†« ¶x@P|ÆÕ2˜¿ÑÅIG]så" òtxÝr˜©ìà™)éð°žöÃÀ¯^ŸQ8Jg¸óv÷»û}þÑ;W©j#à4?½¦áá2„_ÇEG"»[lÏ üGúz/ÐÃŽê×4æý±(u†­“ñ„s÷Ž×9w(aÅïùèGµn©§*›1ϯ»Ñðè :Ü,9¸m¿…¤·±1ÚšÝûaÆÆ(׫t43ÏýÀ+ñÛXdm¤‘ÙbkÍwáf¬{}?x‹õ©’äc©dNÛ~\Nàtl•ò Â/ž°_ôÝ[÷nPV·`SDJA`†x IÈè2ìò½Aä6Ÿ„±ª†Âx°œõï†|R" hïÌ£ˆ€“;Ãåz"`ãï&fLšF”÷ˆSW7G֦džŒ‹Ž¹£”ñŸ±ÞMˆÀÑùÚ~œ&È·céø D#B \wgˆ€*†uÝ` ³$`ôÚ24B-£’@²¾•.Ä…"’@é‹×UL5¹ÿ¾û‡bëɈ¹Â­TµŽxIAô’B¬ÐÕÜV6C‚he„ €]8G6}#ØŒ°+ƒð9Ww;O}¹õRChý KJ:ITà㫎7"ÐÅ1KÜóP˘áz¥OEG6q?öœÝŒµ>/ úª‹ò`ë˜pß}÷­]ØG›/¯…8š7$è;ÔAI›¯(ò{š8KGd×%AªóxDv‡¨cdžËßôë:!Ws#•ç8Ò”¥ãKÙv‰ 'Àfhi3" ŸÝ½95*¸µÛJ& }hôÜ䤗j@ÌyÂC=ó%˜_ôý A~€t"Pûï8}Pšî€ƒý}|ægü^<ïù/Àáê·>뙀g=ëÙxÆ-·"g On{ö³A‰ðÙŸó¹¸õÖgáâŰZe|Ögý~Üté&pθíÙÏÆç~ÞàÜù ±ÇGIk.Q=YYËCô½žˆ€H9ÇQy6Ÿõ;ŸÀøø Û×&é®ueÀö#Á†D ɘ˜.o»EŒ51ßìÕ¸çl¨—†J›©~—íÀ{î¹§ì(Ô"눻Ä4<Žuêvô#We+‹®DKrÎø“òËð«¿òV<ãæ›ñ’—¼/ùgàé7ߌ—}ò'ãå/ÿ ìíÃ¥K7áÅ/~1¾âÏ¿ÿú_ý >ïü<ç9ÏÅ—|É—âßýÜ¿ÆüƒÜw¾ú/} ~ê§Þ€/ýÒ?…ÃÃUlu 0šÇ\WD ræÍZïÎg\d·Xk#<ò(V«FüØ’‡XI'$ã1sSvz!û±ûQ|ì‹>¿ýÛoÇ{Þýnü»Ÿû7˜&Æ/ýÒ/bµZá]ïz'ÞùÎwàܹsøÞ×|'n~úÍxûoý&®\¾ŒùÇ?ˆOùÔOÅÞî..œ¿ˆýÆŸÅb¹ÄÏþÌOcggg0±^ŠBGÐý<–Åÿø£iÚöæê^ŸŒøñ§ONŰZ­¼tÓÍ88Ø¿I`ÅÛ½Ó÷¼†(w7d6C i“Þ¨j€Ôá·Ur ÜÿýÕ5¸ïqäô½VÿX¥†D HC{{çðë¿ñk¸ç£÷ -|ðA€3î¿ÿ~¼øÅ—¼ä%xë[Þ 0ð±÷b<ã–[Þûžwc¹³ƒ·¾õ-xï{ß‹ÅrY`@„ûï» ‘LDÀÃu¦ÇËAŽCŽv”ºln×#Õ<·—ÛT8"À̸zõ n¿ãy8<<|àȆ›tlpxxøÓ/}Ù§óßÿ^½·oÔ×y"0ùe2T7Ç5Â¯Ä DEô°·m[„  ;.HHp„!áÁ ;sD@»ÆoHö“®,ú÷C"`ÄPDr°HDx÷»ßŸû¹ƒÝ½=€xÿûñßô&¼å-oÆr¹ì+Ñ“£Â¦ÃïÑ|ÍU·ŽC6kûº®Å[°O?8Î=qdf<øÀ}ø”OV«Õ¿Ø°²PëÆéËþÜW#gܼX¤{õÍÿûíÿn¿ãùØ;¾°Û*é†8ØFé÷­y\fƒ`”{„ûËÁžTwRqîïùƒ?á{9À>øÁöÐᙳ¿ÎJãcí¶sÇÕ7ñ“> ‹´†³3– ïý÷ݰI}oÿíwÞð»?á%¸õ–g®ÕM§œñ“?ùg=ü§|º\¼ `›ž éùÏ{.Òb½h¿·»‡+W®nTßáÁ!î¸ãÙ¸xÃùµùNrúl›žXiKžéiO{ÚzÀÀ¥›.á®»7SsθpñLÓ´Ö²°%×Ú€'AZ,—X,kó<톧á7ßþÞê{à¡qû³oÆrggm¾‰Ž…v›žXéØŽ@ÛôÄK”ÒÚÿ ÂÅnÀ~êg6ªï'ÿå±ÜY¿ˆ£êÞ¦ë:m%€'AJ”°n{Á¸áâELÓôÅ_øÇþÔ'Ð0gr¾W¯î¿h¹XÚè¹ziëÌq½§-x¤âá¸Yï»ï~þ—?þ£_½Z­0MVÓ„ôáоkðŠæKÑúz·èý§-x¤iÊÄß›K'Gãí.ÀõŸ¶àI¦él¬ñgÕî6=viKžiuMÀÉÓ´•®û´%O‚4MyÃ@“m:Išmzb¥-x’¤íiÌm:IÚ€'AJ©\pzÚ‰yKt®÷´%O‚tóÓoBJ©Øós¶mAEyøŽ#£ Ûuk)\½fqikx¤- ¿ÎÓ½þõÏùØ}Üûî~½Ù%À×°cBÂû#>‡6~éÿÃm¯þ–¿õ‘³†Ã6,m%€ë<ÝtÓÍw®&°Ä„g..º\/¡ gvœŸ|EfˆÏሠYxÑÇ}ìól Àuš¶à:OËåÎËV«¹rêF8WÎ GjÑ‚ïE`Çé.WL;=9ÏêúDÀÞÞÞïðÖ³†Ã6,m Àužrη¯V«z/—ðä^ìŸU Jf®ôÂ5×wõûŒ¢Xbýã¹g ƒm:yÚ€ë<1óËWõÒN ›ìJjÏáÙ‰özCWÉÁ‰ÿ%Ì}??ã.\Ÿ¾ô¬a°M'O[p§i5ÝÂës¹LƒÉ¸»½ò÷Jy._Žör{7A­kÍ!LÓôœ³†Á6ŠãìÊá¥Ëáàúˆ5o¹@âDäÊør½Ú%žÃÃn¼ñ¦µ}e0ÎíÃÁáa!„Gì.<Ö)sÆ;ßñŽø¯þæo<µvŸèiKšô#ÿôõÿîÒ7}+oW@áãoÔ<‘?q㮤×Ýwvûð°wöÎáù»:ö̧ℓQbΠ…t å;î•ÙÀjbäÌGÞáˆpáÂì_½ê¼N-ñ£>òæ¿øÊ/ÿÌÓlô‰ž¶ ¦oüæoÅr¹ü¤ÿ„ÿ5¢C4ó».bê‘gîžx.6Ùo¼ñ¼ûÝ¿säE `A„å΢;Ý×ô®Oë<ûÖ=9Axp°ÂjÊGÞq?M·Ýv+îàÁ*‰œöòcÜù¼âððð?¾ú›¿á”Û~b¦-péäÇ~ý†§=í¥†Ï ZëïÈÝMó§žX “ߢ‹„àŽÛoÃo½ýET>"%"ìíºÛ{føÊ/úç›%C^Ľˆ>®\½Š)­Ô/ |ÌÇ<¿ó¾÷Ÿ_¹|ù=_óÕáE§Ýð5m €¿û߃Õjõ^ð‚ü[®r<5"25œœ±”1›Ü…höå%«xßÉï§]<ûØáçÿß7áððpm¤"¹½ÝЇòµGiëwÓéPß°•5ïJzôòÕµáÁ˜‹ÅìÞò+ÿ÷Üû8ŸMC"àîÜõ%ßôõí_l£(m €¦ïû¡ýàÅóo‡SüI”zrÌAjf÷LqΞד¸m2T­r÷ÞóQ|Îçü~$Jøíw½oÿíwa¹X pno/Üì*¦jh¨#þ‘‘ˆ†t¸qwí»Ÿ?òh±4‰™±Z­ð /þ8|Ö+^ŽƒƒCüð?ù1\ºôtdæ#U†Ç#1ƒöïûº¿òª[N¿õ'^Úßúíßõgo¿ýŽ•­²YÄ :Wia€žÝ“D‘º˜±XÞó®wâ ¿ð ënpçÆú0xàA,—Kx®|þü9‡übˆ3D¦@‘ ¶ûK„Däþ Å ¨ì0ÖÏjµ' Þ(Yí Ìx𡇫Wa);M.]º·Þr ^ø¢àéO¿„§]<þáÁͷ܆ƒÃCä|¤ÍðqL„ûï»÷«¿ùÿú÷Už(i{À7^úG«ÕŠëšWd8ü]¥¦æ†UÅ5áÖHco÷>æ…/Âëÿ¯×ã¥/ýD<ïùƒ›Ÿñ <ÿùÏ3ãCú0>|×ݸóCwÁX.5XU9·o£`0R¶½ gºÐÎ;»zŒ¤<™ ”3ãêÕ}¤”ðÌgÞ‚½½s¸pñ"öWØ»xW÷÷ñëoû5¼ùÍoÆK?ñe¸²ˆÕ•«k,”§|þÂ…ïð”'Oy à[¿ý»þÆ3žqë·d©+¦{¤P»€¦ݸQÂ:wÞy£Ä $n½å\½z¿ù›ÿ÷Þs/ž÷üçã“>é“pË-ÏÀÅ‹páü9Üpñ"xàA|àƒwâ®»?ŠGy<üzä,Ò¢tA.þ¬—|Rèd }§øGßið*LSÆÓn¸.œ/0I ,–;HË%xð¡rI)1ö¯\Æ=wß…~äøå–gâ¥/})‹%Þó;ïCÎîÒ%ᡇü–Wÿ­¿ùÍgÚ‘3NOYðµýðÝï[é»ÿÁæÝ‚¶^ö¼có­z0vv¢C}£â…Ó¼–wË%ž~Ó%LSÆåËWpׇ?„}èƒ8î^ø1ƒßóÒÿϾí6ÜtÓ%¬VøÈGïÅÝwß[p±ÀÁþ~½ès…œ3˜3ò4ß§‚C'`F9ñwH ¨Ÿ)%€vwwðð£Wp°J„E*g V‡‡xôÑGpׇ>ˆûî½`Æóžÿ<ç9ÏÅM—ž†år‰|àN\Ý?0¯Ä³L\n6ú—ÿâÇw?óú¬ÃïýÎo;ãM:ëi8Óôê¿û÷¿ëÒ¥§-Ãéþy×#ûà-k^ŠÐ]…y;€|¡Tœfvvv«Õ!î¿ÿ>Üõ¡ƒ9ãÒ7ছnÂù‹7`±ÜÅ•ƒV«Œ´X”0á”s.WâÔè?Ì ÎâþËõ  *ñ$A~f0—Ûƒó´Â•Ë—ñðƒàá‡Ä•+—ÁyÂîîn}æ³pÓÓŸŽÝÝ=œ;Wþîà¾ûЂ'¨éò£—¿ÿï|Ë×ÿųîÇY¥'È4œnzåWÿUÜs÷]7¾ü3_ñàb±ÒfÈžàæÑÛc‰½&årv—‡J„s»çpþü9ìíí"-5T÷4Mxð¡q÷G?Š{>z~ø!L“ WBJ„]ììîbgwËå²ró…úçSJXM¦Õä® _aZM8<ØÇááV‡(ç"¹ª){çöpà 7â†nÀùó´nÙ‘`ÎàÌØ?<¨‡–L§8[á?&ž2ÞóîwÝrîü¹{èû^sÖÝ9õô”$ð·_ýí¯¿á†§ý)…ÖүϜA¯õ>ß0­q›0úï—'ËåÎ_À… çqþü9ìîî`µšpåÊU\¹º+W®à`U7ç «Õ ‡‡‡åÿþW‡˜ò„ýé7¿ÚcúÛAC <óî¼F2 ‚Ô"èú¤yÛ³ž/DÈ¿W®^ûžÒË9O;+ßÿ&•ÈöÔ€GjòˆÞ$ùjU9ãpU·tP.¹þ_<òÈ7½áuÿøÕgÝ•Sê“?ýêÛ~ýÎ_~ó¯Üþž÷¾?ü0¦)›(­›ÿ Ÿom}ݹß.Û ÐL›û—¦æ÷Eªêa±\FåØz/†=}af&ß¼q/s..Ä9_§F¿˜(.œ?;ž}>û³~ßýŸûÙŸuóY÷éñNO `gg÷à+þì—áÜÞÞ‘Á6·i›ñŽw¾ûêY÷ã4ÒS‚ìííÑ=ŒßyßÛqùÊóŽ'ùtªÒƒ¹3þ¤™œ:¡Ï¥N)¨¶guT“Q ®C!Ÿü±¶QlrV¡ëøÒma®ñ‰e–sS¼[3~ ¢¨y{ÿg?`x{‚ÔcÒ‰º-‡ËNåä¢{¢—ž²ÝBT^˜ñTêQÛ†I7Z{fÜzËÍxîÏÆÁáê)!?%ÀN‰h¹\€(Uý¹è¦ë§²ý§Ò~²¸û5S*•`­á²ÈˆˆÞà‰¾¯{ ­G ‰sNöD#üŽý©¯¾ .‚QŸÀ6Œ¢£"{A*vƒ !›0¢@øD­«A~°CD@ƒ´„CŽ2+aáH(Yõ"rífTïf½ñX¶H9gg OVî6(Ñ•ÀSžÎzÕžFz*€½×|ÏwÃç}þçÿLËÛ/\¼aoo¯¥Z›¨cMÉ#,9c!éùxEØzw@AÄdH¯å\YÀÕ›*ÁH±î§'Önì_”J`ír$&šZbð*pÌ’Aþèß³M×cò>TÙýö`ªÿÑyö¤NOå>ç¶ÿT†É“5uŽ–ÍóëÓqa›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›ž:éÿñÙýÄõ¸[IEND®B`‚( @ × × ÿÿþ ÿÿÿÐÌÆüÕÏÊÿÚÕÏÿÞÚÖÿãßÜÿèåáÿíêçÿðïìÿôóðÿõôðÿóïïÿîëèÿéæäÿåáÝÿàÜ×ÿÛ×ÒÿÖÒÍÿÕÒÎý}vqÉ{toþ|vpÿ}vqÿ}vqÿ~wrÿ‰‚}ÿ‚zuÿztÿwpÿ|tmÿwohÿphbÿnf`ÿogaÿogaÿogaþslf»†zŒ‡(œ—’ÿ—“ÿž™”ÿŸš•ÿ¯¬©ÿÆÄÁÿž™“ÿ£ž–ÿ¢›•ÿŸ˜‘ÿš“Œÿ¡œ–ÿ”ŠÿމƒÿމƒÿŠ„ÿ„~y!skf¯«¦±´¯«ÿµ±­ÿ»¹´ÿ¨£žÿš”þ¯«¨ÿ²¯¬ÿ´°¯ÿ¸µ²ÿ›–‘þ¥ œÿµ±­ÿ§¢œÿ§¢ÿ¥Ÿš®£ ›»µ²¾ºUÄÀ»S¾ºS½¸¶gµ±®ÀŸœ˜ÿ¡ž›ÿ¢Ÿœÿ¤¡Ÿÿ·³±Ã»¶³p½¸´P¹´°Q¹´°S³±¬ —”ÎÊʲ²·¸´°ÿº¸µÿ½»·ÿÀ½»ÿº´²ÿ¹³²ÿ¸³²ÿºµ³ÿ··¶ÿº´²¹¹´±²··¶ÿ´ÿÿÿÿÿ ÿÿÿÿÿÿÿÿþÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿ´ÿ*&#ÿ ÿÿÿÿ!$'ÿ*-1ÿ"&ÿÿÿÿÿ ÿ#ÿ&*.ÿ,14ÿ#ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿìŒ4ÿà…2ÿâ†4ÿâ†4ÿã†5ÿãˆ6ÿåŠ:ÿä‡4ÿä‡5ÿä†5ÿã†5ÿá†5ÿß„4ÿÞ„4ÿ݃4ÿ݃5ÿÝ‚7ÿÝ‚8ÿß‚8ÿß9ÿß9ÿà:ÿà;ÿß;ÿ߀9ÿÞ€:ÿÝ9ÿê‡;ÿÿÿÿÿë8ÿÖƒ4ÿ׃3ÿÙ„5ÿÛ†7ÿ܇9ÿÛ‡9ÿÚ‡9ÿÛ…4ÿ܆5ÿÜ…5ÿÚ…5ÿÙ„5ÿ؃5ÿÕ‚5ÿÔ5ÿÓ6ÿÒ7ÿÒ~7ÿÒ}8ÿÓ}9ÿÔ|;ÿÕ};ÿÕ}<ÿÖ}=ÿÕ{<ÿÔ|<ÿá„?ÿÿÿÿÿï”:ÿá8ÿÙ‡6ÿÚ‡8ÿ܈8ÿß‹;ÿÞŒ=ÿß>ÿÞ‰9ÿ܇6ÿ܈6ÿ܈7ÿ܉8ÿÞ‰8ÿ܈8ÿÛ‡8ÿÙ…8ÿØ„9ÿÖƒ:ÿÕ‚;ÿÖ;ÿÖ€=ÿ×€>ÿØ@ÿØ@ÿÙAÿØ~Bÿç‡Eÿÿÿÿÿï˜=ÿã‘;ÿå’;ÿÛ‹:ÿÜŒ<ÿß<ÿá>ÿã‘?ÿâ‘@ÿà9ÿà9ÿߌ9ÿÞŒ9ÿÜŠ9ÿÜ‹9ÿÜŠ:ÿÜŠ;ÿÜŠ;ÿÜŠ<ÿÛ‰<ÿÙ†>ÿ؆>ÿÙ„@ÿÙ„AÿÚ„BÿÛ„DÿÛ‚Eÿê‹Iÿÿÿÿÿï›@ÿä”=ÿå•>ÿæ–>ÿÝ=ÿß?ÿá“@ÿâ”Aÿä–Cÿä”?ÿä’<ÿâ’<ÿâ‘<ÿá‘<ÿá<ÿß<ÿÞŽ<ÿÜŒ<ÿÚ‹=ÿÚŠ=ÿÙŠ>ÿ؉@ÿÙˆAÿ؇BÿÙ†CÿÚ‡EÿÛ†FÿëKÿÿÿÿÿïAÿã•@ÿå—Aÿç˜Bÿæ™Bÿà”Aÿá”Cÿâ•Dÿå˜EÿåšGÿæ–?ÿæ—@ÿå–@ÿå•@ÿå–@ÿä•@ÿâ”?ÿá’?ÿß‘?ÿÞ@ÿÜŽ@ÿÛŒAÿÙŠBÿ؉DÿׇFÿ׆GÿØ…IÿçŽOÿÿÿÿÿïŸEÿã˜BÿåšCÿæšCÿèEÿäšEÿã˜Dÿã™Fÿâ™GÿæœHÿçœFÿçšAÿè›Bÿè›CÿèšCÿçšCÿæšCÿæ™Cÿä˜Bÿá•Bÿà”BÿÞ“CÿÝ‘CÿÛŽDÿÚEÿÙ‹GÿØŠIÿç’Nÿÿÿÿÿî¡HÿášDÿäœDÿæœEÿçŸFÿé HÿäœGÿåœHÿåJÿäKÿæ LÿéžDÿéCÿêŸDÿêŸEÿêžFÿéŸEÿéžFÿèEÿèžEÿå›Eÿâ˜Dÿà—Eÿß–EÿÝ“FÿÛ’GÿÚIÿè˜Nÿÿÿÿÿë¢JÿßšGÿâGÿåžGÿæ Hÿè¡Iÿè¢KÿäžJÿæ Kÿå Lÿæ¡Nÿå Lÿé Fÿë¢Gÿë¡Fÿë¢Gÿë¢Hÿê¢Hÿê¢Hÿé¡Hÿé Hÿè¡HÿåGÿâ›GÿášGÿߘHÿÜ–HÿéžMÿÿÿÿÿé¤MÿÝœHÿàIÿã Iÿä¡Jÿç£Lÿè¥Mÿç£Mÿæ¢Nÿæ£Oÿæ¤Pÿç¥Rÿå Kÿæ Hÿì¥Iÿí¦Jÿí¦Iÿí¥Jÿì¦Jÿë¦Jÿë¤Jÿê¤Kÿê¤Kÿè¢Jÿä IÿâžIÿà›Jÿì¤Nÿÿÿÿ ÿç¦OÿÜžKÿÞ Kÿà Lÿã¢Lÿæ¥Mÿç§Nÿé¨Pÿå¦Qÿç§Rÿç§Sÿè¨Tÿè¨Tÿæ£Jÿå¢Jÿé¥LÿïªLÿï«LÿîªLÿî©Lÿì©Mÿì¨Mÿì¨Mÿë¨Mÿê¦Mÿæ¤Lÿã¡Lÿñ«Pÿÿÿÿ ÿå¨RÿÚŸNÿÝ¢MÿߣNÿá¤Nÿä¦Oÿå¨QÿèªRÿç©Sÿæ©Sÿç©TÿèªVÿç«Wÿç¨Rÿæ¥Mÿä¤Mÿä¤MÿëªNÿò¯Oÿð®Nÿï¬Oÿí¬NÿìªOÿëªOÿëªOÿë©Oÿè¨Oÿõ¯Sÿÿÿÿ ÿå«UÿÚ£PÿݤPÿߦPÿà§Pÿâ§Qÿä©Rÿæ«Tÿé¬Vÿæ«Vÿç¬Wÿè­Xÿè®Yÿè®[ÿå§Pÿå§Oÿå§Oÿä§Oÿä§Pÿë­Qÿñ°Qÿï°Qÿî®Qÿí­Qÿë¬Qÿé«QÿèªQÿø¶Uÿÿÿÿ ÿæ²XÿÚ§RÿÜ©RÿÞ©Rÿà©RÿáªSÿâ¬Uÿä¬Vÿç®Wÿæ¯Xÿæ¯Yÿç¯Zÿè°\ÿè±\ÿå¬Xÿã©Rÿå©RÿåªRÿåªRÿä©SÿãªSÿê®Sÿï²Sÿî±Sÿí°Sÿë¯Sÿê®Sÿø¹Wÿÿÿÿÿê¸[ÿÛ­VÿܬVÿݬVÿÞ¬Vÿà¬Vÿá­Wÿâ®Xÿä°Zÿå±Zÿå±\ÿæ²]ÿç³^ÿç³_ÿä°`ÿã­Vÿä¬Uÿã¬Uÿã¬Uÿä¬Uÿã¬Uÿã¬Uÿã¬Uÿè°Uÿí³Vÿì²Vÿë²Vÿù¼[ÿÿÿÿ ÿì¼^ÿݰYÿܰYÿݯYÿݯXÿÞ¯Xÿß°Yÿá°Zÿâ±[ÿä²\ÿä³^ÿå³^ÿåµ`ÿå³aÿä³bÿã±`ÿâ®Xÿã®Xÿã®Xÿã®Xÿä®Xÿä®Xÿã®Xÿâ®Xÿâ­Xÿå°Xÿê³Xÿú¿]ÿÿÿÿ ÿîÂaÿÞ¶\ÿÞµ[ÿÝ´[ÿܳ[ÿܲ[ÿݲ[ÿÞ²]ÿà³]ÿâ´_ÿâ´`ÿãµaÿä¶bÿâ´cÿâ´cÿãµeÿâ±\ÿâ°Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ°Zÿß°Zÿñ¾_ÿÿÿÿ ÿÿÓjÿñÇcÿñÆcÿïÅcÿîÄcÿíÂcÿìÁdÿëÂdÿîÀeÿîÁeÿîÀfÿïÁgÿîÀgÿí¾hÿí¾hÿë¾hÿì½hÿî¼aÿï¾bÿð¾bÿñ¿bÿñ¿bÿñ¿bÿñ¿bÿñ¿bÿñ¾bÿï¾bÿþÊgÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿÿ ÿ ÿ ÿÿ !'ÿ,+1ÿ66<ÿCCGÿKLSÿUU\ÿabhÿ**0ÿÿÿÿÿÿÿÿÿÿÿ& ÿÿ²ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿ"""ÿ ÿÿÿÿÿÿÿÿÿÿÿÿ²ÿÿþþþÿÿÿÿÿø?ÿÿü?ÿÿü?ÿÿÿÿÿ(0` $Ãà ;LPOPPPPOOOOONNNNNNNNNNMH9 ÚÝÜDÕÏÊÿÚÕÎÿÝØÓÿàÜ×ÿãßÚÿæâÞÿéåâÿìéåÿïìèÿñïëÿôñîÿöôðÿ÷õñÿ÷õòÿ÷ôòÿõóðÿôñîÿðîëÿîëèÿëèäÿçäßÿåáÝÿâÝÙÿÞÚÕÿÚÕÑÿÚÖÑÿÍÌÊH„~z/xqkÿxpkÿyrlÿzrmÿzrmÿzrmÿyrmÿyrlÿvnhÿzrnÿ{smÿ{smÿzrlÿypjÿvngÿtkeÿpgaÿja\ÿjb\ÿlc]ÿlc]ÿld^ÿld^ÿld^ÿld^ÿmf_ÿˆ„ Œ†¿‰„þŠ…ÿ‘Œ†ÿ’Œ‡ÿ’‡ÿ’‡ÿŸ™”ÿ¨£Ÿÿ œ™ÿއÿ‡€ÿއÿ„|ÿ‰xÿˆzÿ†~xÿ‹…ÿ•‰ÿ…yÿƒ}wÿƒ}wÿƒ}wÿƒ}wÿƒ}wþ€zt¬|wrˆƒ š•ÿ ›–ÿ¡œ—ÿ¡œ˜ÿ£˜ÿ¥ ›ÿ©¦¢ÿÑÏÌÿØÕÒÿ²ª¤ÿ³­¨ÿµ®©ÿµ®¨ÿ²¬¥ÿ²ª£ÿ© ˜ÿ§Ÿ˜ÿ¦¡œÿž™•ÿ“‡ÿ“‡ÿ“‡ÿ“‡ÿ“ˆÿ~xr®¦žª¥¡¤¯ª¥ÿ°«§ÿ±¬¨ÿ²­©ÿ¿»·ÿ²­¨ÿ–Šÿ˜’Žÿ®«§ÿ°®ªÿ³°­ÿµ²¯ÿ¶³°ÿ¸µ²ÿ˜“Žÿ–‹ÿ«¦¡ÿÀ¼¹ÿ£œ˜ÿ£œ˜ÿ£œ˜ÿ£˜ÿŸ™•ŸŠ„¤¡› ½¸´ÿÀ¼¸ÿÁ½¹ÿ½¹ÿ½¹ÿ±¬§ÿ«¦¢ÿ¦¡žÿ˜–‘ÿœ˜“ÿ›™–ÿœš—ÿš˜ÿžœ™ÿ¦¢žþ«¦¢ÿ®©¥ÿ·³®ÿ¶±¬ÿ¶±¬ÿ¶±¬ÿ³®©ýœ—’{wsÄÀ¼Ç¿M·³°š­©¥ÿ®¬¨ÿ°¬©ÿ±®«ÿ²¯¬ÿ´±®ÿ·²°ŸÄ¿»\Á½·ºµ²$±®ªÿ´°¬ÿ¶³¯ÿ¸´²ÿº¶´ÿ»¸´ÿ°­¬°­­º¶³ÿ¹´²ÿºµ²ÿº¶³ÿ»·µÿ½¹¶ÿ¼¸¶ÿº¶´ÿ¼¸¶ÿ¼¸¶ÿº¶´ÿ¼¸µÿ¾½½ÿº¸¸ÿ¤›™Ò£›˜Îº¸¸ÿ¾½½ÿomlÿwtsÿÿÿÿ2ÿÿÿwutÿomlÿlÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿþþÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlÿ+'$ÿ)$"ÿ($!ÿ'#!ÿ&" ÿ&" ÿ&" ÿ+'%ÿ1.,ÿ731ÿ30.ÿÿ ÿ ÿÿÿÿÿÿ" ÿ963ÿ:75ÿLHFÿ,*(ÿ# ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ)$"ÿ%!ÿÿÿÿÿÿÿ!&ÿ$',ÿ,04ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿ($!ÿÿ߃0ÿ߃1ÿà„1ÿá†2ÿá†4ÿâ‡4ÿâ†5ÿä‡6ÿäˆ6ÿä‰9ÿã†4ÿã‡4ÿã†4ÿâ†4ÿâ†4ÿá†4ÿà…4ÿß„4ÿÞ„4ÿÝ„4ÿ݃4ÿÜ‚5ÿÝ‚6ÿÝ6ÿÝ7ÿÝ7ÿÝ7ÿÝ€8ÿ߀8ÿ߀9ÿà€9ÿà€9ÿ߀:ÿ߀:ÿÞ:ÿÞ:ÿÝ:ÿÜ9ÿÛ8ÿè†9ÿ ÿÿÿÿ'#!ÿÿ݆1ÿÒ2ÿÔ2ÿÖ€3ÿׂ4ÿ؃5ÿÙ„6ÿØ„7ÿØ…8ÿÙ†9ÿÚ†7ÿÚ„3ÿÚ‚3ÿÚ‚4ÿÙ‚4ÿØ‚3ÿØ3ÿÖ4ÿÕ4ÿÓ3ÿÒ3ÿÒ~4ÿÑ}5ÿÐ}5ÿÑ|6ÿÐ{6ÿÐ{7ÿÐ{7ÿÐ{8ÿÑz8ÿÒz8ÿÒz:ÿÓz9ÿÔz;ÿÔz;ÿÓy;ÿÓy;ÿÒy:ÿÑy9ÿÞ<ÿ ÿÿÿÿ'# ÿÿàŠ5ÿÞˆ6ÿÕ‚4ÿ؃4ÿØ„5ÿÚ†6ÿ܇8ÿ܈9ÿ܈:ÿ܈;ÿÚ‰<ÿÚ…6ÿÛ†6ÿ܆5ÿ݇6ÿ܇6ÿÛ†5ÿÚ…6ÿÚ…5ÿÙ„6ÿØ„6ÿÖƒ6ÿÕ‚6ÿÔ€7ÿÓ€7ÿÓ€8ÿÒ8ÿÒ~9ÿÓ~9ÿÓ~;ÿÔ};ÿÕ}<ÿÕ}=ÿÖ}=ÿÖ}>ÿÖ}>ÿÖ|>ÿÕ|>ÿÕ|>ÿâ„@ÿ ÿÿÿÿ&" ÿÿã7ÿàŒ8ÿá8ÿ×…6ÿÚ‡7ÿÛ‡8ÿ܉9ÿß‹;ÿߌ;ÿߌ<ÿß>ÿÞŒ<ÿ݈6ÿ܈6ÿÛ‡6ÿ܈7ÿ܉7ÿÞŠ7ÿÞŠ8ÿ݉7ÿ܈8ÿÛ‡8ÿÚ‡8ÿÙ†8ÿØ…9ÿÖƒ9ÿÖ‚:ÿÕ‚:ÿÕ‚;ÿÖ<ÿÖ=ÿ×€>ÿ×€>ÿØ€?ÿØ€@ÿÙ€AÿÙAÿÙBÿÙBÿæ‡Eÿ ÿÿÿÿ%!ÿÿã8ÿâ:ÿâ:ÿâ:ÿ؈9ÿÚŠ:ÿÜ‹;ÿÞŒ;ÿàŽ=ÿá>ÿà?ÿá@ÿà:ÿߌ8ÿß‹8ÿÞ‹8ÿÝŠ8ÿÛ‰8ÿÛ‰8ÿÜŠ9ÿÜŠ9ÿÞ‹:ÿÞ‹:ÿÜŠ:ÿÛ‰:ÿÚˆ;ÿÙ‡;ÿ؆;ÿ×…<ÿׄ=ÿ׃>ÿ؃?ÿ؃@ÿÙ‚AÿÙ‚AÿÚ‚BÿÚ‚CÿÚDÿÛDÿéŠHÿ ÿÿÿÿ$!ÿÿã‘:ÿâ‘;ÿä’<ÿå“<ÿã’<ÿÛ‹;ÿÜ<ÿߎ<ÿà=ÿá>ÿã“@ÿã”Aÿã“AÿâŽ:ÿá:ÿáŽ:ÿàŽ:ÿà:ÿߎ:ÿÞ:ÿÝŒ:ÿÛŠ:ÿÚŠ:ÿÚŠ:ÿÚŠ;ÿÛŠ;ÿÜ‹<ÿÜ‹=ÿÛŠ=ÿÚˆ>ÿÚ‡?ÿÙ‡@ÿÙ†@ÿÚ†AÿÙ„BÿÛ…CÿÛ…DÿÛ„EÿÛ„FÿëŒJÿ ÿÿÿÿ$ ÿÿä“;ÿã“=ÿä”=ÿå•>ÿæ•?ÿã•?ÿÝ=ÿÞ>ÿß?ÿá“@ÿâ“Aÿã•Cÿå–Dÿä”@ÿä’<ÿã’<ÿâ‘<ÿâ‘<ÿá‘<ÿá‘<ÿá<ÿß<ÿß<ÿÞŽ<ÿÝ<ÿÜŒ<ÿÙŠ=ÿ؉=ÿ؉>ÿ؉?ÿ؈?ÿ؈@ÿ؈BÿÙ‡CÿÚˆCÿÛ‡DÿÛ‡EÿÛ‡Fÿ܆GÿëLÿ ÿÿÿÿ#ÿÿã•=ÿâ•?ÿä•?ÿå–?ÿæ—@ÿç™Aÿá•Aÿß“@ÿà“Aÿß“Bÿã•Cÿä–Cÿä—Eÿå™Fÿå•>ÿå•>ÿå”>ÿä•>ÿä•>ÿä”>ÿã”>ÿã”>ÿâ“>ÿà’>ÿß‘>ÿÞ>ÿÝ>ÿÜŽ>ÿÜ?ÿÚŒ@ÿÙ‹@ÿÙ‰Bÿ؈CÿׇDÿÖ†EÿÖ…FÿÕ„Gÿ×…HÿØ…IÿçŽNÿ ÿ ÿÿÿ"ÿÿã–>ÿâ–@ÿä—Aÿå˜Aÿæ™AÿçšBÿéœDÿá–Cÿâ–Cÿâ–Dÿá–Eÿã—EÿæšFÿæšGÿæ™Eÿç˜@ÿç˜@ÿç˜@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿå—@ÿå—@ÿä•@ÿâ”@ÿá“@ÿà’@ÿß‘@ÿÞAÿÝAÿÜŽBÿÛŒCÿÚ‹DÿÙŠEÿ؉Fÿ؈GÿׇIÿ؇JÿçOÿÿ ÿÿÿ"ÿÿã—?ÿá—Aÿã™BÿäšBÿæ›Bÿç›DÿèDÿèžFÿá˜Dÿã™Dÿã™Eÿâ™FÿâšHÿçHÿçŸJÿçšBÿçšBÿè›BÿèœBÿè›Bÿç›Bÿç›Bÿç›BÿçšBÿçšBÿæšBÿä™Bÿâ–Aÿá•Aÿà•Bÿß“BÿÞ’CÿÜ‘CÿÛDÿÛŽEÿÚFÿÙŒGÿÙ‹HÿØŠJÿç“Oÿÿ!ÿÿÿ!ÿÿá˜Cÿá™Dÿã™Dÿä›DÿåœEÿæœEÿçžFÿèŸHÿæHÿã™Gÿå›Hÿå›IÿäœJÿã›JÿæžKÿé IÿèœCÿéœCÿéDÿêžEÿéžEÿéEÿéEÿéEÿèEÿèœEÿçœEÿçœEÿåšDÿâ˜Dÿá—Dÿà–Dÿß•EÿÞ”EÿÜ’FÿÜ‘GÿÛHÿÚIÿÙJÿç–Oÿÿ!ÿÿÿ ÿÿá™Dÿß™Eÿá›FÿãœFÿåFÿæžFÿçŸHÿè Iÿé¡JÿäIÿåJÿæžJÿæžKÿåŸKÿåžLÿå NÿéŸGÿêŸEÿê Eÿê Eÿê Eÿë¡Gÿë¡Gÿê Gÿê Gÿé Gÿé GÿéŸGÿèŸGÿèŸGÿæFÿãšFÿâ™Fÿá˜Fÿß—FÿÞ–GÿÝ”HÿÜ“HÿÛ’IÿèšNÿÿ!ÿÿÿÿÿß›FÿÝšGÿßœGÿáGÿäžGÿäŸHÿæ Iÿç¢Iÿè¢Jÿè¤LÿäžJÿå Kÿæ Lÿå¡Mÿæ¡Nÿæ¢Nÿä¡NÿæžFÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë£Hÿë£Iÿê¢Hÿê¢Hÿé¢Hÿê¢Hÿé¡Hÿé¡Iÿè HÿäGÿâœHÿâ›HÿàšHÿÞ™HÿÞ—IÿÜ–IÿéŸNÿÿ"ÿÿÿÿÿÞ›GÿÝ›HÿßœHÿážHÿãŸIÿä Iÿæ¡Jÿç£Kÿè¤Lÿè¥Mÿæ£Mÿå¢Mÿæ¢Nÿç£Nÿæ£Pÿç¤Pÿç¤Qÿæ LÿäŸHÿê¢Iÿí¥Iÿí¥Iÿì¦Iÿí¦Iÿì¥Iÿì¥Jÿë¥Jÿì¥Jÿë¥Jÿë¤Jÿê¤Jÿê¤Jÿê£Jÿç¡IÿäŸIÿâžIÿâIÿàœIÿßšIÿì£Nÿÿ"ÿÿÿÿÿÝIÿÛœJÿÝžJÿßžJÿà Jÿâ¡Jÿä¢Kÿæ¤Lÿç¥Mÿè¦Nÿé§Oÿå£Oÿæ¥Pÿæ¤Qÿç¥Qÿç¥Rÿç¦Sÿç¦Tÿæ¡Jÿå¡Iÿæ¢Jÿì§Kÿî©Kÿî¨Kÿî¨Kÿí¨Kÿí§Kÿì§Kÿì§Lÿì¦Lÿë§Lÿë¦Lÿê¦Lÿê¦Lÿé¥Lÿæ¢Kÿä¡Kÿâ KÿážKÿï§Oÿÿ#ÿÿÿÿÿÛžJÿÙžKÿÛžLÿÝ Lÿß¡Lÿà¡Lÿâ£Lÿå¥Mÿæ¦Oÿç§Pÿè¨Qÿè¨Qÿæ§Qÿç§Rÿæ§Sÿç¨Tÿè¨Tÿç©Tÿç¦Qÿæ¤Kÿæ£Kÿâ¢Kÿç¤Kÿï«Mÿð¬Lÿï«Lÿï«MÿîªMÿí©Lÿì©Mÿì©Nÿë©Nÿì©Nÿë¨Mÿê§Nÿê§Nÿè¦Mÿä£Lÿã¢Lÿò«Pÿÿ#ÿÿÿÿÿÚŸLÿÙžMÿÛ MÿÝ¡MÿߢMÿà£Nÿá¤Mÿã¥Oÿå§Pÿæ¨PÿçªQÿéªRÿå¨Sÿç¨Sÿç©TÿèªTÿèªVÿè«Vÿè«Wÿç¦Nÿç¥Mÿå¤Mÿå¤Mÿâ£Mÿé¨Nÿò®Nÿò¯Nÿð®Nÿï¬Nÿî¬Nÿí¬NÿìªNÿëªNÿëªOÿëªOÿëªOÿê©Oÿé©Oÿæ¦Nÿô¯Rÿÿ#ÿÿÿÿÿÙ¡NÿØ OÿÚ¢OÿÝ£OÿÞ¤OÿߥOÿá¥Oÿâ¦Oÿä¨Pÿå©QÿæªSÿè¬Tÿç«UÿæªUÿç«Uÿç«Vÿç¬Wÿè¬Xÿè­Yÿè«Vÿæ§Oÿå¦Nÿå¦Oÿå¦Oÿå¦Nÿä¥Nÿê«Oÿò°Pÿñ°Pÿï¯Pÿï®Pÿî­Pÿí¬Pÿì¬Pÿê«PÿêªPÿéªPÿéªPÿéªPÿ÷´Tÿÿ$ÿÿÿÿÿÚ¤PÿؤPÿÛ¥QÿݦQÿÞ§Qÿß§Qÿà¨Qÿá¨RÿâªRÿãªTÿå¬Tÿè­Uÿé®Wÿå¬Vÿæ­Wÿç­Yÿç¯Yÿç®Zÿè¯[ÿè¯\ÿåªSÿå¨Qÿå¨Qÿå¨Qÿä¨Qÿä¨Qÿä¨Pÿâ¨Qÿê­Rÿñ±Rÿð±Rÿï°Rÿî°Rÿí¯Rÿì®Qÿë®Qÿê­Qÿé¬Qÿç«Qÿ÷¶Vÿÿ$ÿÿÿÿÿÛ¨RÿاSÿÛ¨SÿܨSÿÞ¨SÿÞ©Sÿà©SÿáªSÿâªTÿã«Uÿã¬Vÿæ®Wÿç®Xÿæ®Xÿå®Yÿç®Zÿç°Zÿè°[ÿè°\ÿè±]ÿæ­\ÿã©Rÿä©Sÿå©SÿåªSÿå©Sÿä©Rÿä©Sÿä©Sÿã©Sÿê­Tÿï²Tÿï±Tÿî°Tÿí°Tÿì¯Tÿë®Tÿé®Tÿé­Sÿø¸Xÿÿ% ÿÿÿÿÿݬTÿÚ«UÿÚ«UÿÛ«UÿÜ«UÿÝ«Uÿß«Uÿà¬Uÿà¬Vÿâ­Wÿâ®Wÿä¯Xÿå°Yÿç°Zÿå°[ÿæ±[ÿæ±\ÿç²]ÿç²^ÿç²^ÿå°_ÿä¬Wÿã«Tÿã«Tÿä«Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿã¬Tÿã«Tÿâ«Tÿè¯Tÿî³Uÿí³Uÿì²Uÿì±Uÿë±Uÿé°UÿøºZÿÿ% ÿÿÿÿ ÿ߯WÿÛ­WÿÜ®WÿÜ­WÿÝ­WÿÝ­WÿÞ­Wÿß­Vÿà­Wÿà®Wÿâ®Yÿã°Yÿä°[ÿå°[ÿå±[ÿå±\ÿå²^ÿæ´_ÿç´_ÿå²_ÿä±`ÿä±`ÿã¬Vÿã­Vÿä¬Vÿä­Vÿã­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä­Vÿâ¬Vÿæ¯WÿìµWÿì³Wÿë²Wÿê²Wÿù½[ÿÿ% ÿÿÿÿ ÿà²XÿݱYÿܱYÿݱYÿܰYÿݰXÿܯXÿÞ¯XÿÞ¯Yÿß°Yÿà±Zÿá°[ÿã²[ÿä²]ÿä³]ÿä³^ÿå³_ÿåµ_ÿæµaÿä³aÿã³bÿã³cÿã±]ÿã®Xÿâ¯Xÿâ®Xÿã¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä®Xÿã¯Xÿâ¯Xÿâ¯Xÿá­Xÿä°Xÿé³Xÿë´Xÿù¿]ÿÿ% ÿÿÿÿ ÿâ¶[ÿÞµ[ÿÞµ[ÿÞ³[ÿݳZÿܳZÿݱZÿܲZÿݱZÿÞ±[ÿß²\ÿà²]ÿâ³^ÿã³^ÿã´_ÿãµ`ÿäµ`ÿäµaÿå¶bÿâ´bÿãµcÿãµcÿãµdÿâ°Yÿâ°Yÿâ°Yÿã°Yÿâ°Yÿã°Yÿã°Yÿã°Yÿã°Yÿâ°Yÿã°Yÿâ°Zÿâ°Zÿâ°Yÿá¯Yÿâ°YÿöÀ_ÿÿ% ÿÿÿÿ ÿã¸\ÿ߸]ÿß·\ÿß·\ÿÞ¶\ÿݵ\ÿÝ´\ÿÜ´\ÿݳ\ÿݳ]ÿݳ]ÿÞ³^ÿà´^ÿáµ`ÿâ´`ÿáµ`ÿã¶bÿã¶bÿâ¶cÿâµdÿáµeÿâµeÿã¶fÿâ´cÿà±[ÿá±[ÿâ±[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ±[ÿâ²[ÿâ²[ÿá±[ÿá±[ÿà±[ÿï½`ÿÿ% ÿÿÿÿ ÿñÇbÿïÅbÿïÅbÿîÅbÿíÄbÿíÃbÿìÂbÿëÀbÿêÀbÿé¿bÿè¿cÿè¾bÿé¾cÿé½dÿê½dÿê½eÿê½eÿë¾eÿé¼fÿé»fÿé¼eÿè¼fÿè»gÿè¼gÿé¹_ÿëº`ÿì¼`ÿì¼`ÿì¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿì¼`ÿí¼`ÿûÇeÿÿ% ÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿÿ"ÿ$%)ÿ++0ÿ228ÿ::?ÿ@@EÿGHNÿNOUÿVV\ÿ^_cÿ>>Dÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ% ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%"!ÿ,)(ÿ30/ÿ:76ÿB?>ÿHEDÿWROÿa^^ÿ^ZZÿebaÿlhhÿxvuÿ*'&ÿ!ÿ"ÿ"ÿ#ÿ#ÿ$ÿ$ÿ%ÿ% ÿ% ÿ% ÿ% ÿ% ÿ% ÿ% ÿ'! ÿÿjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿjÿÿÿÿÿÿÿÀÿÿÀÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿÿàÿÿÿÿðÿÿÿÿøÿÿÿÿøÿÿÿÿøÿÿÿÿøÿÿ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ÿÿÿÿÿÿÿÿÿÿÿÿ(@€ @¹n¹nÿÿÿ&)******))))))))((((((((((((('$!ÿÿÿÝÙ×¹ÒÎÇÿØÔÏÿÛÖÑÿÝÙÔÿàÛ×ÿâÞÚÿåáÝÿçäàÿêæâÿìéæÿîëéÿñïìÿóñîÿõóðÿ÷ôòÿøöôÿù÷ôÿù÷ôÿù÷ôÿøõóÿöôñÿõòðÿóðíÿðîêÿîìèÿìéåÿéæáÿçâÞÿåàÜÿáÝÙÿßÛÖÿÜØÓÿÙÕÐÿÔÏÉÿäâà½ztnªohbþqicÿqjdÿrjeÿrkeÿrkeÿslfÿskfÿrkeÿrkdÿqjdÿpicÿphbÿpicÿtmhÿskfÿrjeÿqjdÿpicÿohaÿjc[ÿf]Vÿe\Vÿe\Vÿe\Vÿe]Vÿe]Vÿf]Vÿf]Vÿf^Vÿf^Xÿf^Xÿf^Xÿf^Xþoga«ogb{rn"†yÿ†yÿ‡€zÿ‡€{ÿˆ|ÿˆ‚|ÿ‰‚}ÿ‰‚|ÿ‰‚}ÿˆ|ÿˆ|ÿ‡€{ÿ†€zÿˆ|ÿ†ÿ‹…€ÿŠ…€ÿ‰ƒÿˆ‚~ÿˆ|ÿƒ|wÿ}uoÿ{unÿzsmÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ|tnÿsmf#ha[‰„µ’Œ‡þ“ˆÿ”Žˆÿ•‰ÿ•Šÿ–Šÿ–Šÿ–Šÿ•Šÿ•މÿ“‡ÿš”ÿ—“ÿ–ŠÿŠ„ÿ‹…ÿˆ‚|ÿ‹„~ÿ‰ƒÿ’‹†ÿ†€ÿˆ{ÿ‡€zÿ‡€yÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zþ…~x¶„~y‘‹†!Ÿ™”ÿŸ™”ÿ š•ÿ¡š–ÿ¢œ—ÿ¢œ—ÿ¢œ—ÿ¡›—ÿ¡›–ÿ¥Ÿ›ÿŸ›—ÿÃÁ¿ÿ®ª¦ÿ—‘‹ÿ™“ÿœ•Žÿœ”ÿ™‘‰ÿ•އÿ“Œ…ÿ”‡ÿމ‚ÿ›–’ÿ’‹†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“‡ÿ‰‚~"}wq¦¡³ª¤ þ«¥¡ÿ¬¦¢ÿ­§£ÿ­¨¤ÿ®¨¤ÿ­¨¤ÿ¬¦¢ÿ³±¯ÿ®¨¤ÿ”ˆÿ—‹ÿš•‘ÿ›–’ÿœ–’ÿœ—“ÿ˜”ÿ˜”ÿ›•’ÿ•ŽŠÿ¡›–ÿÂÀ¾ÿ—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’þœ•‘µ˜’ޤ¡›µ±­ÿµ±¬ÿ¶²­ÿ·²®ÿ¸³¯ÿ¸´°ÿ·³¯ÿ·²®ÿ¬§£ÿ¦ œÿ¦¡ÿ¬¦£ÿ¬¦£ÿ¬§¤ÿ¬§¤ÿ¬©¥ÿ­¨¦ÿ­ª¦ÿ¯ª§ÿ§¢žÿ¦ œÿ£žšÿ®©¤ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿ—’!‹†»¶³˜Á¼¸ÿ½¹ÿþºÿÿ»ÿÿ»ÿþ»ÿ¾ºÿ½¹ÿ¼¶³ÿ³¯«ÿª¥¡þ«§¤ÿ­©¥ÿ®ª§ÿ¯«¨ÿ¯¬©ÿ±®«ÿ²®«þ´°­ÿ·²¯ÿ¸³¯ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ²­©¥¡ž¥¡±­©ÿ²®ªÿ´°¬ÿµ±®ÿ¶³°ÿ¸´±ÿ¹µ²ÿº¶³ÿ®¬« œ˜¼¸µÿ¼¸µÿ¾»·ÿ¿½¹ÿÁ¾¼ÿÿ¾ÿÄÀ¾ÿÆÃÁÿ·°­ÿµ¯«ÿµ®ªÿµ®ªÿ´®ªÿ´®ªÿ´®ªÿµ¯¬ÿ¾»¹ÿ¼¹·ÿ½º¸ÿ¾¼»ÿ¾¼»ÿ½º¸ÿ¼¹·ÿ¾»¹ÿ¼»ºÿ»¹¸ÿ¯«¨þ¤™ÿ¤™ÿ¯«¨þ»¹¸ÿ¼»ºÿxvvÿxvvÿ¡›ÿ œ›ÿxvvÿxvvÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–– ÿ'# ÿ)%#ÿ(%"ÿ'$!ÿ($!ÿ'# ÿ&" ÿ($"ÿ,(&ÿ1-+ÿ520ÿ:75ÿ.+)ÿ ÿ!ÿ!ÿ ÿÿÿÿÿÿÿÿ'##ÿÿ)%$ÿ843ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–ÿ'# ÿ&"ÿ&"ÿ%!ÿ%!ÿ$ ÿ# ÿ"ÿ#ÿ'$"ÿ+(&ÿ0,*ÿ410ÿ:74ÿÿÿÿÿÿÿÿÿÿÿÿ1.,ÿA=<ÿ40.ÿ=98ÿ965ÿ@;:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*%"ÿ%"ÿÿÿÿÿÿÿÿÿ $ÿ"&)ÿ&*-ÿ,/3ÿ$'+ÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿÿ)%"ÿÿÊv)ÿÐ{-ÿÑ{-ÿÓ|-ÿÓ}.ÿÓ}.ÿÓ}/ÿÔ0ÿÕ1ÿÖ€2ÿÕ2ÿÔ2ÿÕ€3ÿÕ}.ÿÕ~.ÿÕ~.ÿÕ~.ÿÕ~.ÿÔ~.ÿÔ}.ÿÓ}.ÿÒ}.ÿÑ|.ÿÐ|.ÿÐ{.ÿÏ{.ÿÏ{/ÿÏz/ÿÏz/ÿÏz0ÿÎz1ÿÐz1ÿÐz2ÿÐz2ÿÐy2ÿÐw2ÿÑw4ÿÑw4ÿÑw4ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÐv5ÿÐv5ÿÏv4ÿÏv4ÿÎv2ÿÍv2ÿÉt/ÿÿÿÿÿ)$!ÿÿÓ/ÿÐ}2ÿÓ~2ÿÔ2ÿÕ3ÿÖ3ÿ×4ÿׂ5ÿׂ5ÿÖ‚6ÿØ„8ÿÙ…9ÿÚ†9ÿÙ„7ÿØ‚3ÿØ3ÿØ‚3ÿ×3ÿØ3ÿ×3ÿÖ3ÿÖ€3ÿÕ€3ÿÓ3ÿÒ3ÿÑ~3ÿÐ}3ÿÐ}3ÿÐ|4ÿÐ|4ÿÐ{5ÿÏ{5ÿÐ{5ÿÐz6ÿÐ{6ÿÐz6ÿÐz7ÿÐz7ÿÑy8ÿÑz8ÿÒz8ÿÒz9ÿÒy9ÿÒy9ÿÒy:ÿÒy:ÿÒx:ÿÑy9ÿÐy8ÿÐy9ÿÏy8ÿÌw5ÿÿÿÿÿ(#!ÿÿÙ„0ÿÚ…4ÿÓ€3ÿÖ3ÿÖ3ÿØ‚4ÿÙ„6ÿÚ„6ÿÚ…7ÿÚ…8ÿÚ†8ÿÙ†9ÿÚ‡:ÿÚ‡;ÿÛ…5ÿÜ…5ÿÛ„5ÿÛ…5ÿÛ„5ÿÚ„5ÿÚ„5ÿÙ„4ÿÙƒ4ÿ؃5ÿׂ5ÿÖ5ÿÕ€5ÿÔ€4ÿÓ5ÿÒ~5ÿÒ~5ÿÒ}7ÿÑ}7ÿÑ}6ÿÑ}8ÿÑ|8ÿÒ|8ÿÒ|8ÿÓ|9ÿÓ{:ÿÓ{;ÿÔ{;ÿÔ{;ÿÕ{;ÿÕ{<ÿÕ{<ÿÔ{<ÿÔz<ÿÔz<ÿÓz<ÿÒz;ÿÐx7ÿÿÿÿÿ'# ÿÿÚ†2ÿÞ‰6ÿ݈6ÿÔ‚4ÿׄ4ÿØ„5ÿÙ…6ÿÛ‡7ÿ܈8ÿ܈9ÿ܉:ÿ܈:ÿ܉;ÿÜŠ<ÿÛ‡:ÿÙ…5ÿÚ†5ÿ܇6ÿ݇6ÿ݇6ÿ܇6ÿÛ†5ÿÛ†5ÿÛ†6ÿÚ…6ÿÙ…6ÿØ…6ÿ׃6ÿ׃6ÿÖ‚7ÿÕ‚7ÿÔ7ÿÓ€8ÿÓ€8ÿÓ8ÿÒ9ÿÓ~9ÿÓ~:ÿÓ~;ÿÔ~;ÿÕ}<ÿÕ}=ÿÕ}=ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ}?ÿÖ|?ÿÖ|>ÿÕ|>ÿÕ|?ÿÒ{:ÿÿÿÿÿ'" ÿÿ܉4ÿàŒ8ÿáŒ8ÿß‹8ÿÖ…6ÿÙ†7ÿÚ‡7ÿÚ‡8ÿ݉9ÿߊ;ÿß‹;ÿß‹<ÿß‹=ÿÞŒ=ÿÞŒ>ÿ݉8ÿ݈7ÿÛ‡6ÿÛ‡6ÿÛˆ7ÿ݉8ÿߊ8ÿÞ‰8ÿ݉8ÿ݉7ÿ܈7ÿ܇8ÿÛ‡8ÿÚ‡8ÿÚ†8ÿÙ…8ÿØ…8ÿ׃9ÿÖƒ9ÿÕ‚:ÿÕ:ÿÕ;ÿÕ;ÿÖ€<ÿÖ€=ÿ×€=ÿÖ€>ÿ×?ÿØ?ÿØ@ÿÙ@ÿÙAÿÙ~AÿÙ~AÿÙ~BÿØ~BÿÕ}=ÿÿÿÿÿ&"ÿÿÝŠ5ÿáŽ9ÿáŽ9ÿâ9ÿà9ÿׇ8ÿÚ‰9ÿÛŠ9ÿÜ‹:ÿÞ‹;ÿà<ÿàŽ=ÿàŽ>ÿà>ÿà?ÿà>ÿÞŠ7ÿÞ‹7ÿÞŠ7ÿÞŠ7ÿ܉7ÿÛˆ7ÿÚ‰8ÿÛ‰8ÿÜŠ9ÿß‹9ÿÞ‹9ÿÝŠ9ÿ݉9ÿ܉9ÿÛ‰9ÿÚˆ:ÿÚ‡:ÿÙ‡:ÿØ…:ÿ×…;ÿׄ;ÿÖƒ<ÿÖƒ=ÿÖƒ>ÿׂ>ÿׂ?ÿ×?ÿØ@ÿÙAÿÙAÿÚBÿÙBÿÚ€CÿÚ€CÿÚ€CÿØ?ÿÿÿÿÿ&!ÿÿÝŒ6ÿâ;ÿã;ÿä‘;ÿä‘;ÿà;ÿÙŠ:ÿÛ‹;ÿÝŒ<ÿß<ÿß<ÿá>ÿâ?ÿâ‘?ÿâ‘@ÿâ’Aÿá<ÿà9ÿà9ÿàŒ9ÿà9ÿߌ9ÿߌ9ÿÞŒ9ÿÝŠ9ÿÚŠ9ÿÛ‰9ÿÛŠ:ÿÜ‹:ÿÞ‹;ÿߌ;ÿÞŒ;ÿÝ‹;ÿÜŠ<ÿÛ‰<ÿÚˆ<ÿÚˆ=ÿÙ‡=ÿ؆>ÿÙ…>ÿÙ…?ÿÙ„@ÿØ„AÿÙƒAÿÚƒBÿÚƒCÿÛƒCÿÛƒDÿÛ‚DÿÜ‚EÿÜ‚EÿÚAÿÿÿÿÿ%!ÿÿÝ8ÿâ‘;ÿã’<ÿã“<ÿä“=ÿå“<ÿß<ÿÛ<ÿÜ<ÿÞ<ÿà>ÿà>ÿá‘?ÿã“Aÿã”Aÿã”Bÿã”Bÿâ:ÿâ;ÿá;ÿá;ÿá;ÿàŽ;ÿà;ÿߎ;ÿߎ;ÿÞ;ÿÞ;ÿÜŒ:ÿÚ‹:ÿØŠ:ÿÙŠ<ÿÚŠ<ÿÚ‹<ÿÛ‹<ÿÝŒ>ÿÜ‹>ÿÛ‹>ÿÛ‰>ÿÚˆ@ÿÚˆ@ÿÚ‡AÿÚ†AÿÙ†AÿÙ†CÿÚ…CÿÚ…DÿÚ…DÿÛ…EÿÛ„FÿÜ„GÿÛƒCÿÿÿÿÿ$ ÿÿÞ:ÿâ“=ÿä“=ÿå”>ÿæ•>ÿæ•>ÿç–?ÿÞ‘>ÿÞ=ÿÞ‘>ÿß?ÿâ’@ÿâ“@ÿâ“Aÿã•Bÿå–Cÿå–Dÿä”@ÿä’<ÿã’<ÿã’<ÿã’<ÿã’<ÿâ‘<ÿâ‘<ÿá<ÿà<ÿà<ÿß<ÿß<ÿÞŽ<ÿÝ<ÿÜ=ÿÛŒ=ÿÚ‹=ÿ؉=ÿ؉>ÿ؉?ÿ؉?ÿ؉?ÿÙ‰@ÿÙ‰AÿÚ‰BÿÛ‰CÿÛ‰CÿÛˆDÿ܇Dÿ܇Eÿ܇Fÿ܆Gÿ݆GÿÛ…Dÿÿ ÿÿÿ# ÿÿÝ9ÿâ”?ÿã•?ÿå–?ÿæ–?ÿæ—@ÿç—Aÿè™AÿÝ‘?ÿà“@ÿà“@ÿß’Aÿá”Bÿã•Cÿã•Cÿä–Dÿå˜Eÿæ™Fÿå•>ÿå•>ÿå”>ÿä”>ÿä”>ÿã”>ÿã”>ÿã”>ÿã“>ÿâ“>ÿâ“>ÿà‘>ÿà‘>ÿß‘>ÿÞ>ÿÞ>ÿÝŽ>ÿÜŽ?ÿÛ?ÿÛŒ?ÿÚ‹@ÿÙŠAÿ؉Aÿ׈BÿÖ‡CÿÖ†CÿÕ…DÿÖ…EÿÖ…Fÿ×…GÿØ…GÿÙ†HÿÚ†HÿØ„Eÿÿ ÿÿÿ#ÿÿÝ‘;ÿâ•?ÿã–@ÿä—@ÿå˜@ÿæ˜@ÿç™AÿçšBÿçšCÿÞ“Aÿá•Aÿá•Bÿà•Cÿá•Cÿä—Dÿå™Eÿå™EÿåšFÿæ™Dÿæ—?ÿæ—?ÿæ—?ÿå–?ÿå–?ÿå–?ÿå–?ÿä–?ÿå–?ÿä–?ÿä–?ÿâ•?ÿá“?ÿá“?ÿà’?ÿß‘?ÿÞ?ÿÞ?ÿÜ@ÿÜŽ@ÿÛAÿÚŒAÿÚŒBÿÙ‹CÿÙ‰Dÿ؈Dÿ׈EÿׇGÿ׆Gÿ؆Hÿ؆IÿÙ†Jÿ׃Gÿÿ ÿÿÿ"ÿÿÝ’<ÿâ–Aÿã—Aÿä˜Aÿå™BÿæšBÿçšBÿè›CÿèœEÿåšEÿà–Cÿã—Dÿã—Dÿâ—Dÿá–FÿäšFÿæ›Gÿæ›HÿæœIÿæ˜Aÿç™Aÿè™Aÿç™Aÿç™Aÿç™Aÿæ™Aÿæ™Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿå˜Aÿä—@ÿâ•@ÿá”Aÿá”Aÿß“Aÿß’AÿÞ‘BÿÝBÿÜCÿÛŽCÿÛŽDÿÚDÿÚŒEÿÙ‹FÿØŠGÿ؉Gÿ׉Iÿ؈JÿÙˆJÿ׆Gÿÿ!ÿÿÿ"ÿÿÜ“=ÿá—Bÿâ˜Bÿä™CÿåšCÿæ›Cÿç›DÿçœDÿèEÿéžFÿã™Eÿã˜Dÿã™EÿãšFÿã™Gÿâ™GÿäšHÿçIÿçIÿèžHÿçšAÿèšAÿèœCÿèœCÿè›Cÿè›Cÿè›Cÿç›Cÿè›CÿçšCÿçšCÿçšCÿæšCÿæšCÿå˜Bÿâ–Bÿâ–Bÿá•Bÿà•Cÿß“CÿÞ“CÿÝ’DÿÜ‘DÿÜEÿÛEÿÚŽFÿÚFÿÙŒHÿÙ‹HÿØ‹JÿØŠJÿׇGÿÿ!ÿÿÿ!ÿÿÛ”?ÿà˜Cÿá™CÿãšCÿä›CÿåœDÿæœDÿçEÿèžFÿéŸGÿéŸHÿâšFÿäšFÿå›Gÿå›Gÿä›HÿäœIÿâ›JÿçžJÿé¡KÿèDÿèœBÿèœBÿéCÿêžDÿéžDÿéDÿéDÿèDÿéDÿèDÿèDÿçDÿçœDÿçœDÿçœDÿåšCÿã˜Cÿâ—Cÿá—Dÿà–Cÿß•DÿÞ”DÿÝ“EÿÝ’FÿÜ‘FÿÛFÿÛHÿÚŽIÿÙIÿÙJÿ׊Gÿÿ!ÿÿÿ!ÿÿÚ•@ÿß™EÿášEÿâ›EÿäœEÿåœEÿåFÿçžFÿèŸGÿè Hÿè HÿçŸIÿâ›HÿåœHÿåIÿåJÿåJÿåžKÿãKÿåŸMÿê¢LÿéžCÿéžDÿéžDÿéžDÿéŸEÿê Fÿê Fÿê FÿêŸFÿéŸFÿéŸFÿéŸFÿéŸFÿèžFÿèžFÿèžFÿèžFÿå›EÿãšEÿâ™Eÿá˜Eÿà˜Eÿß–FÿÞ–FÿÝ•FÿÜ“GÿÜ“GÿÛ‘IÿÚ‘IÿÚJÿ×Gÿÿ"ÿÿÿ ÿÿÚ•AÿÞ™Fÿà›EÿâœFÿãGÿäžGÿåžGÿæŸGÿç Gÿè¡Iÿé¢Jÿé¢KÿäŸIÿåžJÿæŸJÿæŸKÿæŸKÿæ Kÿæ Mÿå Mÿä Nÿè Iÿê¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Eÿë¡Fÿê¡Gÿë¢Hÿë¢Hÿë¡Hÿê¡Gÿé¡Gÿê¡Gÿê¡Gÿé Hÿé Gÿé HÿèŸGÿåGÿã›Gÿâ›GÿášFÿà™FÿߘGÿÞ—HÿÝ–GÿÜ•IÿÛ”IÿÛ“IÿØFÿÿ#ÿÿÿÿÿÙ—CÿÝšGÿÞ›GÿàœGÿâGÿãžGÿäŸHÿåŸHÿæ¡Iÿç¢Jÿç¢Jÿé£Kÿè¤LÿâžJÿå Kÿæ¡Kÿæ¡Lÿæ¢Mÿç¢Nÿæ¢Nÿæ¢Oÿå¢PÿåžFÿê¢Gÿë£Gÿë£Gÿì£Gÿì£Gÿë£Gÿë£Hÿì¤Hÿë¤Iÿë£Iÿë£Hÿë£Hÿê£Hÿê£Hÿê¢Iÿê¢Iÿé¢Iÿé¢Iÿç IÿäHÿãGÿâœHÿá›HÿàšHÿß™HÿÞ˜HÿÝ—IÿÜ—JÿÙ“Fÿÿ"ÿÿÿÿÿÙ—DÿÜ›HÿÞœHÿßIÿàžIÿâŸIÿä Iÿå¡Iÿæ¡Jÿç£Kÿè¤Lÿè¤Mÿé¥Mÿæ£Mÿå¡Mÿå¢Mÿç¢Nÿæ¢Oÿæ¤Oÿç¤Pÿç¤Qÿç¤Qÿæ¢MÿäžHÿç¡Iÿí¥Iÿí¥Iÿì¥Iÿí¦Iÿí¦Iÿí¥Iÿí¥Iÿí¥Jÿì¥Jÿë¥Jÿì¥Jÿë¥Jÿê¤Jÿë¤Jÿê¤Jÿê¤Jÿê¤Jÿé£Jÿæ¡IÿäŸIÿãžIÿâIÿáIÿàœJÿß›JÿÞ™JÿÛ–Fÿÿ#ÿÿÿÿÿטFÿÛœIÿÝIÿÞžIÿߟIÿàŸIÿâ¡Iÿä¡Jÿä¢Jÿæ£Kÿç¥Lÿç¥Mÿè¦Nÿé§Oÿä¢Nÿæ¤Nÿå¤Oÿæ¤Oÿæ¥Pÿæ¥Qÿç¥Qÿç¦Rÿæ¦Sÿæ¡Jÿå¡Iÿä Iÿé¤Jÿí§Jÿí¨Jÿî¨Jÿî¨Jÿí¨Jÿí¨Jÿì§Jÿì§Jÿë§Kÿë§Kÿì§Kÿë¦Kÿê¦Kÿë¦Kÿê¦Kÿé¥Kÿé¥Kÿè¤Kÿä¡Jÿã JÿâŸJÿâŸJÿàžJÿßJÿÜ™Gÿÿ$ÿÿÿÿ ÿ×™GÿÛJÿÜKÿÝžKÿߟKÿà Kÿâ¡Kÿã¢Kÿä£Kÿå¤Lÿæ¥Nÿç¦Nÿè§Oÿè¨Pÿè¦Pÿå¥Pÿç¦Qÿç¦Qÿç¦Rÿè§Sÿè§Sÿè§Tÿè¨Tÿç¦Rÿç£Jÿæ£Jÿå¢Jÿå¢Kÿí§KÿïªKÿïªLÿïªLÿïªLÿîªLÿî©Lÿí©Lÿí¨Lÿí¨Mÿí¨Mÿì¨Mÿì¨Mÿì¨Mÿë§Mÿë§Mÿê¦Mÿê¦Mÿç¤Lÿä¢Kÿä¢Lÿã¡Lÿá LÿÞœHÿÿ$ÿÿÿÿ ÿÕ™HÿÙLÿÛžLÿÜŸLÿÝ MÿÞ¡Mÿà¢Mÿá¢Mÿã¤Mÿä¥Nÿå¦Nÿæ§Oÿç§Qÿè©QÿéªRÿå¦Qÿæ§Rÿç§Sÿæ¨Sÿç©Tÿè©Tÿè©UÿçªUÿçªWÿç¦Mÿç¤Lÿå¤Lÿå£Lÿâ¢Lÿç¥Mÿï«Mÿð¬Mÿð­Mÿï­Mÿï¬Nÿî«Nÿî«MÿíªMÿìªMÿì©Nÿë©Nÿì©Oÿì©Nÿë©Nÿë©Nÿê¨Nÿé¨Nÿè¦Nÿå¤Mÿä¤Mÿã£MÿߟHÿÿ$ÿÿÿÿ ÿÔ›IÿØžMÿÚŸMÿÜ MÿÝ¡MÿÞ¢Mÿà¢Mÿá¤Mÿâ¤Mÿã¥Oÿä§Oÿæ§Pÿæ©Qÿè©Qÿè«Rÿè©Sÿæ¨Rÿç©Sÿç¨SÿèªTÿç«UÿèªUÿè«Vÿè«WÿèªVÿæ¥Lÿç¦Mÿæ¥Mÿå¤Mÿå¤Mÿâ£Mÿé¨Mÿñ®Nÿò¯Oÿñ®Nÿð®Nÿï­Nÿï¬Nÿî«Nÿí«NÿíªNÿìªNÿë©NÿìªNÿìªOÿë©OÿëªOÿê©Oÿé¨Oÿæ¦Nÿå¥Nÿá¡Jÿÿ%ÿÿÿÿ ÿÔœKÿØŸNÿÙ OÿÛ¢OÿÜ¢OÿÞ£OÿߤOÿà¤Oÿá¥Oÿâ¥Oÿä§Pÿå©Qÿå©RÿæªSÿè«Tÿé¬Tÿå©TÿæªUÿçªUÿçªVÿè«Wÿè«Wÿç«Xÿç¬Xÿç¬Yÿç©Sÿç§Oÿå¥Nÿä¥Nÿä¥Oÿä¥Oÿä¥Oÿâ¥NÿêªOÿñ°Pÿñ°Pÿñ¯Pÿï®Pÿï®Pÿî­Pÿí­Pÿì¬Pÿì«Pÿë«PÿêªPÿê«Pÿê«QÿêªQÿéªPÿéªPÿç¨Pÿâ¤Lÿÿ%ÿÿÿÿ ÿÔžKÿØ¢PÿÚ£OÿÛ¤OÿݤOÿÞ¥QÿߥPÿà¦Qÿá¦Pÿá§Qÿâ¨Rÿä©RÿåªRÿæ«Tÿç¬Tÿé­Vÿç¬Vÿæ«Vÿæ«Wÿç¬Wÿè­Xÿè­Yÿè­Yÿé®Yÿé®[ÿè®Zÿæ¨Pÿå¦Pÿæ§Pÿæ§Pÿæ§Pÿå§Pÿå§Pÿä¦Oÿä¦Oÿë¬Qÿò±Rÿñ°Qÿð°Rÿð¯Qÿï¯Rÿî®Rÿí®Rÿí­Qÿì¬Pÿë¬Pÿê«Pÿé«PÿèªPÿèªPÿè«Qÿå§Mÿÿ% ÿÿÿÿ ÿÕ MÿؤQÿÚ¥QÿÛ¥QÿܦQÿÞ§Qÿß§Rÿà¨Rÿà¨Rÿá¨Qÿâ©SÿãªTÿãªTÿå«Uÿæ­Uÿè­Vÿé®Wÿå­Wÿæ­Xÿç­Yÿç®Yÿç®Zÿç¯[ÿç¯[ÿç¯\ÿç¯\ÿæ¬Vÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿå¨Qÿä¨Qÿä¨Qÿâ¨Qÿä¨Qÿê­Rÿñ²Sÿï±Sÿï±Rÿï°Rÿí°Rÿí¯Rÿì®Rÿì®Rÿê­Rÿê­Rÿé¬Rÿè¬Rÿç«Rÿä§Nÿÿ& ÿÿÿÿ ÿÕ£OÿÙ§SÿÙ§SÿÛ¨SÿܨSÿݨSÿÞ©Sÿß©Sÿà©Sÿà©SÿâªTÿâ«Tÿã«Uÿä¬Vÿå­Vÿç¯Xÿç¯Xÿç¯Yÿæ®Yÿæ¯Yÿç¯Zÿç°[ÿè°[ÿè°\ÿè±\ÿè±]ÿæ¯^ÿä©Sÿä©Sÿä©SÿåªSÿåªSÿåªSÿåªSÿåªSÿä©Sÿä©Sÿã©Sÿã©Sÿê¯Tÿð²Tÿï²Tÿî±Tÿî±Tÿí°Tÿì°Tÿì¯Tÿê®Tÿê®Tÿé®Tÿè­Tÿä¨Oÿÿ& ÿÿÿÿ ÿ×¥PÿÙ©TÿÚªTÿÛªTÿܪTÿݪTÿÞªTÿÞªTÿß«Tÿà«Tÿá«Tÿá¬Uÿâ­Vÿã­Vÿä®Wÿå¯Xÿç°Xÿç°Yÿä¯Zÿæ°Zÿæ°[ÿç±[ÿç²\ÿè²]ÿè±]ÿç²^ÿå¯^ÿå­ZÿâªSÿä«SÿäªSÿä«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿä«Sÿä«SÿãªSÿãªTÿé¯Tÿï³Uÿï²Tÿí²Uÿì²Tÿì±Tÿì°Uÿë°Tÿé°Tÿè¯TÿåªPÿÿ& ÿÿÿÿ ÿרRÿÚ¬VÿÛ¬VÿÛ¬VÿܬVÿܬVÿݬVÿݬVÿ߬Vÿà¬Vÿà­Vÿà­Vÿá®Xÿâ®Xÿã®Yÿå°Zÿå°Zÿæ°[ÿå°[ÿå±\ÿå±]ÿæ²]ÿç³^ÿç³^ÿç³_ÿæ²`ÿä°_ÿå±aÿä­Vÿä¬Uÿä¬Uÿã¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿã¬Uÿâ¬Uÿè¯VÿîµVÿí³Vÿì³Vÿì²Vÿë²Vÿê±Vÿé±Vÿå­Rÿÿ& ÿÿÿÿ ÿÙ«TÿÛ¯XÿÛ¯XÿÛ¯XÿÜ®XÿÝ®XÿÜ®WÿÝ®VÿÞ®VÿÞ®Vÿß®Vÿà®Xÿà¯Xÿá¯Xÿâ¯Zÿä±Zÿä±Zÿå²[ÿå±[ÿå²]ÿå³]ÿå²]ÿæ´^ÿç´_ÿç´`ÿå³`ÿä²`ÿå²aÿä±_ÿã­Vÿã­Wÿã®Wÿã®Wÿã®Wÿã®Wÿä­Wÿä®Wÿã®Wÿã­Wÿã®Wÿä®Wÿã®Wÿã­Wÿâ­Wÿâ­Vÿæ°Wÿì³Xÿí´Wÿì³Xÿë³Xÿê²Xÿæ®Rÿÿ& ÿÿÿÿ ÿÚ®UÿܱYÿݱYÿݱYÿݱYÿܰYÿݰYÿݰXÿܯXÿÞ¯XÿÞ¯XÿÞ¯Yÿà°Yÿà±Zÿá°Zÿâ²[ÿã²\ÿä³]ÿå²]ÿâ³^ÿå´^ÿå³_ÿæ´`ÿåµ`ÿæµaÿã²aÿä³bÿã³cÿä³cÿã°[ÿã¯Xÿâ¯Xÿâ¯Xÿã¯Xÿä®Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿã¯Xÿã¯Xÿâ¯Xÿâ®Xÿá®Xÿä°Yÿé´Xÿë´Xÿê´Xÿæ¯Tÿÿ& ÿÿÿÿ ÿÛ°WÿÞ´[ÿÝ´[ÿÝ´[ÿݳ[ÿݳZÿܲZÿݲZÿݱZÿݱZÿݱZÿÞ°[ÿÞ±[ÿß²\ÿà±\ÿâ²]ÿâ³^ÿã´^ÿä´_ÿä´_ÿä´`ÿäµ`ÿäµaÿå¶bÿäµbÿã³bÿãµcÿäµcÿãµdÿä´cÿâ¯Xÿâ°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿâ°Yÿã°Zÿã°Zÿâ°Zÿá°Yÿá¯Yÿâ°Yÿç³Yÿç±Uÿÿ& ÿÿÿÿ ÿܳWÿß¶\ÿß¶\ÿß¶[ÿÞµ\ÿÞµ\ÿÝ´\ÿÝ´\ÿݳ\ÿݳ\ÿݲ\ÿܲ\ÿݳ]ÿÞ³]ÿÞ³]ÿà³^ÿá´^ÿá´_ÿâ´`ÿã´_ÿâ¶aÿãµbÿã¶cÿä·cÿâµbÿãµdÿãµdÿâµeÿâ¶eÿâ¶fÿâ³_ÿá±Zÿá±[ÿá±[ÿâ±[ÿâ±[ÿâ±[ÿâ±[ÿâ±[ÿã±[ÿã±[ÿâ±[ÿâ²[ÿâ±[ÿâ±[ÿá±[ÿá±[ÿâ±[ÿá±[ÿá±[ÿà°[ÿÞ­Vÿÿ& ÿÿÿÿ ÿßµYÿà¹]ÿà¹]ÿ߸]ÿ߸]ÿÞ·]ÿß·]ÿÞ¶]ÿÞ¶]ÿܵ]ÿÝ´]ÿÝ´]ÿݳ^ÿÝ´^ÿÝ´_ÿß´_ÿà´_ÿàµ`ÿá¶aÿâ¶aÿâ¶bÿâ·bÿã·cÿã·cÿáµdÿâ¶eÿâµeÿâ·fÿâ·fÿâ·gÿâ·hÿá±\ÿá²\ÿá²\ÿá²\ÿá²\ÿâ²\ÿâ²\ÿâ³\ÿâ³\ÿá³\ÿâ³\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿá²\ÿá²\ÿá²\ÿÞ­Wÿÿ& ÿÿÿÿ ÿá¶Wÿå»]ÿãº\ÿäº\ÿãº\ÿâ¹\ÿâ¹\ÿá¸\ÿá¸\ÿà·\ÿà¶\ÿß¶\ÿß´]ÿß·]ÿßµ]ÿàµ^ÿàµ^ÿáµ_ÿá¶_ÿâµ_ÿâµ_ÿâ¶`ÿãµ`ÿâµ_ÿá´`ÿá´`ÿá´`ÿà´aÿà³aÿà³bÿß´bÿÞ²\ÿâ²[ÿâ³[ÿâ³[ÿâ³[ÿâ´[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿã³[ÿâ³[ÿâ³[ÿâ´[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿß®Uÿÿ& ÿÿÿÿÿ ÿ  ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿ ÿ"!%ÿ''+ÿ-,0ÿ226ÿ87;ÿ==@ÿFDFÿJINÿOMRÿSSWÿYY]ÿ^^bÿgfkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ#ÿÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$! ÿ*'&ÿ0,+ÿ521ÿ;87ÿA>=ÿGCBÿMJHÿYVRÿb_^ÿ]YXÿda`ÿigfÿolkÿvsrÿecaÿÿ#ÿ"ÿ#ÿ$ÿ$ÿ$ÿ%ÿ%ÿ% ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ#ÿ ÿ––ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü?ÿÿü?ÿÿü?ÿÿü?ÿÿþÿÿþÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿàÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿñÿÿÿðàààààààààààààààààààààààààààààààààààààààðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿddcui-0.3.0/icons/ddcui_multires.ico000066400000000000000000004066101427175135000174410ustar00rootroot00000000000000€€ (f hŽ ˆö   ¨•00 ¨%¸¥@@ (B`Ë(€ ¹n¹n 0FS ] `bdddddddccccccccccccccbbbbbbbbbbbbbaaaaaaaaaaaaaa````````_\ZXSJ?*µ³±QÍÊÇîÄÁ»üËÆÀÿÌÈÃÿÎÉÄÿÏËÆÿÐÌÇÿÒÍÈÿÓÏÊÿÔÐËÿÖÑÍÿ×ÒÎÿØÔÐÿÙÕÑÿÚÖÓÿÛØÔÿÜÙÕÿÞÚÖÿßÜØÿáÝÙÿãÞÛÿäáÝÿåâßÿæãáÿçåâÿéæãÿêçåÿëèæÿëéçÿíêèÿîëéÿîìêÿðíëÿðíëÿñîìÿñîìÿðîìÿðíëÿðíëÿîìêÿíëéÿìêèÿëéçÿêèåÿéçäÿèæãÿçäâÿæãàÿäâßÿäàÝÿâßÜÿáÞÚÿàÜ×ÿßÛ×ÿÝÚÕÿÜ×ÔÿÛ×ÒÿÙÕÑÿÙÓÏÿÖÒÎÿÕÑÌÿÔÐËÿÓÏÊÿÑÍÈÿÐÌÇÿÏÊÅÿÍÉÄÿÌÇÂÿÉľýÝÚØô´±¯YåâàlííëÿçäâÿçæãÿèæäÿèæäÿéæåÿéçæÿêèæÿêèæÿëéçÿëéçÿìêèÿìêèÿíìéÿîëêÿîìêÿïíìÿïíëÿïîìÿðîíÿñïíÿñïîÿòñîÿòñïÿòòïÿóóñÿóóòÿôóòÿôóòÿôóóÿõóòÿõóòÿõôòÿõôòÿõôòÿõôóÿõôóÿõôòÿõôòÿõóòÿõóóÿôóóÿôôòÿôóòÿóóñÿôòñÿóòðÿóñðÿòñïÿòðïÿñðîÿñïíÿïïíÿïîìÿîîìÿîíëÿíìêÿíìêÿìëéÿìëéÿìêèÿìêçÿêéçÿêéæÿéèæÿéèåÿèçäÿèæäÿçæãÿóòðÿàÜÛoª¥¡k…~yÿrkeÿqjdÿrjdÿrkeÿrkeÿrkeÿsleÿslfÿslfÿslfÿsmgÿsmgÿtmgÿtmgÿtmgÿtmgÿtmgÿtmgÿsmgÿsmfÿslfÿslfÿslfÿrleÿrkeÿrkeÿrjdÿtmgÿvoiÿvoiÿuniÿunhÿtmhÿtmgÿslfÿslfÿrkeÿrkeÿqjdÿpjcÿohbÿjc[ÿib[ÿia[ÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿh`Zÿjb\ÿ}wrÿ¥ œnqic#yslú{tnÿ{tnÿ|uoÿ|uoÿ|vpÿ}vpÿ}wpÿ}wqÿ~wqÿ~wqÿ~xqÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~xrÿ~wqÿ~wqÿ}wqÿ}wpÿ}vpÿ|vpÿ|uoÿ|uoÿ~xrÿ‚{vÿ{vÿzuÿ€zuÿ€ytÿytÿxsÿ~xsÿ~wrÿ~wqÿ}vqÿ}vpÿ{tnÿtmgÿsleÿrkeÿrkdÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿqjcÿpicûjc]#~wrž{tÿ‚{uÿ‚{uÿ‚|vÿƒ|vÿƒ}wÿ„}wÿ„}wÿ„~xÿ„~xÿ…~xÿ…~xÿ…yÿ…yÿ…yÿ…yÿ…yÿ…xÿ…~xÿ…~xÿ„~xÿ„~wÿ„}wÿƒ}wÿƒ}vÿ‚|vÿ‚|uÿ†zÿ‰ƒ}ÿ‰ƒ}ÿˆ‚}ÿˆ‚|ÿ‡‚|ÿ‡{ÿ†€{ÿ†€zÿ…zÿ…yÿ„~xÿ„}xÿ‚|vÿ{tnÿzslÿyrkÿxqkÿxqjÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿwpiÿunhŸ{up"‡|úˆ‚|ÿˆ‚}ÿ‰‚}ÿ‰ƒ}ÿŠƒ~ÿŠ„~ÿŠ„ÿ‹„ÿ‹…ÿ‹…€ÿ‹…€ÿ‹…€ÿŒ…€ÿŒ…€ÿŒ…€ÿŒ…€ÿ‹…€ÿ‹…€ÿ‹…ÿ‹„ÿŠ„ÿŠ„~ÿŠƒ~ÿ‰ƒ~ÿ‰ƒ}ÿ‰‚}ÿŽˆƒÿŠ…ÿ‰„ÿŽˆƒÿŽˆƒÿˆ‚ÿ‡‚ÿŒ‡ÿŒ†ÿ‹…€ÿ‹…ÿŠ„ÿŠ„ÿŠ„ÿƒ}wÿ€ysÿysÿxrÿ~wqÿ~wqÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpÿ}vpûtnh#‹„œŽˆ‚ÿˆƒÿ‰ƒÿ‰„ÿŠ„ÿŠ…ÿ‘Š…ÿ‘‹†ÿ‘‹†ÿ‘‹†ÿ’Œ†ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ‡ÿ’Œ†ÿ’‹†ÿ‘‹†ÿ‘‹†ÿ‘Š…ÿŠ…ÿŠ„ÿ‰„ÿ‰„ÿŠ„ÿ”ŽŠÿ“ˆÿ’Œ‡ÿ’Œ†ÿ‘‹…ÿ‘Š…ÿŠ„ÿ‰ƒÿ‰‚ÿŽˆ‚ÿއ‚ÿ‡ÿ‡ÿއ‚ÿ‹„ÿ†€zÿ†yÿ…~xÿ„~xÿ„}wÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿƒ|vÿztž‡‚|!”މú•‰ÿ•Šÿ–Šÿ–‹ÿ—‹ÿ—‘‹ÿ—‘Œÿ—‘Œÿ˜’Œÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜’ÿ˜‘Œÿ—‘Œÿ—‘Œÿ—‹ÿ—‘Œÿž™”ÿ¨£Ÿÿ«¦¡ÿ¡œ–ÿ›“ÿ–‰ÿ‘‹…ÿŒ…ÿˆ‚|ÿ…xÿ„}wÿ…~xÿ†yÿŠƒ|ÿˆ€ÿ’‹„ÿ–އÿ•އÿ”†ÿ‘‰ƒÿ†ÿ‹„~ÿŠƒ~ÿŠƒ}ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ÿ‰‚|ú€zs#–‹››•ÿ›•ÿœ–‘ÿœ–‘ÿ–’ÿ—’ÿ—“ÿž˜“ÿž˜“ÿž˜”ÿž˜”ÿž˜”ÿŸ™”ÿŸ˜”ÿž˜”ÿž˜”ÿž˜”ÿž˜“ÿ—“ÿ š–ÿ¨¢žÿ­¨¤ÿ œ™ÿœš—ÿš–ÿ‰…ÿŠƒ|ÿ‡ÿ‘Š‚ÿ–†ÿ˜‡ÿ™‡ÿ™†ÿ–Œÿ‘ˆ~ÿŽ…|ÿŠyÿ†wÿƒ{sÿxrÿ~wqÿ{vÿ’‹…ÿ›•ÿœ–ÿ‘Š„ÿ‰ƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿˆƒÿŒ†€’Œˆ ¡š–ù¡›–ÿ¡›—ÿ¢œ—ÿ¢œ˜ÿ£˜ÿ£™ÿ¤ž™ÿ¤žšÿ¤žšÿ¤žšÿ¥Ÿšÿ¥Ÿšÿ¥Ÿšÿ¤žšÿ¤žšÿ¤žšÿ¤ž™ÿ©¤ ÿ¦¢Ÿÿ‹‡ÿ¢ŸœÿÌÊÈÿïîíÿâàÜÿÁ½¸ÿ´°ªÿ±­§ÿ¯ª¦ÿ­¨¤ÿ­¨¤ÿ¬¨¥ÿ­¨¥ÿ­©¥ÿ­¨¦ÿ®ª¥ÿ°«¨ÿ³®©ÿµ¯ªÿ¶°©ÿ¹³¬ÿ¥Ÿ—ÿއÿ„zÿ“‹ÿ®©¥ÿ–Šÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މÿ•މúŠ„"¢˜™§¡œÿ§¡ÿ¨¡ÿ¨¢žÿ¨¢žÿ©£Ÿÿ©£Ÿÿª¤ ÿª¤ ÿª¤ ÿ«¥ ÿ«¥¡ÿ«¥ ÿª¥ ÿª¤ ÿª¤ ÿ©£Ÿÿ£ž›ÿ¯«©ÿÐÎÉÿÇÃÀÿ±­©ÿ™“ŽÿŠ…ÿ•Šÿ–Œÿ–Œÿ–‘Œÿ–‘ÿ—‘ÿ—‘Žÿ—’Žÿ—’Žÿ˜“ÿ˜“ÿ˜“ÿ˜”ÿš“ÿ’Œ‡ÿ‘‹†ÿ¥ ›ÿ±¬§ÿÁ¼·ÿÏÍÉÿ©§¤ÿ˜“ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ›”ÿ˜‘Œœ›–’«¥¡ù­§¢ÿ­§£ÿ­¨£ÿ®¨¤ÿ®©¤ÿ¯©¥ÿ¯©¥ÿ°ª¦ÿ°ª¦ÿ°«¦ÿ±«§ÿ°«¦ÿ°ª¦ÿ°ª¦ÿ¯ª¥ÿ®©¥ÿÆÄÁÿÅÁ¿ÿ—“ÿ˜’ÿ˜’ÿ™“ÿ˜”ÿŸš–ÿŸš–ÿŸš–ÿŸš–ÿ ›—ÿ ›—ÿ ›—ÿ œ˜ÿ¡œ˜ÿ¡œ˜ÿ¡œ˜ÿ¡™ÿ¢™ÿ¢™ÿŸ›–ÿ™“ÿ™“ÿ˜’ÿ˜’Œÿ®©¦ÿåäãÿ£™ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ¡š•ÿ ›•ú”Š!­©¤˜±­¨ÿ²­©ÿ²®©ÿ³®ªÿ³¯ªÿ´¯«ÿ´°«ÿ´°¬ÿµ±¬ÿµ±­ÿµ±­ÿµ±­ÿµ±¬ÿµ°¬ÿ´°¬ÿ´¯«ÿÿ¼ÿ š–ÿ¡›—ÿ¡›—ÿ¡›—ÿ¢™ÿ§¢žÿ§¢Ÿÿ§¢Ÿÿ¨£Ÿÿ¨£ ÿ¨£ ÿ¨£ ÿ¨¤ ÿ©¤ ÿ©¤¡ÿ©¤¡ÿ©¥¡ÿ©¥¡ÿª¥¢ÿª¥¢ÿª¥¡ÿ£žšÿ¡›—ÿ¡›—ÿ¡›—ÿ š–ÿª¥ ÿ¸³¯ÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ¦¡œÿ£˜œ¥Ÿ›·²®ø·²®ÿ·³¯ÿ¸³¯ÿ¸´°ÿ¹´°ÿ¹µ±ÿºµ±ÿºµ²ÿº¶²ÿ»¶²ÿº¶²ÿº¶²ÿºµ±ÿ¹µ±ÿ¹´°ÿ¾ºµÿ©£Ÿÿ©¤ ÿ©¤ ÿ©¤ ÿª¦¢ÿ¬¨¤ÿ¬¨¥ÿ¬©¥ÿ­©¦ÿ­©¦ÿ®ª¦ÿ®ª§ÿ®ª§ÿ¯«§ÿ¯«¨ÿ¯«¨ÿ¯¬¨ÿ¯¬©ÿ°­©ÿ°®ªÿ°®ªÿ­©¦ÿ©¤ ÿ©¤ ÿ©¤ ÿ©¤ ÿ°«§ÿ±«§ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ¬§¢ÿ­§£ù™” ·²®–¼¸³ÿ¼¸´ÿ½¸´ÿ½¹µÿ¾¹µÿ¾¹µÿ¾º¶ÿ¿º¶ÿ¿º¶ÿ¿º·ÿ¿º¶ÿ¿º¶ÿ¾º¶ÿ¾ºµÿ¾¹µÿ½¹µÿ¼·´ÿµ°¬ÿ²¬©ÿ²¬©ÿ«¦¢ÿ©¥¡ÿª¦¢ÿ«§£ÿ«§¤ÿ¬¨¤ÿ¬©¥ÿ­©¦ÿ­ª¦ÿ®ª§ÿ®«¨ÿ®«¨ÿ¯«¨ÿ°¬©ÿ±­ªÿ±®«ÿ±®«ÿ°¬©ÿ²¬©ÿ²¬©ÿ²¬©ÿ´®«ÿ´¯«ÿ³®©ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ²­¨ÿ¯©¥›«§¤¾¹µ¨Â½ºòľ»ÿÄ¿»ÿÄ¿»ÿÅ¿¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅÁ¼ÿÅ¿¼ÿÅ¿»ÿÄ¿»ÿÄÀ»ÿÄ¿ºÿ¾ºÿ¿¹¶ÿ±­ªÿª¦¢ÿ¬§£ÿ¬¨¤ÿ­©¥ÿ®ª¦ÿ¯ª§ÿ¯«¨ÿ°¬¨ÿ°¬©ÿ°¬©ÿ±­ªÿ±®ªÿ²®¬ÿ³¯­ÿ³¯­ÿ³¯­ÿµ±­ÿºµ±ÿ½¸³ÿ¼¶²ÿ¼¶²ÿ¼¶²ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ±ÿºµ°ÿº´°óµ°¬®¦¢ž®©¥m­©¥ÿ¯ª¦ÿ°«¨ÿ±¬©ÿ±®ªÿ²®«ÿ³¯¬ÿ´°­ÿ´±­ÿµ±®ÿµ²®ÿ¶²¯ÿ¶²°ÿ·³±ÿ·³±ÿ·³±ÿµ²¯i±­©L±­©ÿ²®ªÿ³¯¬ÿ´°­ÿ¶²®ÿ¶²¯ÿ·´°ÿ¸µ±ÿ¹µ²ÿ¹¶³ÿº¶´ÿº·´ÿ»¸µÿ»¸µÿ»¸µÿ»¸µÿ¸µ³I²­ª+µ±­ÿ¶²¯ÿ¸³°ÿ¹µ²ÿº¶³ÿ»·´ÿ¼¹µÿ½º·ÿ¾»¸ÿ¿»¹ÿÀ¼¹ÿÁ½ºÿÁ½»ÿÁ½ºÿÁ½ºÿ¾ºÿ·³°(²¯« ¾º·ÿ½º¶ÿ½º·ÿ¾º·ÿ¾º·ÿ¿»¸ÿ¿¼¹ÿÀ¼ºÿÁ½ºÿ¿»ÿÃÀ¼ÿÄÁ½ÿÄÁ¿ÿÄÁ¿ÿÅ¿ÿÇÃÁÿ¨¤  ·±­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿµ°­ÿ´°­ÿ´°­ÿ´°­ÿ´°­ÿ´°­ÿ·±®ÿ¸²¯ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿµ¯­ÿ¸²¯ÿ¼¸¶ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿ¹µ³ÿ¹µ³ÿ¹µ³ÿ¹µ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿºµ³ÿ¼¸¶ÿÁ½»ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿÓÐÏÿÐÎÎÿÎËËÿÌÈÉÿÉÆÅÿÆÂÂÿÁ¼¼ÿ¾º¹ÿ¾º¹ÿ¾º¹ÿÁ½»ÿ½»ºÿ»¹¸ÿ»¹¸ÿ»¹¸ÿÍËÌÿ…€Ñyt‹‚{v‹‚{v‹zu‹Œ…ÈÂÀ¿ÿ»¹¸ÿ»¹¸ÿ»¹¸ÿ½»ºÿ¸¸·ÿµµµÿµ´µÿµ´´ÿÁÀÁÿ»´³™»µ³†¼»»ÿµ´µÿµ´µÿµµµÿ¸¸·ÿ™——ÿ—–•ÿ—–•ÿ—–•ÿš˜˜ÿ¼¶´™¼¶´†žžÿ—–•ÿ—–•ÿ—–•ÿ™——ÿQONÿPNNÿPNNÿONMÿ[ZYÿ½·µ™½·µ†[ZYÿONMÿPNNÿPNNÿQONÿqd^ob\«ob\÷l`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿk`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿk`Zÿk_Yÿj^Xÿj^Xÿj^Xÿi^Wÿj^Xÿj_Yÿl`Zÿl`Zÿj_Yÿj^Xÿi^Wÿj^Xÿj^Xÿj^Xÿk_Yÿk`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿl`Zÿnb\÷nb\«qd^rf`«F?;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿLE@ÿrf`«vjd÷ÿÿ($!ÿ($"ÿ($!ÿ($!ÿ'#!ÿ'#!ÿ'# ÿ'" ÿ&" ÿ&" ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$!ÿ'#!ÿ)&$ÿ+(&ÿ-*(ÿ0,*ÿ2/-ÿ41/ÿ631ÿ954ÿ1.,ÿ ÿ!ÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿvjd÷wlgÿÿ)$"ÿ'#!ÿ'# ÿ'# ÿ&" ÿ&" ÿ&"ÿ&!ÿ%!ÿ%!ÿ%!ÿ$ ÿ$ ÿ$ ÿ# ÿ#ÿ#ÿ%! ÿ'$"ÿ)&$ÿ,(&ÿ.+)ÿ0-+ÿ2/-ÿ51/ÿ742ÿ:75ÿ%" ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ<87ÿ+(&ÿ'$"ÿ864ÿ/,*ÿDA?ÿTPNÿ40/ÿ$"!ÿ'$"ÿ($"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwlgÿ|qkÿÿ($"ÿ'# ÿ'# ÿ&" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$ ÿ$ ÿ$ ÿ# ÿ#ÿ#ÿ#ÿ$!ÿ&# ÿ)%#ÿ+'%ÿ-*(ÿ/,*ÿ1.,ÿ30/ÿ631ÿ853ÿ40.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB>=ÿÿJGFÿSPNÿ?<:ÿ><8ÿ@<:ÿE@?ÿSONÿ20.ÿ@<;ÿ?<;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ|qkÿ€uoÿÿ($!ÿ'# ÿ'" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$ ÿ$ ÿ$ ÿ#ÿ#ÿ#ÿ"ÿ# ÿ%" ÿ($"ÿ*'%ÿ,)&ÿ.+)ÿ0-+ÿ30.ÿ520ÿ742ÿ986ÿ(%#ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ>;9ÿ)&%ÿ(%$ÿ'%#ÿ'$"ÿ520ÿ51/ÿ2.,ÿ&"!ÿ@=:ÿ#! ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€uoÿƒzsÿÿ($!ÿ'" ÿ&" ÿ&"ÿ&"ÿ%!ÿ%!ÿ%!ÿ$!ÿ$ ÿ$ ÿ$ ÿ#ÿ#ÿ#ÿ"ÿ"ÿ"ÿ%!ÿ'$!ÿ)&#ÿ+(&ÿ-*(ÿ0,+ÿ2/-ÿ41/ÿ632ÿ964ÿ733ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒzsÿ†~xÿÿ(#!ÿ&" ÿ&"ÿ%"ÿ# ÿ"ÿ"ÿ!ÿ!ÿ!ÿ!ÿÿÿÿÿÿÿÿÿ"! ÿ$##ÿ&%%ÿ(''ÿ,)*ÿ.,,ÿ0/.ÿ221ÿ543ÿ766ÿ'&&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†~xÿŠ‚}ÿÿ'#!ÿ&"ÿ&"ÿ# ÿ£` ÿ»n(ÿ»m(ÿ»n(ÿ»n(ÿ¼n(ÿ¼n(ÿ¼n(ÿ¼n(ÿ¼p)ÿ¼p)ÿ½p*ÿ¼p*ÿ½q*ÿ¾q+ÿ¿r+ÿ¿r+ÿ¿s,ÿ¿r,ÿ¿r-ÿ¿r,ÿ¿r,ÿ¿s,ÿ¾s,ÿ¾s-ÿ¿r-ÿ¾p)ÿ¾q)ÿ¾q)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ½p)ÿ¼p)ÿ¼p)ÿ»o)ÿ»o)ÿ»o)ÿ»o)ÿ»o)ÿºo)ÿºn)ÿ¹n)ÿ¹n)ÿ¹n)ÿ¹n)ÿ¹m)ÿ¹m*ÿ¸m*ÿ¸m*ÿ¹m*ÿ¸l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l*ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹l+ÿ¹k+ÿºk+ÿºk-ÿºk-ÿºk-ÿºk-ÿºk-ÿºk,ÿºk,ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿ»k-ÿºk-ÿºk-ÿºk-ÿºk-ÿºk-ÿ¹k-ÿ¹k,ÿ¸k,ÿ¸k,ÿ¸k,ÿ¸k-ÿ·k+ÿ·k+ÿ¶j,ÿ¡^#ÿÿÿÿÿÿŠ‚}ÿ†ÿÿ'# ÿ&"ÿ%!ÿ"ÿµm'ÿÏ|1ÿÑ|1ÿÒ|1ÿÒ|1ÿÒ|1ÿÓ}1ÿÔ}1ÿÓ~1ÿÓ~2ÿÓ~2ÿÓ2ÿÓ3ÿÔ3ÿÔ4ÿÔ4ÿÕ4ÿÖ‚6ÿ׃6ÿ׃6ÿ׃7ÿ׃7ÿׄ8ÿׄ8ÿׄ8ÿׄ9ÿÖ‚4ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÕ2ÿÔ2ÿÔ2ÿÔ~2ÿÔ~2ÿÔ~2ÿÔ~2ÿÓ~2ÿÓ~2ÿÓ}2ÿÓ}2ÿÒ}2ÿÑ|2ÿÑ|2ÿÐ|2ÿÐ{2ÿÐ{2ÿÐ{2ÿÏ{2ÿÏ{2ÿÏz3ÿÏz3ÿÏz3ÿÏz3ÿÏz3ÿÏz4ÿÏy4ÿÏy4ÿÏy4ÿÏy4ÿÏy5ÿÏy5ÿÐy5ÿÐy5ÿÐy5ÿÐy5ÿÐx5ÿÐx5ÿÐx6ÿÐx6ÿÐx6ÿÑx6ÿÑx6ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑx7ÿÑw7ÿÑw7ÿÑw7ÿÐw7ÿÐw7ÿÐw7ÿÏw7ÿÏw7ÿÍw6ÿÎw6ÿÎw6ÿÍw6ÿÍw5ÿ´i,ÿÿÿÿÿÿ†ÿ“Š„ÿÿ'# ÿ%!ÿ%!ÿ"ÿ¼q)ÿÐ}1ÿÐ}1ÿÒ}1ÿÒ}1ÿÓ~1ÿÓ~1ÿÔ~1ÿÕ2ÿÕ2ÿÕ€2ÿÕ€3ÿÕ€3ÿÕ€3ÿÖ4ÿÖ4ÿÖ4ÿÖ5ÿÖ‚5ÿ׃6ÿØ„7ÿÙ„7ÿÙ„8ÿÙ…8ÿÙ…8ÿØ…9ÿØ…9ÿ×3ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿ×2ÿÖ€2ÿÖ€2ÿÖ€2ÿÖ€2ÿÖ€2ÿÕ€2ÿÕ€2ÿÔ2ÿÔ2ÿÓ2ÿÓ2ÿÒ~2ÿÒ~2ÿÑ~2ÿÑ}2ÿÐ}2ÿÐ}2ÿÐ|2ÿÐ|2ÿÏ|3ÿÏ|3ÿÏ|3ÿÏ{3ÿÏ{3ÿÏ{4ÿÏ{4ÿÏ{4ÿÏ{4ÿÏz4ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÏz5ÿÐy6ÿÐy6ÿÐy6ÿÐy6ÿÐy7ÿÐy7ÿÑy7ÿÑy7ÿÑy7ÿÑy8ÿÑy8ÿÑy8ÿÒy8ÿÑy8ÿÒy8ÿÑy8ÿÑy8ÿÑy8ÿÑy8ÿÑx8ÿÑx8ÿÐx8ÿÐx8ÿÐx8ÿÐx8ÿÏx8ÿÏx7ÿÎx7ÿÎx7ÿÎx7ÿÎx6ÿµj,ÿÿÿÿÿÿ“Š„ÿ–ˆÿÿ&" ÿ%!ÿ%!ÿ"ÿ¾s)ÿÙ„3ÿÑ2ÿÑ~2ÿÓ2ÿÔ2ÿÔ2ÿÔ2ÿÕ2ÿÖ€3ÿׂ3ÿׂ3ÿׂ4ÿׂ4ÿׂ5ÿ؃5ÿ؃5ÿ؃6ÿ؃6ÿ؃6ÿ׃7ÿ׃8ÿØ…8ÿÚ‡9ÿÚ‡9ÿÚ†:ÿÚ†:ÿÚ„7ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿÙ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ‚3ÿØ3ÿ×3ÿ×3ÿ×3ÿÖ3ÿÖ€3ÿÕ€3ÿÕ€3ÿÔ€3ÿÔ3ÿÓ3ÿÓ~3ÿÒ~3ÿÒ~3ÿÑ}3ÿÑ}4ÿÑ}4ÿÑ}4ÿÐ}4ÿÐ}4ÿÐ|4ÿÐ|5ÿÐ|5ÿÐ|5ÿÐ|5ÿÐ{5ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{6ÿÐ{7ÿÐz7ÿÐz7ÿÑz7ÿÑz8ÿÑz8ÿÑz8ÿÒz8ÿÒz8ÿÒz9ÿÒz9ÿÒz9ÿÓz9ÿÓz9ÿÓz9ÿÓz:ÿÓz:ÿÓz:ÿÓy:ÿÒy:ÿÒy:ÿÒy:ÿÒy:ÿÑy:ÿÑy9ÿÑy9ÿÑy9ÿÐy9ÿÐy9ÿÏy8ÿÐy8ÿ¶j-ÿÿÿÿÿÿ–ˆÿš“ÿÿ&" ÿ%!ÿ%!ÿ!ÿÀt*ÿ܆4ÿÛ…4ÿÓ€3ÿÒ3ÿÕ€3ÿÖ€3ÿÖ3ÿÖ3ÿÖ4ÿׂ4ÿÙƒ4ÿÙƒ5ÿÙƒ5ÿÙ„5ÿÚ„6ÿÚ„6ÿÚ„7ÿÚ„7ÿÚ…7ÿÚ…8ÿÙ…8ÿÙ…8ÿØ…9ÿÙ†:ÿÚ‡:ÿ܈;ÿ܈;ÿÛ„5ÿÛ„4ÿÛ„4ÿÛ„4ÿÛ„4ÿÛ„4ÿÚ„4ÿÚ„4ÿÚ„4ÿÚ„4ÿÚƒ4ÿÚƒ4ÿÙƒ4ÿÙƒ4ÿÙƒ4ÿ؃4ÿØ‚4ÿׂ4ÿׂ4ÿÖ‚4ÿÖ4ÿÖ4ÿÕ4ÿÕ€4ÿÔ€4ÿÔ4ÿÓ4ÿÓ4ÿÒ~5ÿÒ~5ÿÒ~5ÿÒ~5ÿÒ~5ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ}6ÿÑ|6ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|7ÿÑ|8ÿÒ|8ÿÒ{8ÿÒ{9ÿÓ{9ÿÓ{9ÿÓ{9ÿÓ{:ÿÔ{:ÿÔ{:ÿÔ{:ÿÔ{:ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔ{;ÿÔz;ÿÔz;ÿÔz;ÿÓz;ÿÓz;ÿÓz;ÿÒz;ÿÒz;ÿÒz:ÿÑz:ÿÒz:ÿ¸k.ÿÿÿÿÿÿš“ÿž—’ÿÿ&" ÿ%!ÿ$ ÿ!ÿÁv+ÿ݈5ÿ܇5ÿ܇5ÿÔ‚4ÿÒ€4ÿÕ‚4ÿׂ3ÿׂ3ÿׂ3ÿׂ4ÿ؃4ÿÙ„6ÿÚ…6ÿÚ…6ÿÚ†7ÿÛ†7ÿÛ†7ÿÛ†8ÿÛ‡8ÿÛ‡9ÿÛ‡9ÿÚ‡9ÿÚ‡:ÿÚ‡:ÿÙ‡:ÿ؆;ÿÚ‡;ÿÛ‡9ÿ܆5ÿ܆5ÿ܆5ÿÜ…5ÿÜ…5ÿÜ…5ÿÜ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÛ…5ÿÚ…5ÿÚ„5ÿÚ„5ÿÙ„5ÿÙ„5ÿÙ„5ÿ؃5ÿ؃5ÿ׃5ÿׂ5ÿÖ‚5ÿÖ‚5ÿÕ5ÿÕ5ÿÕ5ÿÔ€5ÿÔ€6ÿÓ€6ÿÓ6ÿÓ6ÿÒ6ÿÒ7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ~7ÿÒ}8ÿÒ}8ÿÑ}8ÿÒ}8ÿÒ}8ÿÒ}9ÿÒ}9ÿÓ}9ÿÓ}:ÿÓ|:ÿÓ|:ÿÔ|:ÿÔ|;ÿÔ|;ÿÔ|;ÿÕ|;ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|<ÿÕ|=ÿÕ|=ÿÕ{=ÿÕ{=ÿÕ{=ÿÕ{=ÿÔ{<ÿÔ{<ÿÔ{<ÿÓ{<ÿÓ{<ÿÓ{<ÿÓ{;ÿ¹l0ÿÿÿÿÿÿž—’ÿ¢›–ÿÿ&"ÿ$ ÿ$ ÿ!ÿÂv+ÿÞˆ6ÿÞ‰6ÿÞˆ6ÿ݈6ÿÖƒ5ÿÓ‚4ÿÖƒ5ÿ׃4ÿ؃4ÿ؃5ÿØ„5ÿØ…5ÿÚ…6ÿÛ†7ÿÛ‡8ÿ܇8ÿ܇8ÿ܇9ÿ܇9ÿ܈9ÿ܈:ÿ܈:ÿ܈;ÿ܉;ÿÛ‰;ÿÛ‰<ÿÛ‰<ÿÚ‰<ÿØ…6ÿÙ„5ÿÚ…5ÿ܆6ÿ݇6ÿ݇6ÿ܇5ÿ܇5ÿ܇5ÿ܆5ÿ܆5ÿ܆5ÿ܆5ÿÛ†5ÿÛ†5ÿÛ†5ÿÚ…6ÿÚ…6ÿÙ…6ÿÙ…5ÿÙ„6ÿØ„6ÿØ„6ÿ׃6ÿ׃6ÿ׃6ÿÖƒ6ÿÖ‚6ÿÕ‚6ÿÕ7ÿÔ7ÿÔ7ÿÔ€7ÿÓ€7ÿÓ€7ÿÓ€8ÿÓ€8ÿÒ8ÿÒ8ÿÒ8ÿÒ8ÿÒ~9ÿÒ~9ÿÒ~9ÿÓ~9ÿÓ~:ÿÓ~:ÿÓ~;ÿÔ};ÿÔ};ÿÔ};ÿÕ}<ÿÕ}<ÿÕ}<ÿÕ}<ÿÕ}=ÿÖ}=ÿÖ}=ÿÖ}=ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ|>ÿÖ|>ÿÖ|>ÿÖ|>ÿÕ|>ÿÕ|>ÿÕ|>ÿÕ|>ÿÔ|>ÿÔ|=ÿÓ|=ÿºm3ÿÿÿÿÿÿ¢›–ÿ¦ šÿÿ%!ÿ$ ÿ$ ÿÿÂx,ÿ߉6ÿÞŠ7ÿߊ7ÿߊ7ÿÞŠ7ÿÖ„5ÿÔƒ5ÿÖ„5ÿØ„5ÿÙ„6ÿÙ…6ÿÙ†6ÿÙ†7ÿÚ†7ÿ܇8ÿ܉9ÿ݉9ÿ݈9ÿ݈:ÿÝŠ:ÿ݉;ÿ݉;ÿ݉;ÿÝŠ<ÿÝŠ<ÿÜŠ<ÿÜŠ<ÿÜŠ<ÿ܉;ÿÛ†5ÿÙ…5ÿØ…5ÿÙ…6ÿÛ†6ÿ݈7ÿ݈7ÿ݈7ÿ݈7ÿ݈6ÿ݈6ÿ݈6ÿ܈6ÿ܇6ÿ܇6ÿ܇6ÿÛ‡7ÿÛ‡7ÿÚ†7ÿÚ†7ÿÚ†7ÿÙ†6ÿÙ…6ÿÙ…7ÿØ…7ÿØ„7ÿׄ7ÿׄ7ÿÖƒ7ÿÖƒ7ÿÖƒ8ÿÕ‚8ÿÕ‚8ÿÔ8ÿÔ8ÿÓ8ÿÓ8ÿÓ€9ÿÓ€9ÿÓ€9ÿÓ€9ÿÓ€:ÿÓ:ÿÓ:ÿÓ;ÿÔ;ÿÔ;ÿÔ<ÿÕ~<ÿÕ~<ÿÕ~=ÿÕ~=ÿÖ~=ÿÖ~=ÿÖ~>ÿÖ~>ÿÖ~>ÿÖ~>ÿÖ~?ÿ×~?ÿ×~?ÿ×~?ÿ×~?ÿ×}?ÿ×}?ÿ×}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÖ}?ÿÕ}?ÿÕ}>ÿ»n4ÿÿÿÿÿÿ¦ šÿª£žÿÿ%!ÿ$ ÿ# ÿÿÃx,ÿߊ7ÿà‹7ÿà‹7ÿàŒ7ÿà‹7ÿà‹7ÿ×…6ÿÖ„5ÿØ…5ÿÙ…6ÿÚ‡6ÿÚ‡6ÿÚ‡7ÿÚ‡7ÿÛ‡7ÿ܉9ÿÞŠ9ÿߊ:ÿÞŠ:ÿߊ:ÿÞ‹;ÿÞ‹;ÿÞ‹;ÿÞ‹<ÿÞŒ<ÿÞŒ=ÿÞŒ=ÿÞŒ=ÿÞŒ>ÿ݉9ÿ݇6ÿ܇6ÿ܇6ÿÛ†6ÿÙ†5ÿÙ†6ÿÛ‡6ÿ݈7ÿߊ7ÿ߉7ÿÞ‰7ÿÞ‰7ÿÞ‰7ÿÞ‰7ÿ݉7ÿ݈7ÿ݈7ÿ܈7ÿ܈7ÿ܇7ÿÛ‡7ÿÛ‡7ÿÛ‡7ÿÚ†7ÿÚ†7ÿÚ†7ÿÙ…7ÿÙ…7ÿØ…7ÿØ„8ÿØ„8ÿׄ8ÿ׃8ÿÖƒ8ÿÖ‚8ÿÕ‚9ÿÕ‚9ÿÕ‚9ÿÕ9ÿÕ9ÿÕ:ÿÕ:ÿÕ:ÿÕ;ÿÕ€;ÿÕ€;ÿÖ€<ÿÖ€<ÿÖ€<ÿÖ=ÿ×=ÿ×=ÿ×>ÿ×>ÿ×>ÿØ>ÿØ?ÿØ?ÿØ?ÿØ?ÿØ@ÿØ@ÿÙ~@ÿÙ~@ÿÙ~@ÿØ~@ÿØ~@ÿØ~@ÿØ~@ÿØ~@ÿ×~@ÿ×~@ÿ½p5ÿÿÿÿÿÿª£žÿ­¨¢ÿÿ%!ÿ# ÿ#ÿÿÃx-ÿà‹8ÿàŒ8ÿáŒ8ÿá8ÿá8ÿá8ÿáŒ8ÿ׆6ÿÖ…6ÿÙ†6ÿÙ‡7ÿÛˆ7ÿÛˆ8ÿÛˆ8ÿÛˆ8ÿÛ‰9ÿÞŠ9ÿß‹:ÿß‹;ÿß‹;ÿߌ<ÿߌ<ÿߌ<ÿߌ=ÿß=ÿß=ÿß>ÿß>ÿß>ÿÞ>ÿ݉7ÿ݉7ÿ݉7ÿ݉7ÿ݈7ÿ܈6ÿÛˆ6ÿÚ‡6ÿÙ†6ÿÚ‡7ÿÛˆ7ÿÞŠ8ÿß‹8ÿߊ8ÿÞŠ8ÿÞŠ8ÿÞŠ8ÿÞŠ8ÿ݉8ÿ݉8ÿ݉8ÿ܉8ÿ܈8ÿ܈8ÿÛˆ8ÿÛˆ8ÿÛ‡8ÿÚ‡8ÿÚ†8ÿÚ†8ÿÙ†8ÿÙ†9ÿØ…9ÿØ…9ÿׄ9ÿׄ9ÿÖƒ9ÿÖƒ:ÿÕƒ:ÿÕƒ:ÿÕ‚:ÿÕ‚;ÿÕ‚;ÿÕ‚;ÿÖ‚<ÿÖ<ÿÖ<ÿÖ=ÿ×=ÿ×=ÿ×>ÿ×€>ÿ×€>ÿ×€?ÿØ€?ÿØ€?ÿØ€@ÿØ€@ÿÙ€@ÿÙ€@ÿÙ€AÿÙ€AÿÙAÿÙAÿÙAÿÙBÿÙBÿÙBÿÙBÿÙBÿÙBÿÙBÿ¾p6ÿÿÿÿÿÿ­¨¢ÿ±¬§ÿÿ$!ÿ#ÿ#ÿÿÃz-ÿàŒ9ÿà9ÿáŽ9ÿâŽ9ÿâŽ9ÿâŽ9ÿâŽ9ÿáŽ9ÿׇ7ÿ׆7ÿÙˆ8ÿÚˆ8ÿÛ‰8ÿ܉9ÿ܉9ÿÜŠ:ÿÝŠ:ÿÝ‹:ÿß‹;ÿàŒ<ÿà<ÿà=ÿà=ÿà=ÿà>ÿàŽ>ÿà?ÿàŽ?ÿàŽ?ÿß?ÿߌ;ÿÞŠ7ÿÞŠ7ÿÞŠ7ÿÞŠ7ÿÝŠ7ÿÝŠ7ÿ݉7ÿ݉7ÿ܉7ÿÛˆ7ÿÙ‡7ÿÙ‡7ÿÚˆ8ÿ܉8ÿÞ‹9ÿß‹9ÿß‹9ÿÞ‹8ÿÞ‹8ÿÞŠ8ÿÝŠ9ÿÝŠ9ÿÝŠ9ÿ܉9ÿ܉9ÿ܉9ÿ܉9ÿÛˆ9ÿÛˆ9ÿÚˆ9ÿÚ‡9ÿÙ‡:ÿÙ‡:ÿÙ†:ÿ؆:ÿØ…:ÿ×…:ÿ×…;ÿÖ„;ÿÖ„;ÿÖ„;ÿÖƒ<ÿÖƒ<ÿÖƒ<ÿÖƒ=ÿׂ=ÿׂ=ÿׂ>ÿׂ>ÿׂ>ÿ×?ÿØ?ÿØ?ÿØ@ÿØ@ÿØ@ÿÙAÿÙAÿÙAÿÙAÿÙBÿÚBÿÚ€BÿÚ€BÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚ€CÿÚCÿ¿p8ÿÿÿÿÿÿ±¬§ÿ²®©ÿÿ$ ÿ#ÿ#ÿÿÃ{.ÿà9ÿáŽ:ÿá:ÿâ:ÿâ:ÿâ:ÿã:ÿâ:ÿá:ÿׇ8ÿ؈9ÿÚŠ9ÿÚŠ9ÿÛŠ:ÿÜŠ:ÿÜ‹:ÿÝŒ;ÿÞŒ;ÿÞŒ<ÿß<ÿàŽ<ÿà>ÿà>ÿà>ÿá?ÿà?ÿà?ÿà?ÿà?ÿà@ÿà?ÿߌ8ÿß‹8ÿß‹8ÿß‹8ÿß‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÞ‹8ÿÝŠ8ÿÝŠ8ÿÛ‰8ÿÚ‰8ÿ؈8ÿ؈8ÿÚ‰9ÿÛŠ9ÿÞ‹9ÿߌ:ÿÞŒ:ÿÞŒ9ÿÞ‹9ÿÝ‹:ÿÝ‹:ÿÝŠ:ÿÝŠ:ÿÜŠ:ÿÜŠ:ÿÛ‰:ÿÛ‰:ÿÛ‰:ÿÚˆ:ÿÚˆ;ÿÚˆ;ÿÙ‡;ÿÙ‡;ÿ؇;ÿ؆;ÿ×…<ÿ×…<ÿ×…<ÿ×…<ÿׄ=ÿׄ=ÿׄ>ÿׄ>ÿ׃>ÿ׃?ÿ׃?ÿ؃?ÿ؃@ÿØ‚@ÿØ‚@ÿØ‚AÿÙ‚AÿÙ‚AÿÙ‚BÿÙ‚BÿÙ‚BÿÚ‚BÿÚ‚CÿÚCÿÚCÿÚCÿÚDÿÚDÿÚDÿÚDÿÚDÿÛ‚Dÿ¿q8ÿÿÿÿÿÿ²®©ÿ³¯ªÿÿ$ ÿ#ÿ"ÿÿÄ|/ÿáŽ:ÿá:ÿâ;ÿâ;ÿã;ÿã‘;ÿã‘;ÿã‘;ÿã‘;ÿâ:ÿ؉9ÿÚŠ:ÿÛ‹:ÿÚ‹;ÿÛ‹;ÿÝŒ;ÿÝ<ÿÞ<ÿÞ<ÿÞ=ÿß=ÿá>ÿá>ÿá>ÿá?ÿá?ÿá‘?ÿá‘@ÿá‘@ÿá‘@ÿá‘Aÿá=ÿà9ÿà9ÿà9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿߌ9ÿÞŒ9ÿÞŒ9ÿÞ‹9ÿÝ‹9ÿÝ‹9ÿÝŠ9ÿÜŠ9ÿÚ‰9ÿÙˆ9ÿ؈9ÿÙ‰9ÿÛŠ:ÿÝŒ:ÿß;ÿߌ;ÿÞŒ;ÿÞŒ;ÿÞ‹;ÿÝ‹;ÿÝ‹;ÿÝ‹;ÿÜŠ;ÿÜŠ;ÿÜŠ;ÿÛ‰;ÿÛ‰<ÿÚˆ<ÿÚˆ<ÿÚˆ<ÿÙ‡<ÿÙ‡=ÿ؆=ÿ؆=ÿ؆=ÿ؆>ÿØ…>ÿØ…?ÿØ…?ÿØ„?ÿØ„@ÿØ„@ÿØ„@ÿØ„Aÿ؃AÿÙƒAÿÙƒAÿÙƒBÿÙƒBÿÙƒCÿÚƒCÿÚƒCÿÚƒCÿÚƒDÿÚ‚DÿÛ‚DÿÛ‚EÿÛ‚EÿÛ‚EÿÛ‚EÿÛ‚Fÿ܃FÿÁr8ÿÿÿÿÿÿ³¯ªÿ³°«ÿÿ$ ÿ"ÿ"ÿÿÄ|/ÿá:ÿâ:ÿâ;ÿã‘;ÿã‘;ÿä‘;ÿä’;ÿä’;ÿå’;ÿå’;ÿá;ÿØŠ:ÿÛ‹:ÿÜŒ;ÿÛŒ;ÿÛ‹;ÿÞŽ<ÿߎ<ÿߎ<ÿàŽ=ÿàŽ=ÿà=ÿá>ÿâ‘?ÿã’@ÿã‘@ÿã’?ÿã’@ÿã’@ÿâ’@ÿâ’Aÿâ“Aÿá;ÿáŽ9ÿáŽ9ÿáŽ9ÿáŽ9ÿáŽ9ÿà9ÿà9ÿà9ÿà9ÿà9ÿß9ÿß9ÿߌ9ÿÞŒ9ÿÞŒ9ÿÞŒ9ÿÞŒ9ÿÝ‹9ÿÜ‹9ÿÛŠ9ÿÙ‰9ÿ؈9ÿ؉:ÿÚŠ:ÿÛ‹:ÿÝŒ;ÿß;ÿÞ;ÿÞŒ;ÿÞŒ;ÿÞŒ;ÿÝ‹;ÿÝ‹<ÿÜ‹<ÿÜŠ<ÿÜŠ<ÿÛŠ<ÿÛ‰<ÿÚ‰=ÿÚˆ=ÿÚˆ=ÿÙ‡=ÿÙ‡>ÿÙ‡>ÿÙ†>ÿÙ†?ÿÙ†?ÿÙ†@ÿÙ…@ÿÙ…@ÿÙ…@ÿÙ…AÿÙ„AÿÚ„AÿÚ„BÿÚ„BÿÚ„BÿÚ„CÿÛ„CÿÛ„CÿÛ„DÿÛ„DÿÛƒDÿ܃Eÿ܃Eÿ܃Eÿ܃Eÿ܃FÿÝ„FÿÁs9ÿÿÿÿÿÿ³°«ÿ´°¬ÿÿ# ÿ"ÿ"ÿÿÄ}0ÿá‘;ÿâ‘;ÿâ‘<ÿã’<ÿã’<ÿä’<ÿä“<ÿå“<ÿå“<ÿå“<ÿå“<ÿá<ÿÙ‹;ÿÜ;ÿÝ<ÿÜ<ÿÜ=ÿÞŽ<ÿà<ÿà=ÿà=ÿà=ÿà>ÿá>ÿâ’?ÿã“@ÿã“@ÿã”Aÿã”Aÿã”Aÿã”Bÿã”Bÿâ“@ÿâ:ÿâ:ÿá:ÿá:ÿá:ÿá:ÿá:ÿá:ÿáŽ:ÿàŽ:ÿàŽ:ÿàŽ:ÿàŽ:ÿߎ:ÿߎ:ÿß:ÿÞ:ÿÞ:ÿÞ:ÿÞŒ:ÿÝŒ:ÿÝ‹:ÿÜ‹:ÿÛ‹:ÿÚ‰:ÿ؉:ÿ׈:ÿ؉;ÿÙŠ;ÿÛ‹;ÿÜŒ<ÿÞ<ÿÞŒ<ÿÞŒ<ÿÝŒ<ÿÝ‹=ÿÜ‹=ÿÜ‹=ÿÜŠ=ÿÛŠ=ÿÛ‰>ÿÛ‰>ÿÚˆ>ÿÚˆ?ÿÚˆ?ÿÚˆ?ÿÙ‡@ÿÙ‡@ÿÙ‡@ÿÙ†AÿÚ†AÿÚ†AÿÚ†BÿÚ†BÿÚ…BÿÚ…CÿÚ…CÿÚ…CÿÛ…DÿÛ…DÿÛ…DÿÛ…EÿÛ…EÿÜ„EÿÜ„EÿÜ„FÿÜ„FÿÜ„FÿÝ„GÿÂt9ÿÿÿÿÿÿ´°¬ÿ´±­ÿÿ#ÿ"ÿ"ÿÿÄ}0ÿá‘<ÿá‘<ÿâ’<ÿã’<ÿã“=ÿä“=ÿä”=ÿå”=ÿå”=ÿå”=ÿå”=ÿæ”>ÿß=ÿÚŒ;ÿÜŽ=ÿÝŽ<ÿÝŽ<ÿÝ=ÿÞ=ÿà>ÿá>ÿá>ÿá‘?ÿá‘?ÿá‘?ÿá’@ÿã“Aÿä•Aÿä•Bÿä•Bÿä•Bÿä•Cÿã–Cÿã’=ÿâ‘;ÿâ‘;ÿâ;ÿâ;ÿâ;ÿâ;ÿá;ÿá;ÿá;ÿá;ÿá;ÿà;ÿà;ÿà;ÿà;ÿß;ÿߎ;ÿߎ;ÿÞŽ;ÿÞŽ;ÿÞ;ÿÞ;ÿÝ;ÿÝŒ;ÿÜŒ;ÿÜŒ;ÿÛ‹;ÿÚ‹;ÿÙŠ;ÿ׉;ÿÖˆ;ÿ׉<ÿ؉<ÿÙŠ<ÿÚ‹=ÿÛŒ=ÿÝŒ>ÿÝŒ>ÿÜŒ>ÿÜ‹>ÿÜ‹>ÿÛŠ?ÿÛŠ?ÿÛ‰?ÿÚ‰@ÿÚ‰@ÿÚˆ@ÿÚˆAÿÚˆAÿÚˆAÿÚ‡BÿÚ‡BÿÚ‡BÿÚ†CÿÚ†CÿÚ†CÿÚ†DÿÛ†DÿÛ†DÿÛ†EÿÛ†EÿÛ…EÿÜ…FÿÜ…FÿÜ…FÿÜ…GÿÜ…GÿÞ…GÿÂu:ÿÿÿÿÿÿ´±­ÿµ±®ÿÿ#ÿ"ÿ!ÿÿÄ~1ÿá’=ÿâ’=ÿâ“=ÿã“=ÿä”=ÿä”=ÿä”>ÿå•>ÿå•>ÿå•>ÿæ•>ÿæ•?ÿæ–?ÿÞ=ÿÛŽ=ÿÞ=ÿÞ=ÿÞ>ÿÞ>ÿÞ>ÿà‘?ÿá‘?ÿá’@ÿá“@ÿá“@ÿá“Aÿâ“Aÿã•Aÿä–Cÿä–Cÿä–Cÿä–Dÿä–Dÿä–Cÿã’<ÿã’<ÿã’<ÿã’<ÿã’<ÿã’<ÿâ‘<ÿâ‘<ÿâ‘<ÿâ‘<ÿâ‘<ÿá‘<ÿá<ÿá<ÿá<ÿà<ÿà<ÿà<ÿà<ÿß<ÿß<ÿß<ÿÞŽ<ÿÞŽ<ÿÞŽ<ÿÝ<ÿÝ<ÿÜ<ÿÜŒ<ÿÜŒ<ÿÛ‹=ÿÛ‹=ÿÚŠ=ÿÙŠ=ÿ؉=ÿ׈=ÿÖˆ=ÿÖˆ>ÿ׉>ÿ؉>ÿ؉>ÿÙŠ?ÿÚ‹?ÿÜ‹@ÿÛ‹@ÿÛŠAÿÛŠAÿÛ‰AÿÚ‰AÿÚ‰BÿÚ‰BÿÚˆBÿÚˆCÿÚˆCÿÚˆCÿÛ‡DÿÛ‡DÿÛ‡DÿÛ‡EÿÛ‡EÿÛ‡FÿÛ‡FÿÛ†Fÿ܆Fÿ܆Gÿ܆Gÿ܆GÿÞ…HÿÂu:ÿÿÿÿÿÿµ±®ÿµ²¯ÿÿ#ÿ!ÿ!ÿÿÄ~1ÿá“>ÿâ“>ÿã“>ÿã”>ÿä”>ÿå•>ÿå•>ÿæ–?ÿæ–?ÿæ–?ÿç–?ÿç–?ÿç—@ÿæ—@ÿÜ>ÿÝ>ÿß‘>ÿß‘?ÿß‘?ÿß‘?ÿÞ@ÿà‘@ÿâ“@ÿâ”Aÿã”Aÿã”Aÿã”Bÿã”Bÿã•Cÿä–Dÿæ—Dÿå—Dÿæ—Eÿå˜Eÿå•@ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿä“=ÿã’=ÿã’=ÿã’=ÿã’=ÿâ’=ÿâ’=ÿâ’=ÿâ‘=ÿá‘=ÿá‘=ÿá‘=ÿà=ÿà=ÿà=ÿß=ÿß=ÿß=ÿÞ=ÿÞŽ=ÿÞŽ=ÿÝŽ=ÿÝ=ÿÜ=ÿÜ>ÿÜŒ>ÿÛŒ>ÿÛ‹>ÿÚ‹>ÿÚŠ>ÿÙŠ?ÿÙ‰?ÿ؈?ÿ׈?ÿÖ‡?ÿÕ‡?ÿÖ‡@ÿÖ‡@ÿÖ‡Aÿ׈Aÿ؈AÿÙˆBÿÙ‰BÿÚ‰CÿÛ‰CÿÛ‰DÿÛ‰DÿÛ‰DÿÛˆDÿ܈Eÿ܈Eÿ܈Fÿ܈Fÿ܈Fÿ܇Gÿ܇Gÿ݇Gÿ݇Hÿ݇HÿÞ†HÿÂv;ÿÿÿÿÿÿµ²¯ÿ¶³°ÿÿ"ÿ!ÿ!ÿÿÄ2ÿá“>ÿâ”>ÿã”>ÿã•>ÿä•>ÿå•>ÿå–>ÿæ–?ÿæ–?ÿæ—?ÿç—?ÿç—@ÿç—@ÿç™@ÿæ˜@ÿÛ?ÿÞ>ÿà’?ÿß“?ÿà’?ÿß’@ÿß‘@ÿß’@ÿâ”Aÿã•Aÿã•Bÿã•Bÿã•Bÿã–Cÿã–Cÿä–Dÿå˜Eÿæ˜Eÿæ™Eÿæ™Eÿå”>ÿå”=ÿå”=ÿå”=ÿå”=ÿä”=ÿä”=ÿä”=ÿä”=ÿä“=ÿä“=ÿã“=ÿã“=ÿã“=ÿã“=ÿã“=ÿã“=ÿâ“=ÿâ’=ÿá’=ÿá‘=ÿá‘=ÿà‘=ÿà‘=ÿà=ÿß=ÿß=ÿß=ÿÞ=ÿÞ=ÿÝ=ÿÝŽ=ÿÝŽ>ÿÜ>ÿÜ>ÿÛŒ>ÿÛŒ>ÿÚŒ?ÿÚ‹?ÿÚ‹?ÿÙŠ?ÿÙŠ@ÿÙ‰@ÿ؉@ÿ؈Aÿ׈AÿׇAÿׇBÿÖ†BÿÖ†BÿÖ…CÿÕ…CÿÕ…DÿÕ…DÿÖ†Dÿ׆Dÿ×…Eÿ؆Eÿ؆EÿÙ†FÿÙ‡FÿÚ‡FÿÚ‡GÿÛ‡GÿÛ‡Gÿ܇Hÿ݈HÿÁw;ÿÿÿÿÿÿ¶³°ÿ¶´±ÿÿ"ÿ!ÿ ÿÿÄ2ÿá”>ÿá”?ÿâ•?ÿã•?ÿä–?ÿä–?ÿå—?ÿå—?ÿæ—@ÿæ˜@ÿç˜@ÿç˜@ÿç˜Aÿç™AÿèšAÿä—AÿÛ?ÿß’@ÿà”@ÿá“@ÿà“Aÿà“Aÿß“Aÿß“Bÿâ•Bÿã–Bÿä–Cÿä–Cÿä–Cÿä—Dÿä—Dÿä—Dÿå˜Fÿæ™FÿæšFÿæ˜Cÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿå•>ÿä•>ÿä•>ÿä”>ÿä”>ÿä•>ÿä”>ÿä”>ÿã”>ÿã”>ÿã”>ÿã”>ÿâ“>ÿâ“>ÿá’>ÿá’>ÿá’>ÿà’>ÿà‘>ÿß‘>ÿß‘>ÿß>ÿÞ>ÿÞ>ÿÝ>ÿÝ>ÿÝŽ?ÿÜŽ?ÿÜŽ?ÿÛ?ÿÛ?ÿÛŒ@ÿÚŒ@ÿÚ‹@ÿÙ‹@ÿÙŠAÿÙŠAÿÙŠBÿ؉Bÿ؉Bÿ؈Cÿ׈CÿׇDÿׇDÿׇEÿ׆Eÿ׆Eÿ׆Fÿ×…Fÿ×…Gÿ×…Gÿ×…Gÿ×…Hÿ×…Hÿ×…HÿØ…IÿØ…IÿØ„JÿÙ„Jÿ¾u<ÿÿÿÿÿÿ¶´±ÿ·´²ÿÿ"ÿ ÿ ÿÿÀ3ÿá•?ÿá•?ÿâ•?ÿã–?ÿä–@ÿä—@ÿä—@ÿå˜@ÿæ˜@ÿæ˜@ÿæ˜@ÿç™Aÿç™Bÿç™BÿèšBÿè›Cÿá–BÿÝ’@ÿß”Aÿà•Aÿá”Aÿá”Bÿà”Bÿà”Bÿß”Cÿá•Cÿã—Dÿä—Dÿä—Dÿä˜Eÿä˜Eÿä™Eÿå˜Fÿå˜Fÿæ›Fÿç›Gÿæ—@ÿæ—?ÿæ–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿå–?ÿä–?ÿä–?ÿä–?ÿä–?ÿä–?ÿä•?ÿä•?ÿä•?ÿä•?ÿã•?ÿâ”?ÿá“>ÿá“?ÿá“?ÿà“?ÿà’?ÿß’?ÿß’?ÿß‘?ÿÞ‘?ÿÞ?ÿÝ?ÿÝ?ÿÝ?ÿÜ@ÿÜŽ@ÿÛŽ@ÿÛ@ÿÛ@ÿÚAÿÚŒAÿÚŒAÿÙ‹BÿÙ‹BÿÙŠCÿØŠCÿ؉Cÿ؉Dÿ؉Dÿ׈Eÿ׈EÿׇEÿׇFÿׇFÿ׆Gÿ׆Gÿ׆Hÿ׆Hÿ؆Iÿ؆Iÿ؆IÿØ…JÿÙ†JÿÚ…Kÿ¿u=ÿÿÿÿÿÿ·´²ÿ·µ³ÿÿ!ÿ ÿ ÿÿÄ€4ÿá”@ÿâ•@ÿâ–@ÿã—@ÿä—@ÿå—Aÿå˜Aÿæ˜Aÿæ™Aÿç™Aÿç™AÿçšAÿèšBÿèšCÿè›Cÿé›DÿéœDÿß”Bÿß”Bÿá•Bÿâ–Bÿâ•Cÿâ•Cÿâ•Cÿá–Dÿà•Dÿà•Dÿä—Eÿå˜Eÿæ™Eÿæ™FÿæšFÿæšFÿæšGÿæšGÿæ›HÿçšEÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿç˜@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå—@ÿå–@ÿä•?ÿâ”?ÿâ”?ÿâ”?ÿá“?ÿá“@ÿà“@ÿà’@ÿà’@ÿß’@ÿß‘@ÿÞ‘@ÿÞ@ÿÞ@ÿÝAÿÝAÿÜAÿÜŽAÿÜŽBÿÛBÿÛBÿÚŒBÿÚŒCÿÚŒCÿÚ‹DÿÙ‹DÿÙŠDÿÙŠEÿÙ‰Eÿ؉Fÿ؈Fÿ؈Gÿ؈Gÿ؇Gÿ؇Hÿ؇Hÿ؇Iÿ؇IÿÙ‡JÿÙ‡JÿÙ‡JÿÚ†KÿÀv=ÿÿÿÿÿÿ·µ³ÿ¸¶´ÿÿ!ÿ ÿ ÿÿÃ4ÿá•Bÿá–Aÿâ—Aÿã—Aÿä˜Aÿä˜Aÿå˜Aÿå™Bÿæ™Bÿæ™BÿçšBÿçšBÿçšBÿè›CÿèœCÿèœDÿéœEÿèœDÿÞ”Cÿà•Cÿâ—Cÿã—Dÿã–Dÿã—Dÿâ—Eÿâ—Eÿá–Eÿà–Fÿã—FÿåšFÿæ›Gÿæ›Gÿæ›Gÿæ›Hÿæ›HÿæœHÿæœIÿæ™Bÿç˜Aÿè™Aÿè™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç™Aÿç˜Aÿç˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿå˜Aÿå˜Aÿå˜Aÿå—Aÿä–@ÿã•@ÿâ•@ÿâ•@ÿá”@ÿá”Aÿà”Aÿà“Aÿà“Aÿß“Aÿß’Aÿß’AÿÞ‘AÿÞ‘AÿÝBÿÝBÿÜBÿÜBÿÜBÿÛŽCÿÛŽCÿÛCÿÚDÿÚŒDÿÚŒEÿÚ‹EÿÙ‹EÿÙŠFÿÙŠFÿØŠGÿ؉Gÿ؉Hÿ؉Hÿ؈Hÿ؈Iÿ؈Iÿ؈JÿÙˆJÿÙ‡KÿÚ‡Kÿ¿v=ÿÿÿÿÿÿ¸¶´ÿ¸·µÿÿ!ÿ ÿÿÿÃ4ÿà•Bÿá–Bÿâ–Bÿâ—Bÿã—Bÿä˜Bÿä˜Bÿå™Bÿå™Bÿæ™BÿæšCÿçšCÿçšCÿè›DÿèœDÿèœDÿèœEÿéFÿåšEÿÞ•Cÿá—Cÿã—Dÿã—Dÿã—Dÿã˜Eÿã—Eÿâ—Eÿâ—Fÿá—Fÿá—FÿåšGÿæ›Hÿæ›Hÿç›Iÿç›IÿçœIÿçœJÿæ›Hÿæ˜Aÿç™Aÿè™Bÿè™Bÿè™Bÿè™Bÿè™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿç™Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿæ˜Bÿå—Aÿã–Aÿâ•Aÿâ•Aÿá”Aÿá”Aÿá”Aÿà“Aÿà“Bÿß“Bÿß’BÿÞ’BÿÞ’BÿÞ‘BÿÝ‘CÿÝCÿÝCÿÜCÿÜDÿÛŽDÿÛŽDÿÛDÿÚEÿÚŒEÿÚŒFÿÚ‹FÿÙ‹GÿÙ‹GÿÙŠGÿØŠHÿ؉Hÿ؉Iÿ؉Iÿ؈Iÿ؈Jÿ؈Jÿ؈KÿÚˆKÿ¿v=ÿÿÿÿ ÿÿ¸·µÿº·¶ÿÿ!ÿÿÿÿÂ5ÿà–Bÿà–Bÿá—Bÿâ—Bÿã˜Bÿã˜Bÿä™Bÿå™BÿåšBÿåšBÿæšCÿæ›Cÿç›Cÿç›DÿèœDÿèDÿèEÿèFÿéFÿâ™Eÿà–Dÿã˜Dÿã˜Dÿã˜Dÿã™Eÿã™Eÿã™Eÿã˜Fÿâ˜Fÿá˜Fÿá˜GÿäšHÿæœHÿçœIÿçœIÿçIÿçžJÿçžJÿç›Dÿæ™Aÿæ™AÿçšBÿè›Bÿè›Bÿè›BÿèšBÿèšBÿèšBÿèšBÿèšBÿèšBÿçšBÿçšBÿçšBÿçšBÿçšBÿçšBÿç™Bÿç™Bÿç™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿæ™Bÿå˜Bÿã—Aÿâ–Aÿâ–Aÿá•Aÿá•Bÿà•Bÿà”Bÿà”Bÿß”Bÿß“BÿÞ“BÿÞ’CÿÞ’CÿÝ‘CÿÝ‘CÿÜ‘DÿÜDÿÜDÿÛDÿÛŽEÿÛŽEÿÚŽEÿÚFÿÚFÿÚŒGÿÙŒGÿÙ‹GÿÙ‹HÿÙŠHÿØŠIÿØŠIÿ؉Jÿ؉Jÿ؉JÿÙ‰Kÿ¿x=ÿÿÿÿ ÿÿº·¶ÿº¸·ÿÿ ÿÿÿÿ‚6ÿà–Cÿà—Bÿá—Bÿâ˜Bÿã˜Cÿä™Cÿä™CÿåšCÿæšCÿæšCÿæ›Cÿç›Cÿç›DÿèœDÿèEÿèEÿéFÿéžFÿéžFÿéžGÿà˜Eÿâ˜Dÿä™Eÿä™Eÿä™EÿäšFÿäšFÿä™Fÿä™Gÿã™GÿãšGÿâšHÿâšHÿæIÿèIÿèžIÿèŸJÿèŸKÿèŸJÿèšBÿèšBÿçšBÿèšBÿè›BÿéœCÿéœCÿéœCÿéœCÿéœCÿé›Cÿé›Cÿé›Cÿé›Cÿé›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›Cÿè›CÿçšCÿçšCÿçšCÿçšCÿçšCÿçšCÿçšCÿæ™Cÿä˜Bÿã—Bÿã—Bÿâ–Bÿâ–Bÿá•Cÿá•Cÿá•Cÿà”Cÿà”Cÿß“Cÿß“CÿÞ“DÿÞ’DÿÞ’DÿÝ‘DÿÝ‘EÿÜEÿÜEÿÜEÿÛFÿÛŽFÿÛŽGÿÛGÿÚHÿÚŒHÿÚŒHÿÙ‹IÿÙ‹IÿÙ‹JÿÙŠJÿÙŠKÿÙŠKÿ¾x=ÿÿÿÿ ÿÿº¸·ÿ»º¸ÿÿ ÿÿÿÿ‚6ÿß–Dÿà—Cÿá˜Cÿâ˜Cÿã™Cÿã™CÿäšDÿäšDÿå›Dÿæ›Dÿæ›DÿæœDÿçœDÿçœDÿèEÿèžFÿèžFÿéžGÿéŸGÿéŸGÿçžGÿà˜Eÿã™FÿäšFÿäšFÿå›Gÿä›GÿåšGÿäšHÿäšHÿä›Hÿã›Iÿã›IÿâšIÿåJÿèŸJÿéŸJÿé Kÿé KÿèžFÿè›Bÿè›Bÿè›Bÿè›Bÿè›BÿéœCÿêDÿêDÿéDÿéDÿéDÿéDÿéœDÿéœDÿéœDÿéœDÿéœDÿéœDÿèœDÿèœDÿèœDÿèœDÿèœDÿèœDÿè›Dÿè›Dÿç›Dÿç›Dÿç›Dÿç›DÿæšCÿä™Cÿã˜Cÿã—Cÿâ—Cÿâ—Cÿá–Cÿá–Cÿá–Dÿà•Dÿà•Dÿß”Dÿß”DÿÞ“DÿÞ“DÿÝ’EÿÝ’EÿÝ‘EÿÜ‘FÿÜFÿÜFÿÛGÿÛGÿÛGÿÛŽHÿÚŽHÿÚIÿÚIÿÙŒIÿÙŒJÿÙŒJÿÚ‹Kÿ¿z=ÿÿÿÿ ÿÿ»º¸ÿ»ººÿÿ ÿÿÿÿ‚7ÿß—DÿߘDÿà˜Dÿá™Dÿâ™DÿãšDÿãšDÿä›Dÿå›DÿåœEÿæœEÿæœEÿæœEÿçEÿçFÿèžFÿèŸFÿèŸGÿéŸHÿéŸHÿéŸIÿäœGÿá™FÿäšGÿä›Gÿä›GÿåœHÿåœHÿå›Iÿå›Iÿä›IÿäœJÿäœJÿãœJÿâ›KÿãœKÿçŸKÿé¡Lÿé¡Lÿé¡KÿéDÿéœCÿéœCÿéœCÿéœCÿéœCÿéCÿéžDÿêžEÿêžEÿêžEÿêžEÿéžEÿéžEÿéEÿéEÿéEÿéEÿéEÿéEÿéEÿèEÿèEÿèEÿèEÿèœEÿèœEÿèœEÿèœEÿçœEÿçœEÿçœEÿæ›Dÿä™Dÿã™Dÿã˜Dÿâ˜Dÿâ—Dÿá—Dÿá—Dÿà–Dÿà–Dÿà•Eÿß•Eÿß”EÿÞ”EÿÞ”EÿÝ“FÿÝ“FÿÜ’FÿÜ’GÿÜ‘GÿÛ‘GÿÛHÿÛHÿÛHÿÚIÿÚŽIÿÚŽIÿÙJÿÙJÿÚKÿ¿{=ÿÿÿÿ ÿÿ»ººÿ»»»ÿÿ ÿÿÿÿÁƒ7ÿÞ—DÿÞ˜Eÿà™Eÿá™EÿášEÿâšEÿã›Eÿã›EÿäœEÿåœEÿåœEÿæFÿæFÿçFÿçžGÿçŸGÿèŸGÿèŸHÿè Hÿé Hÿé Iÿè¡Iÿá›Gÿã›Hÿä›Hÿä›HÿåœIÿåœIÿåœIÿåœJÿåœJÿåJÿåKÿäKÿäKÿãœLÿâLÿåŸLÿé¢Mÿê¢Mÿé IÿéDÿéDÿéDÿéDÿéDÿéDÿéDÿéžDÿéŸEÿêŸFÿêŸFÿêŸFÿêŸFÿêŸFÿêžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿéžFÿèžFÿèFÿèFÿèFÿèFÿèFÿçFÿçEÿæœEÿäšEÿã™Eÿã™Eÿâ˜Eÿá˜Eÿá˜Eÿá—Eÿà—Eÿà—Eÿß–Fÿß–FÿÞ•FÿÞ•FÿÞ”FÿÝ”GÿÝ“GÿÜ“GÿÜ’GÿÛ’HÿÛ‘HÿÛ‘HÿÛIÿÚIÿÚJÿÚJÿÙŽJÿÚŽKÿ¿|=ÿÿÿÿ ÿÿ»»»ÿ¼¼¼ÿÿÿÿÿÿÁƒ7ÿÞ˜EÿÞ˜Eÿß™EÿàšEÿášEÿâ›Eÿâ›EÿãœEÿäœEÿäEÿåEÿåEÿæžFÿæžFÿçžGÿçŸGÿç Gÿè Hÿè Hÿè Hÿé Iÿé¡Iÿç Iÿá›HÿäœHÿäœHÿåIÿåIÿåIÿåJÿåJÿåJÿåžKÿåžKÿåžKÿäžLÿäžLÿãžLÿãŸMÿè¢Mÿê£MÿéŸFÿéžDÿéžDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸDÿéŸEÿê Eÿê Fÿê Fÿê Fÿê Fÿê Fÿê FÿêŸFÿêŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿéŸFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿèžFÿæFÿã›EÿãšEÿãšEÿâ™Eÿâ™Eÿá™Eÿá˜Eÿà˜Eÿà—Fÿß—Fÿß–FÿÞ–FÿÞ•FÿÞ•GÿÝ•GÿÝ”GÿÜ“GÿÜ“HÿÛ’HÿÛ’HÿÛ‘IÿÚ‘IÿÚ‘JÿÚJÿÚ‘Jÿ¿}=ÿÿÿÿ!ÿÿ¼¼¼ÿ½½½ÿÿÿÿÿÿÁ„8ÿÞ˜EÿÞ™EÿßšEÿàšEÿášFÿâ›FÿâœFÿãœFÿäFÿäFÿåFÿåžFÿæžFÿæžFÿçŸGÿçŸHÿè Hÿè Hÿè¡Iÿé¡Iÿé¡Jÿé¡Jÿê¢JÿäžJÿãœIÿåIÿåJÿæžJÿæžJÿæžKÿæžKÿæžKÿæŸLÿæŸKÿæŸKÿæŸLÿåŸLÿåŸLÿäŸMÿäŸMÿæ¡Nÿê¢LÿêŸEÿê Eÿê Eÿê Eÿë Eÿë Eÿê Eÿë Eÿê Eÿê Eÿë Fÿë¡Fÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë¡Gÿë Gÿë Gÿê Gÿê Gÿê Gÿê Gÿê Gÿê Gÿê Gÿé GÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿéŸGÿèŸGÿåœFÿä›Fÿä›FÿãšFÿãšFÿâšFÿâ™Fÿá™Fÿá˜Fÿà˜Gÿà—Gÿß—Gÿß—GÿÞ–GÿÞ–GÿÞ•HÿÝ•HÿÝ”HÿÜ”IÿÜ“IÿÛ“IÿÛ’JÿÛ’JÿÛ’JÿÀ<ÿÿÿ ÿ!ÿÿ½½½ÿ¾¾¾ÿÿÿÿÿÿÁ„8ÿݘFÿÝ™FÿÞšFÿßšFÿà›Fÿá›FÿâœFÿâGÿãGÿäGÿäžGÿåžGÿæžGÿæŸGÿæŸGÿç Hÿç¡Hÿè¡Hÿè¡Iÿè¡Iÿé¢Jÿé¢Kÿé£Kÿé£KÿâIÿäžJÿåžJÿåŸKÿæŸJÿæŸJÿæŸKÿæŸKÿæ Kÿæ Lÿæ Lÿæ Mÿæ Mÿæ Mÿå¡Mÿå Nÿä Nÿä Oÿç Iÿë Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Fÿë¢Gÿë¢Gÿë¢Hÿë¢Hÿë¢Hÿë¢Hÿë¡Hÿë¡Hÿë¡Hÿê¡Hÿê¡Hÿê¡Hÿê¡Gÿê¡Gÿê¡Gÿê¡Hÿê Hÿê Hÿé Hÿé Hÿé Hÿé Hÿé Hÿé HÿçŸGÿåGÿäœGÿãœGÿã›Gÿâ›GÿâšGÿášGÿá™Gÿà™Gÿà™Gÿà˜GÿߘHÿß—HÿÞ—HÿÞ–HÿÝ–HÿÝ•IÿÜ•IÿÜ”IÿÛ”IÿÛ“JÿÛ”JÿÀ€<ÿÿ ÿ ÿ!ÿÿ¾¾¾ÿ¿¿¿ÿÿÿÿÿÿÀ„9ÿÝšGÿÝšGÿÞšGÿÞ›Gÿß›GÿàœGÿáœGÿâGÿâGÿãžGÿäžGÿäžHÿåŸHÿåŸHÿæ Hÿæ Iÿç¡Iÿç¢Iÿç¢Jÿè¢Jÿè¢Jÿé¢Kÿé£Kÿé¤Lÿæ¡LÿãžJÿåŸJÿå Kÿå Kÿæ Kÿæ Lÿæ Lÿæ Lÿæ¡Mÿæ¡Mÿæ¡Mÿæ¡Nÿæ¡Nÿæ¡Nÿæ¢Oÿå¡Oÿå¡Oÿä NÿäFÿé¡Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë£Gÿë£Hÿë£Iÿë£Iÿë£Iÿë¢Iÿë¢Iÿë¢Hÿë¢Hÿë¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¢Hÿê¡Hÿê¡Hÿé¡Hÿé¡Iÿé¡Iÿé¡Iÿé¡Iÿè¡IÿçŸHÿäGÿäHÿãœHÿãœHÿâ›Hÿâ›Hÿá›HÿášHÿàšHÿà™Hÿß™Hÿß™HÿÞ˜HÿÞ—IÿÝ—IÿÝ—IÿÜ–IÿÜ–IÿÜ•JÿÜ”JÿÀ<ÿÿ ÿ ÿ!ÿÿ¿¿¿ÿÀÀÀÿÿÿÿÿÿ¿…9ÿÜšGÿÜšHÿÝ›HÿÞ›HÿßœHÿàœHÿàHÿáHÿâžHÿãžHÿãŸHÿäŸHÿäŸHÿå Iÿæ Iÿæ Iÿç¡Jÿç¢Jÿç¢Jÿè£Kÿè£Kÿè£Kÿé£Lÿé¤Lÿé¤MÿãŸKÿäŸKÿå Kÿå¡Lÿæ¡Lÿæ¡Mÿæ¡Mÿæ¡Mÿæ¡Nÿæ¢Nÿæ¢Nÿç¢Oÿç¢Oÿæ¢Oÿæ£Pÿæ£Pÿæ¢Pÿå¢QÿäŸKÿâGÿæŸGÿê£Hÿë£Hÿë£Hÿë£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿì£Hÿë£Hÿë£Hÿì¤Iÿì¤Iÿë¤Iÿë¤Iÿë£Iÿë£Iÿë£Iÿë£Iÿë£Iÿê£Iÿê£Iÿê£Iÿê£Iÿê¢Iÿê¢Iÿê¢Iÿê¢Iÿé¢Iÿé¢Iÿé¢Iÿé¢Jÿé¢Jÿè¡IÿåŸHÿäžHÿäHÿãHÿãHÿâœHÿâœHÿá›Iÿá›IÿàšIÿàšIÿßšIÿß™IÿÞ™IÿÞ˜IÿݘIÿÝ—JÿÜ—JÿÝ–JÿÀƒ<ÿÿ ÿ ÿ!ÿÿÀÀÀÿÁÁÁÿÿÿÿÿÿÀ…:ÿÜ›GÿÝ›GÿÝ›HÿÞ›HÿßœHÿßœHÿàHÿážHÿâžHÿâŸHÿãŸHÿäŸHÿä Hÿå Iÿå Iÿæ¡Iÿç¡Jÿç¢Jÿç£Kÿè£Kÿè£Kÿè¤Lÿé¤Lÿé¥Lÿé¥Mÿè¤MÿãŸKÿå Lÿæ¢Lÿæ¢Lÿæ¢Mÿç¢Mÿç¢Mÿç¢Nÿç£Nÿç£Nÿç£Oÿç£Oÿç£Oÿç£Pÿç¤Pÿç£Pÿç£Qÿæ£PÿåžHÿäžGÿäžGÿè¢Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¥Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿí¤Hÿì¤Hÿì¤Hÿì¥Iÿì¥Jÿì¤Jÿì¤Iÿì¤Iÿì¤Iÿì¤Iÿì¤Iÿë¤Iÿë¤Iÿë¤Iÿë£Iÿë£Iÿë£Iÿë£Iÿë£Iÿê£Iÿê£Jÿê£Iÿê£Jÿê£Jÿé£Jÿè¡IÿåŸHÿåŸHÿäžHÿäžHÿãIÿãHÿâœIÿáœIÿá›Iÿà›Iÿà›IÿßšIÿßšIÿÞ™IÿÞ™IÿݘJÿÞ˜Jÿ„<ÿÿ ÿ ÿ!ÿÿÁÁÁÿÂÂÂÿÿÿÿÿÿ¿…:ÿÛ›HÿÜ›HÿÝœHÿÝœHÿÞœHÿßHÿßIÿàžIÿážIÿâŸIÿâŸIÿã Iÿä Iÿä¡Iÿå¡Iÿå¡Iÿæ¢Kÿæ£Kÿç£Kÿç£Lÿè¤Lÿè¤Lÿè¤Mÿé¥Mÿé¦Mÿé¦Nÿå¢Mÿå¡Lÿæ¢Mÿæ¢Mÿæ¢Mÿæ¢Nÿç£Nÿç£Nÿç£Oÿç¤Oÿç¤Oÿç¤Pÿç¤Pÿè¤Pÿç¤Qÿç¤Qÿç¤Qÿç¤Rÿæ¢NÿåŸHÿäŸHÿäžHÿå Iÿë¤Iÿí¥Iÿí¥Iÿí¥Iÿí¥Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¦Iÿí¥Iÿí¥Iÿí¥Iÿí¥Jÿí¦Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿì¥Jÿë¥Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿë¤Jÿê¤Jÿê¤Jÿê¤Jÿê¤Jÿê£Jÿé£Jÿé£Jÿæ¡Iÿå IÿäŸIÿäŸIÿãžIÿãžIÿâžIÿâIÿáIÿàœIÿàœJÿß›Jÿß›JÿßšJÿÞšJÿÞšJÿÂ…<ÿÿ ÿ ÿ"ÿÿÂÂÂÿÃÃÃÿÿÿÿÿÿ¾†<ÿÛ›IÿÛ›IÿÜœIÿÝœIÿÝIÿÞIÿßžIÿßžIÿàžIÿáŸJÿá Jÿâ Jÿã Jÿã¡Jÿä¡Jÿå¢Jÿå¢Kÿæ£Kÿæ¤Kÿç¤Lÿç¤Lÿè¥Lÿè¥Nÿè¥Nÿé¦Nÿé¦Oÿè¦Oÿâ¡Mÿå¢Nÿæ£Nÿæ£Nÿæ£Oÿæ£Oÿç£Oÿç£Pÿç¤Pÿç¤Pÿç¤Qÿç¤Qÿç¤Qÿç¥Rÿç¥Rÿç¥Rÿç¥Sÿç¥Rÿæ¡Jÿå Iÿå Iÿä IÿäŸIÿç¢Iÿì¦Jÿí¦Jÿí¦Jÿí¦Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí§Jÿí¦Jÿí¦Jÿí¦Jÿì¦Jÿì¦Jÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿì¦Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿë¥Kÿê¥Kÿê¥Kÿê¤Kÿê¤Kÿé¤Kÿé¤Kÿè¤Jÿå¡Jÿå Jÿä Jÿã JÿãŸJÿãŸJÿâžJÿážJÿáJÿàJÿàJÿßœJÿß›KÿßœKÿ‡=ÿÿ ÿ!ÿ"ÿÿÃÃÃÿÄÄÄÿÿÿÿÿÿ¾†=ÿÚœJÿÚœJÿÛœJÿÜJÿÝJÿÝžJÿÞžJÿßžJÿߟJÿàŸJÿà Jÿá Jÿâ¡Jÿã¡Jÿä¢Kÿä¢Kÿå£Lÿå£Lÿæ¤Lÿæ¤Mÿç¥Mÿç¥Mÿè¥Mÿè¦Nÿè§Oÿè§Oÿé§Pÿæ¤Oÿä¢Nÿæ¤Oÿæ¤Oÿæ¤Pÿæ¤Pÿæ¤Pÿç¤Pÿç¥Qÿç¥Qÿç¥Qÿç¥Rÿç¥Rÿç¥Rÿç¦Sÿç¦Sÿç¦Sÿç¦Tÿæ¥Qÿæ¡Jÿå¡Jÿå¡Jÿå Jÿä Jÿä¡Jÿé¤Jÿí§Kÿí§Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿî¨Kÿí¨Kÿí¨Kÿí§Kÿí§Kÿì§Kÿì§Kÿì§Kÿì§Lÿì§Lÿì§Lÿì§Lÿì¦Lÿì¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿë¦Lÿê¦Lÿê¥Lÿê¥Lÿê¥Lÿê¥Lÿé¥Lÿé¥Lÿæ£Kÿå¡Kÿä¡Kÿä¡Kÿã Kÿã KÿâŸKÿáŸKÿážKÿàžKÿàžKÿßKÿßžKÿÈ=ÿÿ!ÿ!ÿ"ÿÿÄÄÄÿÅÅÅÿÿÿÿÿÿ¾†=ÿÚœKÿÚœKÿÛKÿÜKÿÝžKÿÞžKÿÞžKÿߟKÿߟKÿà Kÿá Kÿá¡Kÿâ¡Kÿã¢Kÿä¢Kÿä¢Kÿå£Lÿå£Mÿæ¥Mÿæ¥Mÿç¥Nÿç¦Nÿè¦Nÿè¦Oÿé§Oÿé§Oÿé¨Pÿé§Pÿä£Oÿæ¤Pÿæ¥Pÿç¥Pÿç¥Qÿç¥Qÿç¥Qÿç¥Rÿç¦Rÿè¦Rÿè¦Sÿè¦Sÿè¦Sÿè§Tÿè§Tÿè§Tÿè§Uÿè§Uÿç£Mÿç¢Jÿæ¢Jÿæ¢Jÿæ¡Jÿå¡Jÿä¡Jÿå¢Kÿë¦Kÿï©Kÿï©Kÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿï©Lÿî©Lÿî¨Lÿî¨Lÿî¨Lÿí¨Lÿí¨Lÿí¨Lÿí¨Lÿí¨Mÿí§Mÿí§Mÿí§Mÿì§Mÿì§Mÿì§Mÿì§Mÿì§Mÿë§Mÿë§Mÿë¦Mÿë¦Mÿë¦Mÿê¦Mÿê¦Mÿê¥Mÿé¥Lÿæ¢Lÿå¢Lÿå¢Kÿä¡Kÿä¡Kÿã Lÿã LÿâŸLÿáŸLÿáŸLÿàžLÿĉ=ÿÿ!ÿ!ÿ"ÿÿÅÅÅÿÆÆÆÿÿÿÿÿÿ½†>ÿÙKÿÙKÿÚKÿÛžKÿÜžKÿÝžKÿÞŸKÿÞŸKÿß Kÿß Kÿà Kÿá¡Kÿá¡Kÿâ¢Kÿã¢Kÿä£Kÿä£Lÿå¤Mÿæ¥Mÿæ¥Nÿæ¦Nÿç¦Nÿç¦Oÿè§Oÿè§Oÿé¨Oÿé¨Pÿé¨Pÿç¦Pÿå¤Pÿæ¦Pÿæ¦Pÿç¦Qÿç¦Qÿç¦Qÿç¦Rÿç§Rÿç§Rÿè§Sÿè§Sÿè§Sÿè§Tÿè¨Tÿè¨Tÿè¨Uÿè¨Uÿè§Sÿç£Kÿç£Kÿç£Jÿæ£Jÿæ¢Jÿå¢Jÿå¢Jÿâ¡Jÿæ£Kÿì¨LÿïªLÿïªLÿïªLÿïªLÿð«LÿðªLÿïªLÿïªLÿïªLÿïªLÿîªLÿî©Lÿî©Lÿî©Lÿí©Lÿí¨Lÿí¨Lÿí¨Mÿí¨Mÿí¨Mÿí¨Mÿì¨Mÿì¨Mÿì¨Mÿì¨Mÿì¨Mÿë¨Mÿë§Mÿë§Mÿë§Mÿë§Mÿê§Mÿê¦Mÿê¦Mÿé¦Mÿç¤Lÿå£Lÿå£Kÿä¢Kÿä¢Kÿã¡Lÿã¡Kÿâ Lÿá Lÿá¡LÿÅŠ>ÿÿ!ÿ!ÿ"ÿÿÆÆÆÿÇÇÇÿÿÿÿÿÿ¼‡>ÿÙKÿÙKÿÚžKÿÛžKÿÛžLÿÜŸLÿÝŸLÿÞ LÿÞ Lÿß¡Lÿß¡Lÿà¡Lÿá¢Lÿá¢Lÿâ£Lÿã£Lÿä¤Lÿä¤Mÿå¥Mÿå¦Mÿæ¦Oÿæ§Oÿç§Oÿç§Pÿè§Pÿè©Pÿè©Qÿé©Qÿê©Qÿå¥Qÿå¦Qÿæ§Qÿæ§Rÿç§Rÿç§Rÿç§Sÿç¨Sÿç¨Sÿç¨Tÿè¨Tÿè¨Tÿè¨Tÿè©Tÿè©Tÿè©Uÿè©Uÿè©Uÿç¦Oÿç¤Kÿç¤Kÿæ¤Kÿæ£Kÿæ£Kÿå£Kÿä¢Kÿä¢Kÿã¢Kÿè¥LÿîªLÿð«Mÿð«Mÿð«Mÿð¬Mÿð¬Mÿð¬Mÿð«Mÿï«Mÿï«Mÿï«MÿîªMÿîªMÿîªMÿîªMÿí©Mÿí©Mÿì©Mÿì©Mÿì©Mÿì©Nÿì©Nÿì©Nÿì©Nÿì©Nÿì©Nÿë¨Nÿë¨Nÿë¨Mÿë¨Mÿê¨Nÿê§Nÿê§Nÿê§Nÿé§Mÿè¦Mÿæ¤Lÿå¤Lÿä£Lÿä£Lÿä¢Lÿã¢Lÿâ¡Lÿâ¢LÿÅŒ>ÿÿ!ÿ!ÿ"ÿÿÇÇÇÿÈÈÈÿÿÿÿÿÿ¼‡?ÿמLÿØLÿÙžLÿÚžLÿÛŸLÿÜŸLÿÜ LÿÝ LÿÞ¡MÿÞ¡Mÿß¡MÿߢMÿà¢Mÿá¢Mÿá£Mÿâ£Mÿã¤Mÿã¥Nÿä¥Nÿå¦Nÿå§Oÿæ§Oÿæ§Oÿç¨Pÿç¨Qÿç©Qÿè©Qÿè©RÿêªRÿç¨Rÿå¦Rÿæ§Rÿæ¨Rÿæ¨Sÿç¨Sÿç¨Sÿç¨Tÿç©Tÿç©Tÿç©Tÿè©Tÿè©Tÿè©UÿèªUÿèªUÿèªVÿèªVÿèªUÿç¥Lÿç¥Lÿç¤Lÿæ¤Lÿæ¤Lÿå¤Lÿå£Lÿä£Lÿä£Lÿã¢Lÿã£Lÿé§Mÿï¬Mÿð¬Mÿð­Mÿð­Mÿð­Mÿð­Mÿð­Mÿð¬Nÿï¬Nÿï¬Nÿï¬Nÿî«Nÿî«Mÿî«MÿíªNÿíªMÿìªMÿìªNÿì©Nÿì©NÿìªNÿìªNÿìªOÿì©Oÿì©Nÿë©Nÿë©Nÿë©Nÿë©Nÿê¨Nÿê¨Nÿê¨Nÿé¨Nÿé§Nÿè§Nÿç¥Mÿå¥Mÿå¤Mÿä¤Mÿä£Mÿã£Mÿã¤MÿÆ?ÿÿ!ÿ!ÿ#ÿÿÈÈÈÿÉÉÉÿÿÿÿÿÿ¼ˆ?ÿמMÿØžMÿÙžMÿÚŸMÿÚŸMÿÛ MÿÜ MÿÝ¡MÿÝ¡MÿÞ¢MÿÞ¢MÿߢMÿà£Mÿà£Nÿá£Nÿá¤Nÿâ¥Nÿã¥Nÿä¥Oÿä§Oÿå§Oÿå§Pÿæ¨Pÿæ¨Pÿç¨Qÿç©QÿèªQÿèªRÿéªRÿêªRÿå§Rÿæ¨Sÿæ¨Sÿæ¨Sÿæ©Sÿç©Sÿç©Tÿç©TÿçªTÿçªUÿçªUÿèªUÿèªVÿè«Vÿè«Vÿè«Wÿè«Wÿè«Wÿè¨Rÿç¥Mÿç¥Mÿæ¥Mÿæ¥Mÿæ¤Mÿå¤Mÿå¤Mÿä¤Mÿä£Mÿä£Mÿã£Mÿä¤Mÿë©Nÿð­Nÿñ®Nÿñ®Nÿñ®Nÿñ®Nÿñ®Nÿð­Nÿð­Nÿï­Nÿï­Nÿï¬Nÿî¬Nÿî¬Nÿî«Nÿí«Nÿí«NÿìªNÿìªNÿìªNÿìªNÿëªNÿìªNÿìªOÿìªOÿìªOÿëªOÿëªOÿë©Oÿê©Oÿê©Oÿê©Oÿê¨Oÿé¨Oÿé¨Oÿè§Nÿæ¦Nÿå¥Nÿä¥Nÿä¤Nÿä¥NÿÇŽ@ÿÿ!ÿ"ÿ#ÿÿÉÉÉÿËËËÿÿÿÿÿÿ¼ˆ@ÿÖNÿןNÿÙŸNÿÚŸNÿÛ NÿÛ¡NÿÜ¡NÿÝ¡NÿÝ¢NÿÞ¢NÿߣNÿߣNÿà£Nÿà¤Nÿá¤Nÿá¤Nÿâ¤Nÿã¥Nÿä¦Pÿä§Pÿå§Pÿå¨Qÿæ¨Qÿæ¨Qÿç©Rÿç©RÿèªRÿè«Sÿé«Sÿê«Sÿè©Sÿå¨Sÿæ©Sÿç©Tÿç©Tÿç©Tÿç©Uÿè©UÿèªUÿè«Uÿè«Vÿè«Vÿè«Vÿè«Wÿè¬Wÿè¬Wÿè¬Xÿè«XÿèªXÿç¦Oÿç¦Nÿç¦Nÿç¦Nÿæ¥Nÿæ¥Nÿæ¥Nÿå¥Nÿå¤Nÿå¤Nÿå¤Nÿä¤Nÿä¤Nÿæ¥Nÿì«Oÿó¯Oÿò¯Oÿò¯Oÿò¯Oÿñ¯Oÿñ®Oÿñ®Oÿð®Oÿð­Oÿï­Oÿï­Oÿï¬Oÿî¬Oÿî¬Oÿî¬Oÿí«Oÿí«Oÿí«OÿìªOÿìªOÿìªOÿëªOÿëªOÿëªOÿì«PÿìªPÿëªPÿëªPÿëªPÿê©Pÿê©Pÿê©Pÿê©Pÿé¨Oÿç§Oÿæ¦Oÿå¦Oÿä¦OÿÇ@ÿÿ"ÿ"ÿ#ÿÿËËËÿÌÌÌÿÿÿÿÿÿ»‰@ÿÖžNÿןOÿØ OÿÙ OÿÚ¡OÿÛ¡OÿÜ¢OÿÝ¢OÿÝ£OÿÞ£OÿÞ£OÿߤOÿߤOÿà¤Oÿá¥Oÿá¥Oÿâ¥Oÿâ¥Oÿã¦Pÿã§Pÿä¨Pÿå¨Qÿå©Rÿæ©Rÿæ©RÿçªSÿç«Sÿç«Sÿé«Tÿé«Tÿê¬Tÿå©TÿæªTÿæªTÿçªUÿçªUÿçªUÿçªVÿç«Vÿè«Vÿè«Wÿè«Wÿè«Wÿè«Xÿè¬Xÿè¬Xÿè¬Yÿè¬Yÿè¬YÿçªUÿç§Oÿç§Oÿç§Oÿå¥Nÿå¥Nÿå¥Nÿå¥Oÿå¥Oÿå¥Oÿå¥Oÿå¥Oÿä¥Oÿä¥Oÿâ¥Oÿæ§Oÿí­Pÿó°Pÿò°Pÿò°Pÿò°Pÿñ¯Pÿñ¯Pÿð¯Pÿð®Pÿï®Pÿï­Pÿï­Pÿî­Pÿî­Pÿî¬Pÿí¬Pÿí¬Pÿí¬Pÿì«Pÿì«Pÿë«PÿëªPÿëªPÿêªPÿêªPÿëªPÿë«Qÿë«QÿëªQÿêªPÿêªPÿêªPÿéªPÿé©Pÿç¨Pÿæ§Pÿå¦OÿÈBÿÿ"ÿ"ÿ#ÿÿÌÌÌÿÍÍÍÿÿÿÿÿÿ»ŠAÿÕ Oÿ× OÿØ OÿÙ¡OÿÚ¢OÿÛ¢OÿÛ£OÿÜ£OÿÝ£OÿݤOÿÞ¤OÿߤOÿߥOÿà¥Oÿà¥Oÿá¦Oÿá¦Oÿâ¦Oÿâ¦Pÿâ§Pÿã¨Pÿä©Qÿå©Qÿå©RÿæªRÿæªSÿç«Sÿç«Tÿè¬Tÿé¬Tÿé¬TÿçªUÿåªTÿæ«Uÿæ«Uÿæ«Uÿç«Uÿç«Vÿç«Vÿç¬Vÿè¬Wÿè¬Wÿè¬Wÿè¬Xÿè¬Xÿè­Xÿè­Yÿè­Yÿè­Yÿè­Zÿç©Qÿç¨Oÿæ§Oÿå¦Nÿå¦Nÿå¦Nÿå¦Nÿå¦Oÿå¦Oÿå¦Oÿå¦Oÿå¦Oÿä¦Oÿä¦Oÿä¦Oÿâ¥Oÿæ¨Oÿî®Pÿó±Pÿò±Pÿò°Pÿñ°Pÿñ°Pÿð¯Pÿð¯Pÿï¯Pÿï®Pÿï®Pÿî®Pÿî­Pÿí­Pÿí­Pÿí­Pÿì¬Pÿì¬Pÿì¬Pÿë¬Pÿë«Pÿë«Pÿê«Pÿê«PÿêªPÿéªPÿêªQÿê«Pÿê«Pÿê«Pÿê«PÿéªPÿéªPÿè©Pÿå¨PÿÈ‘Bÿÿ"ÿ"ÿ#ÿÿÍÍÍÿÎÎÎÿÿÿÿÿÿ»ŠAÿÕ¡PÿסPÿØ¡PÿÙ¢PÿÚ¢PÿÛ£PÿÛ¤PÿܤPÿݤPÿÝ¥PÿÞ¥PÿߥPÿߥPÿà¦Pÿà¦Pÿá¦Pÿá§Pÿâ§Pÿâ§Pÿâ§Qÿã¨Qÿã©QÿäªRÿåªRÿåªRÿæ«Sÿæ«Tÿç¬Tÿè¬Uÿè¬Uÿé­Uÿé¬VÿäªUÿæ«Uÿæ«Vÿæ«Vÿç¬Vÿç¬Wÿç¬Wÿç­Wÿç­Xÿè­Xÿè­Xÿè­Yÿè­Yÿè­Yÿè®Yÿè®Zÿè®Zÿè®Zÿè¬Xÿç¨Pÿæ§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿå§Oÿä§Oÿä§Oÿä§Oÿä¦Oÿâ¦Oÿç©Pÿï¯Qÿò±Qÿñ±Qÿñ±Qÿñ±Qÿð°Qÿð°Qÿï¯Qÿï¯Qÿï¯Qÿî¯Qÿî®Qÿî®Qÿí®Qÿí­Qÿí­Qÿì­Qÿì­Qÿë¬Qÿë¬Qÿë¬Qÿê¬Qÿê«Qÿê«Qÿé«Qÿé«QÿéªQÿéªQÿé«Qÿé«Qÿé«Qÿé«Qÿç«RÿÉ’Bÿÿ"ÿ"ÿ#ÿÿÎÎÎÿÏÏÏÿÿÿÿÿÿ»‹BÿÖ¢Pÿ×¢PÿØ£PÿÙ£PÿÚ£PÿÛ¤PÿÜ¥PÿÝ¥PÿÝ¥PÿÞ¥PÿÞ¦QÿߦQÿߦQÿà§Qÿà§Qÿá§Qÿá§Qÿâ¨Qÿâ¨Qÿã¨Rÿã©Rÿã©RÿäªSÿäªSÿå«Sÿæ«Tÿæ«Tÿç¬Tÿè­Uÿé­Uÿé­Vÿé­Wÿç¬Vÿæ¬Vÿæ¬Vÿç¬Wÿç¬Wÿç­Wÿç­Xÿè­Xÿè®Xÿè®Yÿè®Yÿè®Yÿè®Zÿé®Zÿé¯Zÿé¯[ÿé¯[ÿè¯[ÿè®\ÿçªTÿå§Pÿå§Pÿå§Pÿå§Pÿå¨Pÿå¨Pÿæ¨Pÿæ¨Pÿæ¨Pÿæ¨Pÿå¨Pÿå§Pÿå§Pÿå§Pÿå§Pÿä§Pÿä§Pÿä§Pÿè«Pÿï°Rÿò²Rÿñ±Rÿñ±Rÿñ±Rÿð°Rÿð°Rÿð°Rÿï°Rÿï¯Rÿï¯Rÿî¯Rÿî®Rÿí®Rÿí®Qÿí®Qÿì­Qÿì­Qÿì­Qÿë­Qÿë¬Qÿê¬Qÿê¬Qÿê¬Qÿé«Qÿé«Qÿè«QÿèªQÿèªQÿèªQÿé«RÿË“Cÿÿ"ÿ"ÿ$ÿÿÏÏÏÿÐÐÐÿÿÿÿÿÿ»ŒBÿÖ£Rÿ×£QÿؤQÿÙ¤QÿÚ¥QÿÛ¥QÿܦQÿܦQÿݦQÿÞ¦QÿÞ§Qÿß§Rÿß§Qÿà§Qÿà¨Qÿà¨Qÿá¨Rÿá¨Rÿâ©Rÿâ©Sÿã©SÿãªSÿãªTÿäªTÿä«Tÿå«Uÿæ¬Uÿæ­Uÿç­Uÿè­Vÿè®Vÿé®Vÿè­Wÿå¬Wÿæ­Wÿæ­Xÿç­Xÿç­Xÿç­Yÿç­Yÿç®Yÿè¯Zÿè¯Zÿè¯Zÿè¯[ÿè¯[ÿè¯[ÿè°[ÿè¯\ÿè¯\ÿè¯\ÿè®Zÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿå¨Qÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿè«Rÿð°Sÿò²Sÿñ²Sÿð±Sÿð±Sÿð±Rÿð±Rÿï°Rÿï°Rÿî°Rÿî¯Rÿî¯Rÿí¯Rÿí¯Rÿí®Rÿì®Rÿì®Rÿë®Rÿë­Rÿë­Rÿê­Rÿê¬Rÿé¬Rÿé¬Rÿè¬Rÿè«Rÿè«Rÿç«Rÿæ«SÿÉ“Cÿÿ"ÿ"ÿ$ÿÿÐÐÐÿÒÒÒÿÿÿÿÿÿ¼CÿÖ¤RÿפRÿØ¥RÿÙ¥RÿÚ¦RÿÛ¦RÿÛ§RÿܧRÿݧRÿݧRÿÞ¨RÿÞ¨RÿߨRÿߨRÿà¨Rÿà©Rÿá©Rÿá©Rÿá©Rÿâ©SÿâªSÿâ«Sÿã«Tÿã«Uÿã«Uÿä«Uÿå¬Vÿæ­Vÿæ®Vÿç®Wÿè®Wÿè®Wÿè¯Xÿæ­Wÿå­Wÿæ®Xÿæ®Xÿç®Yÿç®Yÿç®Zÿç¯Zÿç¯Zÿç¯[ÿè¯[ÿè¯[ÿè¯\ÿè¯\ÿè°\ÿè°\ÿè°\ÿè°\ÿç¯]ÿä«Vÿä©Rÿä©Rÿä©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿå©Rÿä©Rÿä©Rÿä©Rÿã¨Rÿã¨Rÿè¬Rÿî°Sÿð²Sÿð²Sÿð²Sÿð²Sÿï±Sÿï±Sÿï±Sÿî°Sÿî°Sÿî°Sÿí°Sÿí¯Sÿì¯Sÿì¯Sÿì¯Sÿë®Sÿë®Sÿë®Sÿê­Sÿê­Sÿé­Sÿé­Sÿè¬Sÿè¬Sÿç¬Sÿæ¬SÿÊ“Dÿÿ"ÿ#ÿ$ÿÿÒÒÒÿÓÓÓÿÿÿÿÿÿ¼ŽCÿÖ¦SÿצRÿئRÿÙ§RÿÚ§RÿÛ§RÿÛ¨RÿܨRÿܨRÿݨRÿÞ¨RÿÞ©RÿÞ©Rÿß©Rÿß©Rÿà©Rÿà©RÿàªRÿáªRÿáªSÿâªSÿâ«Sÿâ«Tÿã¬Uÿã¬Uÿã¬Uÿä¬Vÿä­Vÿæ®Vÿç®Wÿç¯Wÿç¯Wÿè¯Xÿç®Xÿå®Xÿå®Xÿæ®Yÿæ¯Yÿæ¯Yÿç¯Zÿç¯Zÿç°Zÿç°[ÿç°[ÿè°[ÿè°\ÿè°\ÿè°\ÿè±]ÿè±\ÿè±\ÿç¯]ÿå®\ÿä©Sÿä©Rÿä©Rÿä©Rÿä©Rÿä©Rÿå©RÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿåªRÿäªRÿäªRÿä©Rÿä©Rÿä©Rÿã©Rÿã©Rÿã©Rÿç¬Sÿí±Sÿð³Sÿð²Sÿï²Sÿï²Sÿï²Sÿî±Sÿî±Sÿî±Sÿí±Sÿí°Sÿí°Sÿì°Sÿì¯Sÿë¯Sÿë¯Sÿë¯Sÿê®Sÿê®Sÿé®Sÿé®Sÿè­Sÿè­Sÿè­Sÿæ­TÿÊ”Eÿÿ#ÿ#ÿ$ÿÿÓÓÓÿÓÓÓÿÿÿÿÿÿ½DÿצTÿÙ§SÿÙ¨SÿÚ¨SÿÛ¨SÿÛ¨SÿÜ©SÿÜ©SÿÝ©SÿÝ©SÿÞ©Sÿß©SÿߪSÿߪSÿàªSÿàªSÿàªSÿáªSÿáªSÿá«Sÿâ«Tÿâ¬Tÿã¬Tÿã¬Uÿã¬Vÿä­Uÿä­Vÿä­Vÿå®Wÿæ®Xÿç¯Xÿè¯Xÿè°Xÿè°Yÿæ®Xÿæ¯Yÿæ¯Yÿæ¯Yÿç¯Yÿç¯Zÿç°Zÿè°Zÿè±[ÿè±[ÿè±[ÿè±\ÿè±\ÿè±\ÿè²]ÿè²]ÿè±]ÿæ¯]ÿæ¯^ÿå­YÿäªSÿäªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿåªSÿäªSÿäªSÿäªSÿäªSÿäªSÿè­Tÿî±Tÿð³Tÿð³Tÿï²Tÿï²Tÿï²Tÿï²Tÿî±Tÿî±Tÿí±Tÿí±Tÿí°Tÿì°Tÿì°Tÿì¯Tÿë¯Tÿë¯Tÿê¯Tÿê®Tÿé®Sÿé®Tÿé®Tÿç­UÿÊ•Eÿ ÿ#ÿ#ÿ$ÿÿÓÓÓÿÏÏÏÿÿÿÿÿÿ½EÿÙ¨UÿÙ©TÿÚ©TÿÚ©TÿÛªTÿÛªTÿܪTÿܪTÿܪTÿݪTÿݪTÿÞªTÿÞªTÿß«Tÿß«Tÿß«Tÿà«Tÿà«Tÿá«Tÿá«Tÿá«Uÿâ¬Uÿâ­Uÿâ­Vÿã­Vÿã­Vÿã­Wÿä­Wÿä®Wÿå¯Wÿæ¯Xÿç°Xÿç°Xÿè°Yÿæ¯Yÿå¯Yÿæ°Zÿæ°Zÿæ°Zÿç°[ÿç°[ÿç°[ÿç±\ÿè±\ÿè±\ÿè²\ÿè²]ÿè±]ÿè²]ÿè²^ÿç²^ÿæ¯]ÿæ¯^ÿæ¯]ÿä«TÿäªSÿä«Sÿä«Sÿä«Sÿä«Sÿä«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Tÿå«Tÿå«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«TÿäªTÿãªTÿç­Tÿí±Uÿð³Uÿï³Uÿï³Uÿï³Uÿî²Uÿî²Uÿî²Uÿí²Uÿí±Tÿì±Tÿì±Uÿì°Uÿë°Tÿë°Tÿë°Tÿê°Tÿê¯Tÿé¯Tÿé¯Tÿé®UÿË–Eÿ ÿ#ÿ#ÿ$ÿÿÏÏÏÿÍÍÍÿÿÿÿÿÿ¾‘FÿÙªVÿÙªUÿÚªUÿÚ«UÿÛ«UÿÛ«UÿÛ«UÿÜ«UÿÜ«UÿÜ«UÿÝ«UÿÝ«UÿÞ«UÿÞ«Uÿß«Uÿ߬Uÿ߬Uÿà¬Uÿà¬Uÿá¬Uÿá¬Vÿá¬Vÿá­Vÿâ­Wÿâ­Wÿâ®Wÿã®Wÿã®Xÿä®Xÿå¯Xÿå¯Yÿæ°Yÿæ°Yÿç°Zÿç°Zÿå°Zÿå°[ÿæ±[ÿæ±[ÿæ±[ÿæ±\ÿç±\ÿç²\ÿç²]ÿç²]ÿç²]ÿè²^ÿè²^ÿè²^ÿè³_ÿç²^ÿå°^ÿå°_ÿå°_ÿå®\ÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä«Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿå¬Tÿä¬Tÿå¬Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿä«Tÿä«Tÿä«Tÿã«Tÿã«Tÿã«Tÿæ­Tÿì²Uÿï´Uÿï³Uÿî³Uÿî³Uÿî³Uÿí²Uÿí²Uÿì²Uÿì²Uÿì±Uÿë±Uÿë±Uÿë±Uÿê°Uÿê°Uÿé°Uÿé¯Uÿé¯VÿË—Fÿ ÿ#ÿ#ÿ$ÿÿÍÍÍÿÊÊÊÿÿÿÿÿÿ¾”FÿÚ¬WÿÚ«VÿÚ¬VÿÚ¬VÿÛ¬VÿÛ¬VÿÛ¬VÿܬVÿܬVÿܬVÿܬVÿݬVÿݬVÿÞ¬VÿÞ¬VÿÞ¬Vÿ߬Vÿ߬Vÿ߬Vÿà­Vÿà­Vÿá­Wÿá®Wÿá®Wÿâ®Xÿâ®Xÿâ®Xÿã®Yÿã¯Yÿä°Yÿå°Zÿå°Zÿå°Zÿæ°Zÿç±[ÿå°[ÿå±[ÿå±\ÿå±\ÿæ±\ÿæ±]ÿæ²]ÿæ²]ÿç³^ÿç³^ÿç³^ÿç³^ÿç³_ÿç³_ÿç³_ÿå²_ÿå±_ÿå±_ÿå±`ÿå±`ÿä­Wÿâ¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿã¬Uÿã¬Uÿã¬Uÿã¬Uÿå®Uÿë±Vÿî´Vÿî´Vÿî´Vÿí³Vÿí³Vÿí³Vÿì²Vÿì²Vÿì²Vÿë²Vÿë±Vÿê±Vÿê±Vÿé±Vÿé°Vÿé°Wÿ˘Gÿ ÿ#ÿ#ÿ$ÿÿÊÊÊÿÈÈÈÿÿÿÿÿÿ¿•GÿÛ­WÿÛ­VÿÛ­VÿÜ­VÿÜ­VÿÜ­VÿÜ­VÿÜ­VÿÝ­VÿÝ­VÿÝ­VÿÝ­VÿÝ­VÿÞ­VÿÞ­Vÿß­Vÿß­Vÿß­Vÿà­Vÿà­Vÿà­Vÿá­Wÿá®Wÿá¯Wÿâ¯Xÿâ¯Xÿâ¯Xÿã¯Yÿã¯Yÿä°Yÿå°Zÿå±Zÿæ±Zÿæ±[ÿæ±[ÿæ±[ÿå±[ÿå²\ÿæ²\ÿæ²\ÿæ²]ÿæ²]ÿç²]ÿç³^ÿç´^ÿç´^ÿç´_ÿè´_ÿç´_ÿè³_ÿå±_ÿå±_ÿå±_ÿå±`ÿå±`ÿå±^ÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿå­Uÿä­Uÿä­Uÿä­Uÿä­Uÿä­Uÿã­Uÿã¬Uÿã¬Uÿå­Vÿê±Vÿî´Vÿî´Vÿî´Vÿí´Vÿí³Vÿí³Vÿì³Vÿì³Vÿì²Vÿë²Vÿë²Vÿê²Vÿê±Vÿê±Vÿ˘Gÿ ÿ#ÿ#ÿ$ÿÿÈÈÈÿÅÅÅÿÿÿÿÿÿ¿–GÿÛ®WÿÛ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÜ®WÿÝ®WÿÝ®WÿÝ®WÿÝ®WÿÝ®WÿÞ®WÿÞ®WÿÞ®Wÿß®Wÿß®Wÿß®Vÿà®Vÿà®Wÿà®Wÿá¯Wÿá¯Xÿá¯Yÿâ¯Yÿâ¯Yÿã°Zÿä°Zÿä±Zÿå±[ÿå±[ÿå±[ÿæ²\ÿæ²\ÿå±[ÿå²\ÿå²]ÿå²]ÿæ³]ÿæ³^ÿæ³^ÿæ³^ÿç´_ÿç´_ÿç´_ÿç´`ÿç´`ÿæ³`ÿä²`ÿå²`ÿå²`ÿå²aÿå²aÿå²aÿä¯Zÿã­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä®Vÿä­Vÿã­Vÿã­Vÿã­Vÿã­Vÿä®Vÿè±Wÿí´Wÿí´Wÿí´Wÿí´Wÿì´Wÿì³Wÿì³Wÿë³Wÿë³Wÿê²Wÿê²Wÿê²Wÿ̘Hÿ ÿ#ÿ#ÿ$ÿÿÅÅÅÿÃÃÃÿÿÿÿÿÿÀ—HÿܯXÿܯXÿܰXÿܰXÿܰXÿܰXÿܯXÿܯXÿܯXÿܯXÿݯXÿݯXÿݯXÿݯWÿݯWÿݯWÿÞ¯WÿÞ¯WÿÞ¯Wÿ߯Wÿ߯Wÿ߯Xÿà¯Xÿà°Xÿá°Xÿá°Yÿá°Yÿâ°Yÿâ°Zÿã°Zÿã±Zÿä²[ÿä²[ÿå²[ÿå²\ÿå²\ÿä²\ÿä³]ÿå³]ÿå³]ÿå³]ÿå³^ÿæ³^ÿæ³^ÿæµ_ÿæµ_ÿæµ`ÿçµaÿçµ`ÿå³`ÿä²aÿä³aÿä³aÿä³aÿå³bÿå³bÿä²aÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿä®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿã®Wÿâ®Wÿâ®Wÿç±Xÿì´Xÿì¶Xÿì´Xÿì´Xÿë´Xÿë´Xÿë³Xÿê³Xÿê³Xÿê³WÿÌ™Gÿ ÿ#ÿ#ÿ$ÿÿÃÃÃÿÀÀÀÿÿÿÿÿÿÀ˜IÿܱYÿܱYÿܱYÿܱYÿܱYÿܱYÿܱYÿݰYÿܰYÿܰYÿܰYÿܰXÿݰXÿݰXÿݯXÿݯXÿݯXÿݯXÿÞ¯XÿÞ¯XÿÞ¯Xÿ߯Yÿ߯Yÿß°Yÿà±Yÿà±Zÿá±Zÿá±Zÿá±[ÿã±[ÿã²[ÿã²\ÿã²\ÿä²\ÿä³\ÿå³]ÿä²]ÿä³]ÿä³^ÿä´^ÿå´^ÿå´_ÿå´_ÿå´_ÿæµ`ÿæµ`ÿæµ`ÿæµ`ÿæµaÿä²aÿä³aÿä³bÿä³bÿä³bÿä³cÿä³cÿä³cÿã±^ÿâ®Xÿã®Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿã¯Xÿâ¯Xÿâ®Xÿâ®Xÿâ®Xÿâ®Xÿå°Xÿê´YÿìµXÿëµXÿëµXÿë´Xÿê´Xÿê´Xÿê´XÿÌšHÿ ÿ#ÿ#ÿ$ÿÿÀÀÀÿ¾¾¾ÿÿÿÿÿÿÀ™IÿݲZÿܲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿܱZÿܱZÿܱZÿܱYÿݱYÿݰYÿݰYÿݰYÿݰYÿݰYÿÞ°YÿÞ°YÿÞ°Yÿß°Zÿß°Zÿß±Zÿà±[ÿà±[ÿá±[ÿá±\ÿâ±\ÿã²\ÿã³\ÿã³]ÿã³]ÿä³]ÿä³^ÿå³^ÿâ³^ÿä´_ÿä´_ÿä´_ÿå´_ÿå´`ÿåµ`ÿåµ`ÿæ¶aÿæ¶aÿæ¶aÿåµbÿã³bÿã³bÿä´cÿä´cÿä´cÿä´cÿä´dÿä´dÿä´cÿâ¯Zÿâ¯Yÿâ¯Yÿâ¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã°Yÿã°Yÿã°Yÿã°Yÿã¯Yÿã°Yÿã¯Yÿã°Yÿã°Yÿã°Yÿã°Yÿã¯Yÿã°Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿã¯Yÿâ¯Yÿâ¯Yÿâ¯Yÿâ¯Yÿá¯Yÿá¯Yÿå±Yÿé´YÿëµYÿëµYÿê´Yÿê´Yÿê´YÿÌšHÿ ÿ#ÿ#ÿ$ÿÿ¾¾¾ÿºººÿÿÿÿÿÿÚJÿÞ³ZÿÞ³ZÿÞ³[ÿÞ´[ÿÞ³[ÿÞ³[ÿÞ³[ÿÞ³[ÿÞ³ZÿݲZÿݲZÿݲZÿݲZÿݲZÿݱZÿݱZÿݱZÿݱZÿݱZÿÞ±ZÿÞ±ZÿÞ°ZÿÞ±[ÿß±[ÿß²[ÿà²\ÿà²\ÿà²\ÿá²\ÿâ²]ÿâ²]ÿã³]ÿã³^ÿã³^ÿä´^ÿä´^ÿä´_ÿä´_ÿäµ_ÿäµ`ÿäµ`ÿäµ`ÿåµaÿåµaÿåµaÿå¶bÿæ¶bÿæ¶bÿäµbÿã´bÿã´bÿä´bÿäµcÿäµcÿäµcÿäµdÿä´dÿäµdÿä³`ÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Zÿã°Zÿã°Zÿã°Zÿã°Zÿâ°Yÿâ°Yÿâ¯Yÿâ¯Yÿã°Yÿç³YÿëµZÿêµZÿêµYÿÌ›Iÿ ÿ#ÿ#ÿ$ÿÿºººÿ¸¸¸ÿÿÿÿÿÿÛKÿÞ´[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞµ[ÿÞ´[ÿÞ´[ÿÞ´[ÿÞ´ZÿݳZÿݳZÿݳZÿݳZÿݲZÿݲZÿݲZÿݲZÿݲZÿݲZÿݱZÿݱZÿÞ±[ÿÞ±[ÿÞ²[ÿß²\ÿß²\ÿß²\ÿà²\ÿá²]ÿâ³]ÿâ³]ÿâ´^ÿã´^ÿã´^ÿã´_ÿä´_ÿä´_ÿãµ_ÿäµ`ÿäµ`ÿäµ`ÿä¶aÿä¶aÿå¶aÿå¶bÿå·bÿå·bÿã´bÿã´bÿã´bÿã´bÿãµcÿãµcÿãµcÿãµdÿãµdÿäµdÿäµeÿâ±\ÿâ°Yÿâ°Yÿâ°Yÿâ±Yÿâ±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Yÿã±Zÿã±Zÿâ±Yÿâ±Yÿâ°Yÿâ°Yÿâ°Yÿá°Yÿá°Yÿá°Yÿâ°Yÿå³Zÿê¶ZÿÌœIÿ ÿ#ÿ#ÿ$ÿÿ¸¸¸ÿµµµÿÿÿÿÿÿÜKÿßµ\ÿÞ¶\ÿß¶\ÿß¶\ÿÞ¶\ÿÞ¶\ÿÞµ\ÿÞµ\ÿÞµ[ÿÞµ[ÿÞ´[ÿÝ´[ÿÝ´[ÿÝ´[ÿÝ´[ÿݳ[ÿݳ[ÿݳ[ÿݳ[ÿݲ[ÿݲ[ÿݲ[ÿݲ\ÿݲ\ÿÞ²\ÿÞ³\ÿÞ³]ÿÞ³]ÿß³]ÿà³^ÿá³^ÿá´^ÿá´_ÿâ´_ÿâµ_ÿâµ_ÿãµ`ÿãµ`ÿãµ`ÿã¶aÿã¶aÿã¶aÿä¶bÿä¶bÿä¶bÿä¶bÿä·cÿä¶cÿâµbÿâµcÿãµcÿãµcÿãµdÿã¶dÿã¶dÿã¶eÿã¶eÿã¶eÿã¶eÿãµcÿá±Zÿá±Zÿá±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿã±Zÿâ±Zÿã±Zÿã±Zÿâ±Zÿâ²Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿá±Zÿá±Zÿá±Zÿá°Zÿà°Zÿá°ZÿÇšJÿ ÿ#ÿ#ÿ$ÿÿµµµÿ³³³ÿÿÿÿÿÿÜKÿß¶\ÿß·\ÿß·]ÿß·]ÿß·\ÿß·\ÿß·\ÿÞ·\ÿÞ¶\ÿÞ¶\ÿÞ¶\ÿݵ\ÿݵ\ÿݵ\ÿݵ\ÿÝ´\ÿÝ´\ÿÝ´\ÿݳ\ÿݳ\ÿݳ\ÿݳ\ÿݳ\ÿݳ]ÿݳ]ÿÝ´]ÿÞ´^ÿÞ´^ÿÞ´^ÿß´_ÿà´_ÿá´^ÿáµ^ÿáµ`ÿâµ`ÿâµ`ÿâµ`ÿãµ`ÿâµ`ÿâ¶aÿã¶aÿã¶bÿã¶bÿä·cÿä·cÿä·cÿä·dÿâ¶cÿâµcÿâµdÿâµdÿâµdÿâµdÿâ¶eÿã¶eÿã¶eÿã¶fÿã¶fÿã¶fÿã¶gÿá³_ÿá±[ÿá±[ÿá±[ÿá²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿá²[ÿá±[ÿá±[ÿá±[ÿá±[ÿà±[ÿá±[ÿŘJÿ ÿ#ÿ#ÿ$ÿÿ³³³ÿ±±±ÿÿÿÿÿÿÄžLÿà·]ÿà¸]ÿà¸]ÿà¸]ÿà¸]ÿà¸]ÿà·]ÿà·]ÿß·]ÿß·]ÿß¶]ÿß¶]ÿÞ¶]ÿÞµ]ÿÞµ]ÿÞµ]ÿÝ´]ÿÝ´]ÿÝ´]ÿݳ]ÿݳ]ÿݳ]ÿݳ]ÿݳ^ÿݳ^ÿÝ´]ÿÝ´^ÿÞ³_ÿÞ´^ÿß´^ÿà´_ÿà´_ÿàµ_ÿáµ`ÿáµ`ÿâµ`ÿâµaÿâµaÿãµaÿâ¶aÿâ¶bÿã¶bÿã¶bÿã¶cÿã¶cÿã¶cÿã·dÿáµdÿâµdÿâµdÿâµeÿâµeÿâµeÿâ¶fÿâ¶fÿâ¶fÿã¶fÿã¶gÿã¶gÿã¶gÿâ¶fÿá±\ÿá±\ÿá±\ÿá±\ÿá±\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ±\ÿâ±\ÿâ±\ÿâ²\ÿá±\ÿá±\ÿá±\ÿá²\ÿÅ™Jÿ!ÿ#ÿ#ÿ$ÿÿ±±±ÿ®®®ÿÿÿÿÿÿÄŸLÿàº]ÿà¹^ÿà¹^ÿá¹^ÿà¹^ÿà¹^ÿà¹^ÿà¸^ÿà¸^ÿ߸^ÿß·^ÿß·^ÿß·^ÿÞ¶^ÿÞ¶^ÿÞ¶^ÿÞµ^ÿݵ^ÿݵ^ÿݵ^ÿÝ´^ÿÝ´^ÿÝ´^ÿÝ´_ÿÜ´_ÿÜ´^ÿÝ´^ÿÝ´_ÿÝ´_ÿÞ´_ÿÞ´`ÿß´`ÿßµ`ÿàµ`ÿàµaÿàµaÿá¶aÿá¶bÿá¶bÿá¶bÿâ¶cÿâ·cÿâ·cÿâ·cÿâ·dÿã·dÿâ·dÿá¶eÿá¶eÿâ¶eÿâ¶fÿâ¶fÿâ¶fÿâ¶fÿâ·gÿâ·gÿâ·gÿâ·hÿâ·hÿâ·hÿâ¸hÿá´bÿà²]ÿà²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿâ²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá²]ÿá³\ÿÅ™Lÿ!ÿ#ÿ#ÿ$ÿÿ®®®ÿ¬¬¬ÿÿÿÿÿÿÄŸMÿàº_ÿáº^ÿâº^ÿâº^ÿâº^ÿâº^ÿáº^ÿá¹^ÿá¹^ÿá¹^ÿà¸^ÿà¸^ÿà¸^ÿà·^ÿß·^ÿß·^ÿß¶^ÿݶ^ÿݶ^ÿݵ^ÿݶ^ÿܶ^ÿܶ^ÿܵ_ÿܵ_ÿܶ_ÿܶ_ÿܶ_ÿܵ_ÿݵ_ÿßµaÿßµaÿß´aÿßµaÿàµbÿàµbÿáµbÿáµcÿá¶cÿá¶cÿá·dÿâ·dÿâ·dÿâ·dÿã·eÿã·eÿá¶eÿâ¶fÿâ¶fÿâ¶fÿâ¶gÿâ¶fÿâ¶fÿâ¶fÿâ·gÿâ·gÿâ·gÿâ·hÿâ·hÿâ·hÿâ¸jÿâ¸iÿá³^ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿá³]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ³]ÿâ´]ÿâ´]ÿâ´]ÿâ´]ÿâ³]ÿâ³]ÿá´]ÿá³]ÿá³]ÿà³^ÿÆšLÿ!ÿ#ÿ#ÿ$ÿÿ¬¬¬ÿ©©©ÿÿÿÿÿÿ³CÿͨSÿΩRÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿÏ©RÿΨRÿΨRÿΨRÿΧRÿΧRÿΧRÿͦRÿͦRÿͦRÿÌ¥RÿÌ¥RÿÌ¥RÿʤRÿʤRÿʤRÿÊ£SÿÊ£SÿʤSÿʤSÿʤSÿÊ£SÿÊ£SÿÌ£Tÿ̤Tÿ̤Tÿ̤TÿˤTÿË£TÿÌ£TÿÌ£UÿÌ£Uÿ̤UÿͤUÿͤUÿͤUÿΤUÿΤVÿΤUÿÍ£UÿÍ£UÿÍ£UÿÍ£UÿÍ¢UÿÍ¢UÿÍ¢UÿÌ¢VÿÌ¢VÿÌ¢UÿÌ¢UÿÌ¢UÿÌ¢UÿÌ¢UÿÍ¢UÿÍ£UÿÌ¢RÿÍ¡Pÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢Qÿ΢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢QÿÍ¢Qÿ´ŠBÿ"ÿ#ÿ#ÿ$ÿÿ©©©ÿ¦¦¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ# ÿ&"!ÿ(%$ÿ*('ÿ-*)ÿ0,,ÿ20.ÿ620ÿ842ÿ:75ÿ=:8ÿ?<:ÿB>>ÿDA@ÿGCBÿIEEÿKHHÿNKJÿPMLÿSPOÿURQÿWTTÿYVVÿ\YYÿ`][ÿa_^ÿca`ÿfdcÿebbÿ#ÿÿÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ&ÿ"ÿ#ÿ#ÿ$ÿÿ¦¦¦ÿ£££ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ# ÿ&#"ÿ)&%ÿ+)(ÿ.+*ÿ1.-ÿ40/ÿ632ÿ965ÿ<98ÿ><;ÿA>=ÿDA@ÿGCBÿKHEÿQMHÿSQPÿXVVÿURQÿVSSÿYVUÿ\YXÿ^\[ÿa^^ÿda`ÿgdcÿifeÿkihÿollÿMJIÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿÿ£££ÿ¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ#ÿ&#"ÿ(%$ÿ+('ÿ.**ÿ1-,ÿ3//ÿ632ÿ865ÿ;88ÿ>;:ÿA==ÿC@?ÿFBBÿMIDÿWRIÿZXXÿponÿSPOÿRPOÿXVUÿ[YXÿ^[[ÿa^]ÿca`ÿfcbÿhfeÿkhhÿnkjÿpnmÿ*%$ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿÿ¡¡¡ÿ¢¢¢÷ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ# ÿ&#"ÿ(&%ÿ+('ÿ.+*ÿ1-,ÿ40/ÿ643ÿ865ÿ<98ÿ?;:ÿB>=ÿEA?ÿGDCÿJGGÿLIIÿOLLÿTQOÿURQÿWTSÿZWVÿ]ZYÿ`]\ÿb_^ÿebaÿgdeÿjgfÿmjiÿpmlÿsppÿ[XWÿÿ ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿ$ÿÿÿ¢¢¢÷ŸŸŸ«bbbÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcccÿŸŸŸ«¡¡¡ŸŸŸ«ŸŸŸ÷œœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿŸŸŸ÷ŸŸŸ«¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿøÿÿÿÿÿÿøÿÿÿÿÿÿü?ÿÿÿÿÿÿü?ÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(  × ×  ÆÂ¾“ÔÏÊÿÝÙÕÿæâßÿìêçÿíëèÿçäàÿßÛ×ÿÕÑÌÿÈÿ’wqjš”ÿŸ™”ÿ—’ÿ•Šþ’Œˆþ‘‹…ÿ‰ƒÿއ‚ÿf^W&ÄÀ½ÿÇÂÀÿ Ë ÿ ÿÿ ÿ ÿÿþ þÿÿÿÿÿÿ Ë ÿí5ÿâ‡4ÿã‰7ÿå‹9ÿå‰5ÿäˆ5ÿß…4ÿ܃4ÿ݃7ÿÝ‚9ÿÞ;ÿß<ÿ߀<ÿé†=ÿ ÿ ÿí•:ÿÛ‰7ÿÞ‹;ÿàŽ=ÿÞŠ9ÿ݉7ÿ܉8ÿ܈9ÿÚ‡9ÿׄ;ÿÖ‚=ÿØ?ÿÙAÿæˆFÿ ÿ ÿï›@ÿå•>ÿÞ>ÿâ“Aÿä•Bÿä’<ÿâ‘=ÿà<ÿÝ<ÿÛ‹>ÿÙ‰@ÿÙ‡BÿÙ…EÿèJÿ ÿ ÿîžDÿæšBÿæ›Eÿâ—Eÿå›HÿçšBÿèšBÿçšBÿå˜Bÿâ–Aÿß’BÿÛCÿÙ‹Gÿå‘Mÿ ÿ ÿë¡HÿäGÿè HÿåŸJÿåŸLÿæ Kÿê Eÿë¡Gÿê Gÿé HÿçžGÿâšFÿÞ—Gÿè›Lÿ ÿÿè¤MÿàŸKÿå£Lÿè¦Oÿæ¤Pÿç¦Rÿæ¢Lÿê¥Jÿï¨Kÿí§Lÿë¦Lÿê¦Lÿå¡Kÿí¦Nÿ ÿÿä¨RÿÞ£Oÿâ¥Oÿæ©RÿçªTÿç«Vÿè«Vÿå¥Nÿç§Nÿï­Oÿî­Oÿì«OÿêªPÿô²Sÿ ÿÿæ±WÿÝ©SÿàªTÿã¬Uÿç®Xÿç¯Zÿè±]ÿå«UÿåªRÿä©Rÿè­Sÿî±Tÿì°Tÿö·Wÿ ÿÿé»^ÿݯYÿÝ®Xÿà°Yÿä±\ÿä³^ÿæ´`ÿä²`ÿã®Wÿä®Xÿä¯Xÿã®Wÿæ°Wÿø½\ÿ ÿÿõÉdÿæ½^ÿãº]ÿâ¹_ÿä¸`ÿå¸aÿå·bÿä¶cÿã²\ÿè¶\ÿè·\ÿé¶\ÿç¶\ÿô¿aÿ ÿÁÿÿÿÿ ÿÿ#%(ÿ349ÿ348ÿÿÿÿ ÿ ÿ Áàààþ‰PNG  IHDR\r¨f€IDATxÚí½{¼íÉUø]µ÷9ç>:};î¤Óm^$0c À@@3Œ¼„ñ‰|eü¨ ‚¨È‡ññD˜ " D>3„¨è 2HD“€t„„¼È£“N§ß{ï9gÿjÍUëUU¿}ö9·ûœ¾Ý»îçž½÷ïWÏUµžµj°MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´MÛ´M×cúÁüÁ³îÂ6mÓ6áÚpqy íÞüÚ×¾ö;www¿h±X\"¢³†Ã6mÓS&13¦izðààà§|€ûNRω°öµ¯}í+vvv~émo{¿ñ?KïßÀೆÉu˜D((%*C„$¿ë;" 4ÏôY]šOÚêóùÌõ…Ö=Ó²®­Úþ¨^°š&¼ç=ï>ëI¸.SJ <ç9wàü‘?Ê/{ÙËèðððúʯüÊ7·žc€*jܼ\.ï}Ýë^Ç¿ð ¿@—nºÙ®NöÉš__nþå¸ÜѰrÇ£ƒÇ“vH#¥„”@ùL‰@”@DH)„×ßön±°ï”,QªùÊ3$Bòu,¨É—S—ßò,ÜwPBéjªïjý”Ê÷Ú‡øÞõ¥¾Åb·¾åWðÎw½ë1œ÷Íæå¤óþDJD„Õj…Ýù>|îç~Ù—}­V«g¸ï•¯|åÆõ¤ã4úÊW¾Ìüo{ÛÛø~á覧?£É‘0˜7•b¾õÅrÍßg—;ºVn¾îq¹Íó<ÌÒ&»öYë$p•¤8¼ËÙu–kû̲{Ì5{iÁµ¬>¶¹‘:Xž±¨<Ëå½oíÕ%ݪíYþ™ës®ãcÆ£<ŠßzûÛu|›Ñ¼Ï¬ˆ®Üfóhå®_©•™‘RÂsŸ÷BüüÏÿ{úµ_û5fæï<òÇ$°··÷Eo|ãéÒM7—EÈ0Á/è ‡Ò l.¹¼5º7åA××ϧ2QXÚ®ÏX5ïvã/jÕ|,%¬ YòÖÊ–:n¼t#^øÂÁr¹„´àZÕªÈ*²¾©ø/„‰z â?[¥D Ëþó›ß\Û­ã“âHý¼·plË­_#ãr×/ "äœqûÏÃÏþìÏÐÞÞÞ·Žc€åryé}ïÐéšná,‰@_öhŽÐ/ž£RÉ»)~PEZfè÷ÐO% †¶Äìtl |÷½ %¾êò€S°»»‡gßö,ÜrË͸íYÏ¥²DQ" •Ú ømˆ/¤„C_ìýݹwÞyg˜›õD`ÎR.ŠõO-"°\.ñ܉åryé¸åM‹ÅQ²:+"0.:Ï­Ç èèÅË<¶D ÙŒ {¸xb@ÊÙ}­Âu®D€;©BÐÍ8·ÖW;?ãv\üô/rÆÞÞ.Þô¦7á½ï}/>üá!Õ>=øàý¨±ý̬}fŠ'Qþ/—Kü§ÿüf•:|+=2w³4ãvΟZD€™‘óTpó˜éØ 5ø­É O6ƒ/»2ŸsuǾÊm¶b™Ç‹ô¨øÎÁ”·Uä"C¸wuÀ[ýÕyï‡pùÍ?¤„G/?Š—¼ô“0­&\¼xrÕ)o¼ñ¦hÙ—¿ÔŒÑÁneölíÊÃúè]ïz7~øáٹ鑹›¥ æoóy²2–ã5íàlf­EA´uŒ³så’Gq…^ðùÙ!‘¯{ñ²2›ÚdŒ¤\Øê*H%póuw\ŸmR gOÎŽø2ÊaT|î[Ë TtÇ{?z7ˆH¾=ø¶áÔZÞ«°ßq|vu.Ò¿ú«ÿEaâá×ÎÍÑ’ÀøåXX?ïqÍð‰é‰N•”ïU$E†n>¸ÚSS¶E±A+M›ÇË¿¾Üc³UDƒÁŒ¶¥8ÄËu+,×-¾L¢˜Ðíº²mÆ ÝVãúœõw!¦™d+1!l;„¶õÜö!l›.%Û6 ÛƒnÛ¯-¶ûd[0%$ –ÑmL©;a‘ÿõïÀá•Gý¢Ìͦ#&³~1Źà#ók®`8}%"¤½#²œˆÔ»p(fãùà*^ðUß…›žy+–çΡ²©kKsF¡Y‘7«ƒxÀóË€«ΑömÐ…£$ ’B>ž©mX·ÎDÁšÖµy!X˜Àä8êLiüxñ±¿û´Ü“ôCÆSLÌ«ƒ}\¾ï#¸ëõߺ–´¸¹Iº&P…õ@˜—žy+nyÎó°{áB/›oøá£Gƒì39Ú»v‚ihÄ üØ[K(¶Ü¨ñíöÏõ»ï©¨Æ:"nÞlÏéæL€Ã)h=@çh²Žvv­ž]é8»I$f\½‚(ã®#ª=Њ-€år˽],÷Î5¹7õð«Ê¸È „æŒ;G¬ÖDó 皣4$M³FzWÜ·%r*a\‚Q¤¢a ã_îùÓ´–dÑÜ;ÂÄŒGóBmÚ þ ¥¶#« ënŽˆ¹År´•3–dF΋åŽ",§nð°"`«µÜ·6q·ö½ÎëòÊ'Uvî2ucyèÛ÷½HÅB%<û%+”6™4Oùð[j½¦rýÁ(N;V½Q'gz‹½#3! HŽÔ0Ç+zÇ%[ÔëËÑ€pX9på‡^ qîf)ˆ¯ò„iH·¦éµ©£z4Îäç5ìö8«eXÛ ŒÖQWÉuº6›oŽt €x}V% Ü/€Ø¾FØ–êˆG×TwœÏïÍGªî-ÞÎèDd¿ NjPHB’:¡Áª•!Z`ÕrɦÍv@€†6›£ËFôRY&vÓÔ´‘6êšæh`ƒ Üœ=.iÎX¹¦k­'m ‹cH g Ä…¡¯œK6wyç~’שÒP³Š¼à y‚1”hÐ;SqæÑ¡,0î*®è-:3"ÂÖÜduxŠl žx0Ê.°' ÌS%(²ªlÌA^èlO|÷_x!××[N:^Lè’ÌÝp.F)¹‚o-mX÷µ¤‘g8Øù~×/IoÐú©ªŠ!=:0™0í`-Z 6<»ÿC5)HéhËeüc% ÕzÏk_?©W05)SÕùk›LlÈÃÉ!Cò–øyÎíY.Ûáê¸#‹†áñÚuì}Yf\|rÖúæàºú€£Ö\S»y`ƃ©H$ë$ä£Ôó.™;äc—2)k¬2n¨³´RMX^2;ÂP=(RÓ©«c"P¦žÝ§ˆà„ž¡Éî\àF?gÝïŒkòhoaú}(ÛŒQ{k¿<»µ1I}2±Nßw0§$ùžÀôÿ’/7–ZÄpè×ùv[©¨>$rCx 3k‰‹Ù íƒ¤ÊÑÌ;Q]L%¼²âjºq;²×el <îÞzý¼¯GþHž¡®v}7o}Æž®®ëñYìôDÀL˜¡G7Tg'ˆ8Üd¤óƒ ^8ë¸Êi²6y6 7ž:>Ǩå?˜T -V÷Û¦vh]"”ˆˆ,uý˜ÃµCx¯ö85Åæ€¸µJ WĆ ž~ -Éïîxi/ùQQícb`ŹÇUö”`nŽ×¥Çù7áàtŒçsyã: pk³ -Oçõà,<µ*®º·‹ŒÉKˆnáôgéAÒœ™Ôí¸§È´ ®"àDMcµ±?†‘ì믛p&K˜SÓŸÂaÊ£dêÔ¡’µ?Õ=x†½tȘ³Ž™URш‘éÁÚÏ Þµ9We†•ê,€Ù¬/»I}Ô¬O'ÑùìCñÿ8í¶ËÁºm%U¯Þ°HÉGS€SVŒwÉ/hoÕUv$Ïââ)3†À?=×XcÉ×·:? &¼@ÉÆãÞFÙ››z Ò ’*z52FBâØj/ë56 Ian ƒþÉsÞ0^Â:Sc*ŒÏu~£dsÙ›3ˆ^Å~÷0ßP÷Æ\½í D„i µÞ¨p×s¶v8´¦Í û˜hU¢ 8âp&€hËnšýœus5’{¼1ÌÔ„Vbê«XcŽ=BÇ×g”#+cg¿­ãgvö§*ÔgDÆí{þLýs1¼P4w¿Ø) ·Ð=à©ì#%`Êc½ùHu:­?W7^¿¢“Ø Ì'ÀäÂZ_rî€A¯¶1¥!ÌëÈò¨2£am»–?Ìe£¡µŒ‘dtˆpœt½˜/3’ØÐ/¿.Ôê?מTPͧ‹% †=ón°/ãšÞ·áxÎà80Ço¢nR±'Ñ#’í5A`vˆUN²ýRt]$Ò{¯ÃN¿£¾̢ |ûÜxj|“vDÔ õ–ÏpæPÇ*FÀ<•<´ ù¾P/œø…á¿ÉÑeÂÆ¥ØÒè:©el•Ø1ã süe]š‘ß[•æqK-µÙ$D|€°R#@-w@‹]Õï‹t瀩_=s‰ Aq†ÇaNDŬÈÇLƒ³CC’xƒ•â«éÄ<šm˜XAÛjú_‰A2 _ˆ½÷èòŸbtS9CŽÃ2gë °eÇ-AU˜½59=!«ÑƒØÍ›ÐµW¥›¡¹šX`Љý‰çÂv°jáó<žH?ä‰tûŽRFì6ÐrX.ÕЧÜqF%Äö,ÔªWøÑ=:WàH|×ëRv½÷lg@éÛ6‚4ƒuavôä‹W^Ûgês·ÄÚów£:„€%‡ø ©%6•›Ϋl;1EÝ¿…“î€8é†ÌµÚC£ôy&ÊF8WKý``F4R "pâö˜Ó(”voÄ\ŸÖ¨ëÖu‹»^|Ÿ6C›íÃãz‘~ âϭ3 ñ|]Ý;6ûàét%aÒΈ¡ d÷_åMe-ëáéExÀQÍyÑЦÐsËäúäÅråD•Ha“Oþ7H¤¤'Äø÷"¹ónëv5WiW¶ +åñ‚dªÝV§’d…qÃï=‘4f^`@Üæð9˜¤PŽï˶—8<(ÐV?ž¾õ)¨3ïýÔ·ÚäH` ÃðjبÂ6±ûVöïÓrHõƬ© ¡*ëCŒ.#‘éé[5;ŠS7€šÙ¨Þ\ñ ±ü ›ùÃ;Y€¶æ¬´«Õ¾µÚº´gõ_O²Ñb²ù†:ÇUcw»»U÷î;B*9$Då¼’£f¢Ô‹ R‡è”* ¼ŽƒüØJG¼ËD„QyöF5#· ¿V¢^†õ|DÎŒCïãÑâ̱֣Ç[|ô®y¶i»Ã¾’«Îl1ëŒ$´X‹~JÕ‹rd„iúìUªaÇ8¼*ÝÙÜzº7¡â«Ž±¨À$PÙ*`Žæ°³¨Rü>›zÎÞJ}ò6‘^ôzËjæ6Ëë»ã¸%èf‚nw¢Ú r­u²”ACÏªŠ¢6?· +G  oLôçl^ç#)+åÄÀˆäÉ垃˜ã\5Ÿ'NWÂÔôÞ(³fNhÍûQà jÞÍ­ Ì×Û™„؈@§³×ÌËeA|JEÔÏÞ;4w\¼JXïC"£ï׆4àÔmS…`Ž×v÷8£È¬ý¥Gê>ùiÙ°Œ 8œ¸J Üg§ìZ/ˆYG Ž¿ðçÓHBeÐÎ.°Ü…€§¼oÖ@‹ÌGµ³aº± 8eWà"ò³_x8²îucHkú”òs¦Í‘"·.ÏèyÿŒ20±Éuâ™\r¢6 W7ý¢¬ÜÛÔ rTÞs/—Jü~8›A³!=‘àæ½«³5Ñ@'ƒpºª²$é¯Þ$µpcŸ"\]å¦+ëõåÍMYGZ+š4ùp¶]çÝ=`±[çÕËǫƤiŸcó t}ᘇ™ÁÈØÄàL¶I¸üHâV©ŸšÀ<‰Ü„ûÓu=â×gºøýkêo4$ ‚ëdˆB±T¯:C¨×%R†SïTýú-ßnö퉰< Þ$ ý¨Ÿ’æÊa•ëøqDz,9óµ&„sÄŠõrФ}9ËÙÀHlT£j†;" œ3ÐÁ¹»Šè`œ\3³¹Äg®ýgH;ˆ£ÁlZhêðI1ŸØ qІYøäŒ„¾Ru éËÁ ¶+¥?æi%i’CŸI™±ùWÈ‚¨ê Ê Í1q]_c¸&]»¤[×Ò‡ìêÐ~0Õ#ÁUîaÆþäæ S§òµ/×=Û@ŸŸmt>#vÏ‹¢Þø¥2J<óÀÇ· Ðõë²6ÐÆoPä¯å¸X«6±žðHQÝW•ÐÚâÔ2茛\B±N" q¾–qÂcûþX—Ø!ÙxÕýÓß‹ØJ!¢? 77.-D tÅ÷ÓàB^ï–îhÑäúááiö‰Z‚ÀPiö ¹©1/Œ÷ÊjÍaŸYÉšÇyƒdao߉omhðVÈ Äs`æd.7ïÄçzäœ\;£Õ8/PÐ ó ¬FïCY>=]# µHÂõ³¹çÒˆ(¬C~Wn<÷mP©Ï¸kÌÂ(Ñzx¾aáäcõ»ºªBYtu©Ër‚E£v‚ž1°"[žax/¿KàŒ~…Õ ±Ú%¬/+¦Ìó -w}3 Ï-ŠuóÝŽyF YzÉ¡8ï,öΩZô¹ÙÃg‘ÜŒ{wË·ëþ@¬ï0gʶðqâôéômà (Àe83X®¨R狹sè0ÛÏ5ÒÍ<Ÿ!Ç %v¨îý+nX@¶l‰Û6 Ì^_W·`uÂëà\|J^'/i©mG›n%†ZU´Î;Bla¿¥¿%>˜<äœõgV½µ¯„ïs„ƒ2tÄ›çï$Å™®èur¦ÂÐb‰´»9œS¦½©ÇÙâúQr¬>¸cÙ‹G„«ÿ1ãЇMÒÙ¸ˆ@0z‹±ƒÛ÷›";0žìFÄPJ3uûvEÎKÎV–«m`,K’Iy²°8A¬u&`X¸ ¨ê˜BÝnA”M”.%/¾Ö,9„ï<íuº©úuÌÐbéÍÁTˆEDÈ1~l­}ºa;Š™¹|].ÕkO¬úæ%:î?uˆÚ·o¾±ÇýÕð#É¥W¯Ùg?"~T`Êh}Óu€„r{gp8ˆï³bÞÌçpÎÖé’NÑ6}’LPv­ ’’ïË´jƒ\È}/°§²7îV]AìÒ'vcM®O’¨\ǤÇ嫨i?ƒÃv¢º©¢š ñÌ’'W¦G€b BQ Übýµ¾ D¦ÜK«¾ÌH²óÒÑF‰ÂTëior: wUíì‚vvÁzF"7[©#ø­‘³)78ëÖ'£Yz®]8£zsŸÏ6˜è%{kÓ™lZttg ©ýf‰ Çeç`d§[«¸úÃóF?”™Ìée(QÄgz䇨éÄs—pä\ƒãÂößxàiÒÀ7Aöu‡çm&#ÝjÐîL}âòl‹•üÎe¹Ýgÿß 9/pMf€Á¨`¾M¶rÃãÖ}:ÎÉAI'¿¤‘¸½iÊ•ý ý„z6¨ÿ(Rcó鎇ö9Rõ(ȇPUÏg'miÃr9CàÔ7¦þy—Ô€iÕƒ,¢¸ ÷Ý©½¾Ÿ>ì·ãlÃp =lk³ˆ J]´9ë?”6¢$'L!¨ªï­ALž¥Ý½¢ãƒtVÅCs\Z€5€¬NõhlØl®ßºÖÒ0ª“ÜL›*@Ï!è8éÚ$€Nì‹È,·gÔÞ/ݯòVõï¸zE´j‹^läôï’IlÖVƒ!VÇÀ˜«õD¡ ù-êûK0âÄÔm¨X'*ûÈ=¥ŽN@õD±È÷è ׇÜ,Ö6ÉëLjçØÏŒœ7 ñýX§¡˜Øöìw÷@;{ÕÂ] BªkO3g BóL?t]5ÜqVº¦xüzÈá«Ä›×/›Þž†Ð5ÒIߤÔËðˆöf\¯ uU® t{ùªŠÉ¥›Ö?Ÿâh#÷ñäïT„9ªïnêÕ€3º½‚îrIOãÈrßéz î ­õm~öÆ=ˆà‚ªÂ>`®Ã®ÏÌ8˜š >:ââëÁ‚ð»Gv|TGlƒ™‘vÏįœBg˜š²nËÃ4?é‡Cè x̆9ûûuìŸûjæ$›Buì³pj²Ÿª € aQI‡¼í9Q£‹”@púVD(Òy%Ÿ¨'û›0eÑüàŒTò“}øïØTâ&[ìÉÝs(ÄÀd0ërl>KÞœåè4×  ­¾X>ôÞ?ïÁê9nÏ“]Êr¡ˆW·J-)GÉDà\¼÷W\CŒ7Æ?OA¾j5'ë0Пœ›]§»2ÒÎÒî¹p{ÎlAŠôÝwˆºV ²Jt¿¦PÅÍ8ñˆ–9É´¦ÁÓµžƒªZ\ç’ùDƾ¹tb @hpµ^\|^Ç—›kµDj •ŸôþÖÅ’J¸nÑùÂjж» É½Dw“â8“É~zP¶¢ò¤jJ;‚–Ië™X{©§Ý[ãè]jÔë(Kr·_£ÍJ´ËkÊ5ÍFQ1NÉΨ"¾-‹u‹_ÒHwÈß?‚cñ!H¬¡^DF6ääRw£Ö¸­D3.§ :§â’¨@&¡ˆÀ)K~á±M6 AŠ«½¥ãµHî»i÷p\ìÞ)@;Öh@ÈÕÒÎMÌ X ™Ù®:â_µ7'·²mßQ•üÐê³i ŽøäOyy‘›cŸÍØÆæ-ß_x| è×Êi€+‡EÜ`?o^”më™M<þ-ðêá%¥`÷JPhŠ!4Ápœ·q:µs8wŽs†Çm!ô¬qÎã¶M–Ô>©{ÿSnNû]³¤ÙÚ æ8e]EKáø {=F»!x2‰ƒëÛü8c ï¼ñÓé±sõÊ‘d‰iÍ-B_˜3ÊžqÖ÷!u#b‰pDÔúï`¤Û]züÔ”+ÄX¨õÅØÍvÍ«F‡ >žǺ îWâÿ‰8W&­ª,ÌaÝhl­Vå÷Hø‰ÀÓªHÜ™šø•^¯i?ÝW¼›Kýw”%>¨ª3öWnlYìq«ÎS7!EÔO ižÌgÿ Ÿä¯uPìC4LÅòa½¸òä÷ò}Ù°^Þä_ÊÝûhÐQЍ⥙©{Í Ê1œÓV<ˆ½xª6È¥Î&NÞQ5¸»ã-íì·}*Å­T´ –Á-Ežgî#®þêÏïwÄx':˜£j,äê ÍC_f·³/¶аj S¿¨ÛAõÃ]{HÍ#Ÿ¬.†ÍV“…s_§g÷rÈ(ùD½¾¤âš›–; ½‚øæC¥À@ÔuÝ8ƒewäÑ1•:ײ£w<¨×C¾›»ÚÛ#û F«&Ø„€UÎOëfrLŽ›N.4 fø©L•³ëâŒT»\…]Ù ºefÔĤyäWŽí;cÖjƯäO¶;ÆÎâ+å$lXíˆ?@Èúê¥b¸Z­êš2Ö PPY²åMq„ÙRnêZ×N"õÿ9¨A>Íw£]¶ÔNùiàÄ/{ù‹{ Çg®R! Ûìï0cŸQ~ ‡nB7@zTõ’&úw:Âáå³®9–[æz ŽÙbÈPžàŸ†£Ÿ¼SWDd·w‚ á:?À‰ölXsËÙ[(µú}àð-2yQÉ+ëF4Ì;Œ‰ˆ±‰l>Ø0† ­ÕÜÌ@En+:\²KFÚz}*P/&‰í4 NsÚ Q ÖWW>¦#¹ …+‹ä$ð â¾~åÀD Ð9‰¹ÇM{M= „ãæþ¹ßÑÃd@¤”-‡^Óž iærÎG J¤>P¨®•èmü^c4(±¶­†çìäù2nîÕí?[Ÿ4ǹñeõ1ëëñ=ÛN¼ææ¹[_Åa;U»±Í‘õoŽ®+"ó°]“1 òCŸ,Ù#ÿfgNUˆ42rf®Ü¿ˆ.‚,~Åz¹ÕéXˆðY%Ï€xTÇò‹ÁÛ¤?Dæe'/©P÷jÂkœ>‰w[)—ØÅÿká2­ B<­g °" àb 6Ã¿ä¬ i8ÝÃw{O‰Ûc„œ«N'öØ5,ù‚ÛêÚª– 5vÎxË^ÇGá¯Ø€`àú¬6#lþ½ëÛH‡ç8&‹˜ì–´–huÛ¦/>eÇô:¼¬H݆õõ 0Zšþ§ÇÀÀ] ¸<ô­éXËì<êp‡×YéÊv|[#ºš óe›*ÀÕªýLOS†âê7ö8&Y7J|¶‘húË5´'nÁÍ+ ¶@[Ü& ‘BD‹¢¶rÿŽsQªc«¯[ˆ²ˆ+Šìî;åL>±?O4ߦ)6Ðwº8á‚ýó5·‰¬! ó3™T@ý æ­6˜é‡ƒƒµæÉ7Ù¸Ûñ ¶“ KæWÆ™l*Pîè)XõÝnnÏ­^Ä{Ž)Hµ^’ãêq›ˆ8¯9§Ë[“ŽÔ ô£ÓD… TîÏ~Š˜ƒ3ÿ#±>¼ê±Ü¶2cóªycWàz·ß¡9|D˜û,‘@”¸{çÂ-QÜÕO®jvߨިÕJHÍnÜìó <8kÛ!Le3wâGÖa%ø‘\ͨÀ¼0Û\Eþ¨Á8 Ǿ¬E×ö;Š=']“ ã†p·§ÒÂ8" È-‹Žó ’—™u—uÃ[]ÛË=,d—5+‹ìÐ÷òÌÆÖ›sj[Ìà<Fç7ô?‚Á2àlú³¾¨>oÁǨa¾ò¨$­¯Ù!]¹TcQ |»ç±LÌa…«g›ÀVn@îÄs¢{¢'.Â2BY3å3[ë`° $rk—c/„IöëºP;f€sFžd‹¯‘RÜzóÈm-|ú^žr@Xޏ:ÉñºòÅ!±~7d-Èi¤Ze61nì³=Šû6‚éE` SÏ…ÉíÖsÍ£‡1œtѨ4jù7ù~õˆKíöKzýi|¸†5žWŒ8X³RHxæ)¤oqîZœ;^,õœ~o#õÌ©L!‘‡‘Ÿc»ËWMjôlê:i€«d¦ËË)m3c–XC®¥1¿mv¿0*!YòdíVבÖÓ+LJÜÍÅ:^ºÆ€ ^¼îé”MϹHôà$«ÞÄÛ[‡üh‰ûY.÷hL.¢“E÷¯ $Dˆ¸DÕzÁxÓd¢+ù›&pJQ<‡\$Ò'ÂÈÃOˆ_¶Ae%†zLgmcì-Ø>çL…û‹d¶Ë½Øb)A hï<°X–S¾Ü©VÎnƦW®±ìû9õË#»5!Hkl†Ýzñ[—ö×$RqÌ™åš]¶CËÜúÍ;¿)¨DNk†¹3>Ü‹•ˆ«n*lÜàÄöÅy°Á1&g$ØIÑávÕBNS4üv%§ R£ÄyàlêbÐ2Þ¦Pëínw…[¼²PTÇlömeRÄÓ+ˆ«µ·Óaé{°ƒ ŠÔÖïàÖ9”Sîæ–À\É0d.N?Ú›ÇOjiBV¡’BËþ®ãø¾l£®¹e¢oC;e>½iRI¯Ÿ¯¶ªJ×]-FÚ6;y8¾o¬TR¶R¢ÖÂ/ßéë'@àդϴŸ¹ïogÜËpwg‰€d?MÀwBî£"gg÷>|¶×aùñ ±¨eÝ…aQZt±Sš<çöÈ_WJoRy+’%pXÔ±ïÁ Â(Tzš ‘ W¡ÇEÔ¦ˆ;&iÐL™@‡úYX¯.001cRg+çåæ±Ù÷G˜׋5ä4¤?«ÞŒÆMw£6tRFyŸEúòz/5=µŠ›j¥²@½nÍ®Xý2™a lÌõ´ŸÅ׃[ð¹8òÔû:FµÛp'¯65PêÃ-^ªþñí1ó¾š6okpR›å£q}.1Ç~uº…[åäSÖqÙŠEÞ@èü¶wöe½K´”ƒÄg`õDà¸éšýˆƒ¯.ªŽP?'v]—ðP®ï&Á¢Ö›t•ó֡p WB[”0½ˆÈe%;é%s%Ô ÷Ð5îOÎÖ5ç@mòÏj¬b8B:¾FǤe”Û}œä¢Ì…Ú9Ô óԵ߾üÉ·5[QÂé¯`›u¾–'IBN®Ô¢û-‘TÙqÐ.QIû=@°:S<­@C¯¿.3²%·‡â²Qëtöõ‰–FVä³Ö%úhÚÙ;Ö™™ðUöÎwz&õ}à^M‘Ú¾0CÓr¯¹ä8¨·áU¬Íð‘6­ ÌLÌóÕ¹…Ë«ÀÏsí³ÜàD@™Í$yÕ3Ö¤4Cì:réÚ·+’Š=26ªž€^|"p½´B\4 dg3(€geWÂá%’ö™á*6¡ …Ë0JÏ«=±çø&*â4ˆÀ‡+0—=ÿ”ì/!•&‰íò‘Ší“Þ[DoŠÅd‹]Ô/g‘Њĕjÿ0WRLZ,AËÝrô¹sIuS*ÈÄþÁ&‹cðÝqIëåÕÄeÔ€÷ µ=[v^aÕŸí5S9ƒ³»ÓÑ/–°Þ8Vï¼U‚g‰ÅzÈ­l‡¨BÈ=‘|¸xÆÜæÝI0d³ÚÚk‡¼:Çþ j «C)0µþª‹·º¤“2Â1_{N©5†ºþ*áh†å\üÐ¢Žƒb»ÙÑ¿ªSêAìR:z\ÂN%àpÅaŠvÎ#WWçtFÏÉ7Éßæ#IY\¼ƒ•ÜIluÄqÝM)]Y¯{ôY³)r,kZÁ#«®ÏŽë×:ä(9¬ÆlYÎhmC•ˆÜoyÏf]ô,CvÂô8ù>Õ…ëôn½2+èãšË‡äÔ"çÓï÷:É„ °ñá–˜$=$G‚rV™Ð@U…Û6HkŽ%€(@oü§®öBã ã¹ÅÃö(:è{Õ¸çL쉣CÌè‰ç$fìtZîT¿}ŠíøÆáj$…ó \ hÁ Ü^Éq.˜¦§×¯´A”7×·.™½¤-Ú]]ÛyªÇv½äÉ¡ ìç‹t¥jê;©º «+U°Ç¨H¨ž™bWs»6&ŽæM§á%™oò”]^»€(r2ǽj Ðµ þ¿_¬uÒPtxáø¥ ‘D(r\rWƒ‡Åë8yXÍ ¼B®Á-@ò”ß}M>|°›®ätëß?â~;·4?Ùû« Z,j`ëh]G¼(ܼM[Fn=Ö™_˜”la³×­®N)ßèU[‡SuHpÅt• ‚×ãÜ%S…¹rfã9BH™H7 ,ˆQY½ëÂKgj;€J•‘Õ÷ênóÖåk—®ÉÀkø² ¡2 °Ž„ÎÞ°¦x³²jõþ31˜˜‹×¾ºƒr¥ B$܉6Å-|aSÌJµõy¶e¢|—_ÏÆuG®/ÃIK~Ïá&É}€ÆÃS陪üÁm‘Úa•v”@9»ºçDጾ"Ç¡Âj~»ù§ôT¹cÕm Lhó ÐO;<Ÿ3gîaäU9ÃO¸²÷ÄÑ ©;O“U¦ÚTm–­ÎäújöY¿^9v´éØÖ—ÑToé€×Ð{ƒÎ©ûˆÅrn—IwÇgḄâ5.×z÷ùÐϺáiKÄ쿼(>3ÔIM'èuîy£_ %Ϋƒj4Fã:‰ÅPŠZhØA/Ç=ZÚ¦.ëÉDöR3@Ù-výe¤å®ä„è™6š¸u\cÒƒ_ªó“›£mÓM_°y˜Ç¥ k†wÔ–ø†á‘Χ±ôLz kETC„O±­ä©¸r“¨ZÜìº(¡f‚1½NWÛÌGåÄ"ê¤Î1JãUjÍ ½0Géøˆ/éØ »Øå*Ò·P‡ æîz±¶‘ã¤.!àLÆ-Ií •ê$Ph¾¿Ø …^<Yé4Íj¥ÄÀvмÁÀz”ˆ|~÷\ÿzÄ;òê9±ã@¨ ‘Ò´ÜÁŠÓtÔõÑ^ X§WtL‡N"æ«ø /a‘óõˆ*¯ŒÅH‰aµ ¾’tκd¸ckÏP½'rö‹ny•!.áE¢ôõ¹5-¢¹ˆ1­$©óV‰˜ÂÃê!ÎæÌ%0t;GR†¼@–ÙÚã£9¼ÇÍMÓ± Àhq•£µÀæUæ'Eu%ÓäHåI@ƒËž_žxkÝìjò7õôr‰|“÷¯h°HVl±µ¨ÓÁ²FšEàþÂ-2JŽ8Ï2ápₜvvÀ´ì¯ „rÍ Î|Ÿ׊ÐìvfX9¿SÓZ¸;˜´g+<Ù Rð¾S¯EVðÉ y´NÌ«UÕÙËV­ÛLHGÿu­9b¬±ËK¨æ1ƒ´%ÖgU¤w*ÅH‰»À)ÜUÂ…YûÉzÂ?N×$XË"Õ×NB|à #Þ²/…"ç÷F•0—ÃxòH¤ #*ÁE&¹Nvj³Hc~W@VÈ™k”_G¸jA&l­IFÈ’E®U„,6A΢½XiGfá`UühØ4)TÝâÖ’=0[ßæ5`ˆßÔÜ‘Ó`*r¢¾œ±ðOGž(Ò™,¨”'p¶#Xzµ[ଂlîJ2Ýhl!Ù!9pu؆ÝoµîK %lòÞYCDõóÉ 8 ÀI’¤‡rš—êé?Ëqïè]ç¨/5“ݯP0(Þšã'ÌOŒ—>‡1bRÜiòá¾îùÏ-41µz´æ¹š ÕÅ(‚–;.vbY‡GŠþëR˜€A<$ÍdáÔ=ÕÙk ŽÄ¥õrOL½³êµm•€ZÙæˆñ ¦dFÎ+uµõ ·9¯¹ŸÔ£ë…![zå ›jç;]‰¤t]ÍÚ^Í/¸w3ós  nôC Ð8K @P/Ùøvb>LÌwAU§ AÈó¼ÊÈAš&d8šÛŠcÚ5Ým¹éž?©1 ¨Þ‚dýiÓ®§fëD\Âá¦ÞÝòœ%ºŒi¹ ¦ä|¿ ±ØŸDlæ5½q¹øÞKD:еçPºK@Ò ˆ\5rê¶'mJp '2‡±•š|UÜ÷–“b£`kÑsä&’‘Ñ 6[‹ˆ^{ÈÍÚTiÅ;Ïf.—kè¾xÛŽ[SU∶7Ò†œŠ§®¹}U]D|®‚Œ\ð©±Õg}‘î¦e?Í;¯ Ö'ß»^®×öuï…÷êÂSñ÷§E'¦ÎeÙAcÜ’ßöóHêŸù vúº½¢f~…XÔÓz¡3¨xŒªn@X‘oÚ¿Pý9‹qžzó‡ÇF#ùJ=~1c¥ðbd™RO{±c5ÙñäaªRmPOe’ÌËÚYFDÑ™³›Çã {SŸ²EG 7Õ¸ÀŠ«Ä`¢¹æ]_ÅùJÙ].[ÂToìmt{Ñÿõ²rTû£º:9ž®\žŒéHl> Âçd7¡t‡¢='bzûÔ©H¾'Ê+mè)!Üïç^ ƒ‚Àq±0ñ½@(nu4Ä‚<Ê÷ù©,ë~¨&T*™ÿBíO8oठX+ ¾z®ŸrâÌŽM‹'_ÙÚ믉Î.õ—Û}ÖmûH|+Œ­t „p˜¥Avéð‘ˆÚT$ ´Ío_Ÿ_Ôܽ<9Ÿ'öm” ¿÷Æþ5{q¾æ“ýw Ü¡‡›ÜÜꎾ ¾´åaÃ…dûÓ¥jÓ [„îH:Pü ȶs½ kÖDÆi€A Ñ5"À~+P'›<Ô€ n’Ô ³hËV I#­O4¹wp7û^$Æ4Ýl ŠŒ\"ü.ÊäçfªHFým%@å<ÞqQœh± N©-¦AüÇ,2‚–? fgVUiŒÜcVé«Cz@Às戕ƒ­¨NñQõz¢éê«¶jžîXq,qÙ)5:þÈ\V®ßª.ú A¢î$7Y§6B¢K¤ùR׺ð<?9õÒ 7ãásÊ6€(˹;œãŽ}j?]‡•£xDÝ”r6€À…ü"1f› .ªóÒ  LW¯Ñ_\~[aFÙ‰°0ªÞ± 7{bP¢ºt -{'ºŽ#FgÐâô“„óX#,dʵ²õK¦5ýè*rßa«Õo³zäôÛÝ<Žê­ì„ ÌÆñ[õΰ¨èaªŠŠcÃÎè.Ë`rÙòôQ~­_Ò݄̿Eû1QßvÿL'Ä®@þ2¶¡u]é’å:uÀˆÊ±Z¸Ÿß£wœ^'¨b*ìþ4RCå¥YÕõ*÷oÄT¥¸Ñ9 ö³ÎD>Ø/í¦ºçïmžài¨]FÕbä¹Ww8„ð¶I¬=Òï€8ã‰Ön°Èê7îÒbÜ Ò“Ÿ4“é¸'NžK»ŽNA{±<¬›¦¼e媬œsåÕŽ¸x£^E> ÌáÅq…¯?™(â!\¡‹ÙŽ‘»|æñ×À’ &]ðCÂÇØ|«×&ÇuT¯ÕªÄ>o‚üÍŒœ†»Fz" Ì®ànKöMl÷:œ­éFô[„¦ÓÊ«B‰ÍXgEïo¶î*‰U“ež0­ZB=Û?(™]ÿ+7MLåX° =\~•êU[‹(-1¹sçÔÚIü„ÂÑM”_›Ž¨Î(Õ¹ÊÑèB§0£`]ê ƒw2ÙÍ«Q¾®9~ñÙçêÕV°AE}œCšê3±Í˜ßFÉ£ž¥Áö"LCÚ,j‚-mÿÅðÇf\v­Š?Pu &/Ò xD´—£Ý25²þ²I¾¬Crü‡ªÛ|ʧ£T”€œÉŒbãÌ&œzO7 ÎÑèïZq+‡õ&º¯ÑZ' ˜@"mdÓÁÂ8l‹„˜ö/WÕÁáKR¥Ž[̨ãð{ÅÕÇ—M\.!=ª‡V¢Qh‰pŠ1,‰ŠÓH6!P’èžÁ G>È£ß]ZçVʱÁk«ƒŽÊ¤,ˆ?9ÆÐäu㘅=rñ¶óÜ:„â–î˜WžÎ­?|E6€­Ípþ‚ê:teD¨ñJŒ_ÇÁ&éî…’>Љ ®ëÿœŠæÊ¯Õä,Ö¨¢¾1¶˜bÜŽþ»5¬ y…¼Ziqjjí J<n- ¸ËObÐb§kîQX'N@ʱL@š÷W¨b¦{Ë`yð» 5¿Û@øœËî*ªƒzB5>²8ñèì¨Ò&Öw¨ÀÞ»Õˆtà¯;'uêR›œ´ÐÄ-`–³N¥á¢>P6”TñF RMP—7‘“ã=¤ÔÐÀK‚Öz{DykNר 8uOÀ6NB_MÌ®r¸U6?g8¿ÉÜÆõ8ÖmÙÜÁ _· &MHÀPqøÑ½ZŠà“þ–ìæ†roA ´kþáë%·þ½ÈI„à H)™t0w9÷Q°Tî]ÃåÁ¶gVúõ ’H~`'ê½…!ósÐí܆«bä|8—²!H§[wÚ¿j½}¡ÎeI"î›þ¯â¾gÓr€}T5ÑW"y̱;Lšl$%Ô3ØpÒ»2ƒBýX¼«Jzý—§Âl‹ËËØÎXâo’m½È¸J¢ŽÀéãTÍhZu-?]y´¾wñirOÂà'ÒËlìèµ³/01Òb§´¬G9}ð«¦öTDÒîy]„Å0U€Š‡žB©nëËÏéîGpwøºœÎM0ÿ€a0“Ù•2|êȤÔYP½<:–çz‚NàT–ŽãøR˜% 7)â©zPŸ‘›9°Õú¸HYÌÚñ§K‹®î`„v·@úÈ®M/Ý8ƒaˆ¡1X#VƒkU<"p·³}ó¸ ô˜£?e2œ£ ÚÝÛG€ªê“Ýæ/H"~õš£B—ô²A)\xÒ~G!Gúr¸àQ2VŽÃ¬~¦v [ätÒˆ6ë%‰¨_¼÷WìºÏ}ß”} Ú›UóE÷vmkqÜ¿MWq ˜ÅNκCO:nvüWÅõ:.&µw7Ý຅gê‘ËGNt‡Ð8nK9tEú쥒Oé²A€¸KÿI×bqSަˆ@$ô—Ú츴åñ°kAu\OÎÀ0 òÆï©¶;0R§„ *"mø yÔaR 5öÈ_ðÁ>–&t9}Î rfðúÇå)º>B¸ð¹ÔpßFŠÑ¨Hõ爵öX%švFm ’Ëêuòãh©ÄúCM9`V¼r߉k˜²1 Beƒ?{ØÖÖ|wFl7´rÇ0Šî•Ó*'×Û} „‡MüöuZD¡Z·ÑK¶B°ü.²ôÖ4ï´)”.h˜„°âÜËøl[øLŒ€#" ƒTâÂèR()lÓàæ»á6ŒrÌ®F–‰°n…kØáµª÷_}D‹"Z»¾WY!¶©í%b÷¼ªrT3% íhvůDïæßÔVX,Ü¢[šþG(Û~ü²¯-L YÐòȞݪê–\/Ù5ŒÛWGhTM,¼¹Ói«¡¬Ì™SkÄë»ä½÷Ô"C¢=É¡ JêjȎ骦éîY^"ê»™0±».]â\Û)m§ŽŽ>ÞŽ¨&]ÇhPÙ˜ž3+(_Yh¨¾uþ §k][¹p/¶úŽÁìî†uâwg#xæê! óË7©CWM#-¦«Â’QTv6ø›_UnlÆÕ‡i±9€.º@‡6n&3”²å>œÖûÄŠàÅÜïêµß#Ñ}ÝZÓUó¤¼Q$8ïÞ*dì"U·®±H7êâ Ç,­ï” ]$Ä–´­;(Ù¯¡¬F<©~oãSAÑlë×|M VÆÉýv ‚·4å\™À"™C¿ú9±ù># »ö"®sGØòå®÷•³Â_páÄH¯ü¨®oÇIÕÏu]*N¾§‡ûÈÓJÉåu"<¸¹á`/RG0.$-ëQ\=‡¨Þ ì¥3sé"½-Á]¡æe&ìO9Ò„°(äk£ËjóN/Ý‚éÇßÎð`Ògl :ÙªO›÷šèÕ\¹(;NØH(þ™|gW7y$p—r8©Al)²ó"a=£_ë•ø ¨Ü[Òj?ä,8‰ ÉÚtLj…Ò¸#~‡‘=J4~Þ•ã«R 0ÉkÛjçµÎ[ãt|ÐØˆºÓyÍwR©và ÛR’¸bu ×@”Ú¦9ªà Óþղ߯ÜVf)¹9`Ö=`O½Yœz$ö@ƒÂ´hh3k³ìå«7b7±ŒƒÉë mņûv‚Юę¾m”$®™â)›ø FfŸÍŽã‰§Ì˜éÛ¹vÒ[ä £]¬üS˜Y¥%R#b®]pv•"¦h$+ JËÙí‰O¿ìÏë\Ë6¤ì4@ûà[[Eædè nÚ¾÷#°c[Òw[‘Çëùøøÿ9͈'^-$µ‚$V¢®LP‚üoµø×º1XºNÏ’NåË „õN¨ÀQKt â‹º¯OˆõÈ zu(ø ·‘³ßEJ‰}D)ãZMnßXƒ°³xë‘=èi}¿Ä‹ÆA²lLªŠªïy«“Ç€àÅ$sØúMø¾šÂ-„Eut•D"t}vk…ô®‰ì"L”,ÅîàÏà›}@µ˜¨ïmÕ¢*(êe½ÛÙ–„=r[n|>!Ñ$mˆµ ™>ƒãÀFòlÎ)=2×ÛrEwƒ¨fù¶QKÛe«ypëß`G@„|ùad$}—@7ÿ*ê t™ˆœk°Jvfœûnƒ+ è¤éêØAbà3á ^è8û«ºÞÅo"@ 8bo<¶®+[á:<:ï¨@ˆHÓN äŽÇ Üží çcÇÝ+± 7O†~¹Ð[¢^x„U@dÍìônW·÷TÕ¥–/MÙ6j Î@n4 yne-¯¬zIx,“ÅUÁ"ãà(2pJŽ@m—«ðâ%öS¹ƒãÜa,eМlg-€rPµ3ôNÙý+å(iZÂÛb ½ºla£¡pK;³£}á ,÷Æ­UÜ„‰üñ>ëK%*×»ý•§™æ{#ÕøGª[Wøx ‰sÍŠ*¹È9|ðÄà Ž{zF¤)×ï°X‘Q‚¶hølÝÞŠâô iÄqW.*\ô"D@j8”Ž=¦úI]þ ™Ó´ÃZÙ[[Ä‹1Cö¾(á$£J²TƤhI®Œè'0öÉ»hÊúð—,r#¾r+$)Ð%W=,ÉP}£ÖF @y:@>Üh©•åqGQݵŠO ”Ài¡0lCwS[±ÒóT町²q¯±Oû+ƒæpeµƒïúâ¹µìaøª¼Í d†-]uïäY.ävrFjFýôúy×®ÚüX{ž Cç‘qóvö¬ZûäÅ7oÃpÏ4‘=”›;ë« ºÀƒL](C‘§Ú“‘Цú?±P¥*§6plÒ €Ç&$˜7ë?m¦ªû;à·^zWz=¹aÑþ±u®ˆvW/z—p%ƈ‹yòÎàêÍŽb¬»[ÌKp6Îe.m¤gÝágc¨™C;s"Aä`ÖY/錅KËï[mdŸùy`„ˆVÖão>¿UG¾.DVŒã‡ª·³á·íØwµXè]è9ñ맺µbiJPwª*)©êû¥ä½ìÍzÒ¾F‚Á®)¦Û—rd|æþ™±ë’ürqÜŠú2íb¥ŽJ Rk¤ª$ŸðÕGP® #m³ˆžÛÂ}ÓrÒpa9£^§Þ¯v¥aâ_ Ã ¬º 71~™\˜/?Hi¡~¶—¤èsØxCÓQÂ`r8o<•¤D–5Sâ`’”¢ñÖuIA|€¸ èµk[•žD '¾‡K<âÙK Ù¾‹Ã‘Je‰”X²Q=ˆãN ªÒ¯–­~(_©*¨›y®ñ¼¿G~̬0£ !ˆí;Õ€ ‘{L”ŒåYa²à¬%Ô¸–Nõ^¼¼ŒÖPôþ+”u)7ùÖCHÆÈ8ÒmºE˜§Ò>¡îçsl¿“àS=!V¹„÷Ûögºt¥¸£Ÿ~«2©Ü´×}'DZu}·b}Ë­=¼XçÏnr’9báÕ6åoè·ð˜‰ ÉnιeÙp@[åÕ캡ÁBi¶#å<á`÷¾!‰Ö6™44"§³ àö739 Îhëñ¸§ÄFvà ³‡‹GW9ü1ò17íÌKï!\çUëRЫ@ýª+/!&6V|”âZ—X÷õ–¢f"}÷[§^FaT«Ì 6sàBŽûÉoׇ!±ÜÑÙ¼ªSáêèî1sªÔ^ýä ÉòEÏÛsÖ]á²N“2DLC!§€Eµ³$H8´>6ØŽ®ã`Ök» h@ÜÌœ'kі̓ԫú=“®%vmýÞ–Q §ô%7ìSñp‹ŠÄ“=èPÞ7Æ)û”3Õn’[‡Ý×üa[œjHïe¹e%é,N!FE-Þ=ÓR[4cGÊœÄ"Ö_ óMÉÙ:‹À †LN=÷+âàm~µá¬Ò‹Â5à[Ï-­óÔVæV†çܵrïݱٺRµŸ±}wg@ã¤#b}.âð]û–íàRZ€RBAtªA[ZÀZ(5‹ÅnýµO£±‡}®j…Í¡:fÁ5J˜®yY0nûó%=×—>÷¡Ú{«B$ÜÌ™'NSUˆ/]ói@‹»Ž€@¬í>#‡WÊYŽº²P–KPÏýË@ZTãZªuçÊÌdK®.FùE‹šVêgAK([“EÌl‰TƒtZÔ¶ ŸÙ–Ìœ3‘ös$Þ{D‡qðpuQ‡ÁF$|›>Œ¹':!@‰{çׂŠðYß‘®—ìÄný'¥ÂÅÓÂæ¤vƒu ŽŒ08;øàÇ[ƒ—0Q½ZËõѱbb7nŠChåv?«ÆÁá»Ö­Ð™îdÐxµªdÌà´!¿[c§}°W9‘C^É8ýü"n¡ÞU瀕|¾u€÷pcä«ÅÓ‘&äê…aîš,ZFáL´g¯¥™j@¸¤B¾žî"–óuÌÞL±ï)ëÂlżƒCg2jð3² (BGQŵ-%p¿(2‚„¤ ‡!ˆª“¼°uúϹ¤ªÎž€„´(Ÿ$6_–åÄ:Or²/H 6~qôQY¹¸FÙa×wD뺩¬Ižö5¼«]‰Œ2­ž°¨+ò[æW‚áöq$g@¢`á“|_½C›lÄÍšEþò.¡p€éêÃG ’íÍæÒV ÔÂùéÖ«´åÎ'2ïE¯‘¿µÇ>“¯[‚Xæh×\MÕ{ÎŽŸ!"+¿{Ý^9cÍ3Ü`6]9ÄR_üC޶²Ú*‚|«yÍêÂfˆ" Éÿ\‹ó›€î´63 ÊÜ8{•¬ÕÀ“j"4ë!…]úv…PeQÁDhh¿Ÿkñ…av¤ƒäíºg¶ ‰€ƒÛºfËnÀôÏò À–Š£E¾úp«èXƒ7rƒD oÀ\§ÖY_ÜÕJÏêÌÃHEœôúž ‡˜\/Ù&ݸOy!];\e‡óÔWú¦ìÊò)·oU8Œ`àku}©»•dTLmtõª×#3¨n¥qZ€hQ=.Ä@ÙZ±u2êlŸJ Ï ×>˜ü#Mr‘ƒ@vð‡kK¹ìÖ\£s×:ˆãŒ©o¡cÂÞî9æÚc¥0´,"ûà°P,ÉÝ´•Nw0$ü ‚gkXS:<’‘‚,´N`Lû–Å£º¼x!V*¯¢1ÓÒlHHuí‡hFz9¨8§ØKÏ Ø÷ÕYè½7i7™&À\ˆÛñz=ÊéM‚ª‹û1DŸ†Òo ¨ñ\‹]qÎqxqµM H )í‘^ m\ÇÂ}½4jÓÁ×.g§¿û~Ș)"¼.;w&¡~a…—áš_‡ò<0$·:M&©‹ÂÇPpìà´Ó$jŸ3âÕ`˜ÃmGLÔãòhä>ý€ M{ÁŽãÿ2-u¯•tƒtÞpðÁðªœí±ÒƒUSvj@ Ò¢—Q· b,ôy”ÑJÞ0ò*zj¨pH5PQnµ Þà5‹ß&h$Ïå9¶iz»Ÿœl°ï8½‹Ï§ˆ–a±îQ+-Êý…âÝÛƒÇÔF6Ž·gêÜÉc ©¢!ú»Ù"¨«[ª¯<½D$&'²KAõtV¡ë$GZCÜ:öäg<äs†K[¯c9¢•"˜1k åÿ×T6QÛ¡ß+’í+õ„`¶å²ÕwxZTÝ2H åýP×µ ók|üQÈ¿NtsŸM&\Ï»hoµKZžãªÓáOö¾áð,ÜR½ÀÄ^2%8÷ãöˆÝV@Ù¸d¯\«–‹4œ¶à@Ùl­Ê#²VKÕž©ÛÉ‚¯Ô3Ø7Ü´ °¬>¬¤5˜…þ¸fTep*±>w¥í >~G¨7ÁíS5ª¨Ô‘:Yc¬ß«Ì¨FþºþO‡ÈW(!Ë]€¢¿ÁÜ)h±Ð>&0rwÐÈã£Øfi¶}<˜Ýš‘.)³–~Á5g`ÊŒW9ž‡OÓ›`…§øÌ#»r_9ÕGºÏžÒÒ5iÒY¼ Ö¯Ë\­»R®!~ÁP#9ŽÎ!:q©²¯­œõ@’GÖìúªt[¨‘¶ß‚t xAŽkƒ©3¾{ÚÊ3ïàßçø®DŸò¹¨«#@’7'§Cü¤R ¯4 2&ä`¤55 .OÈû—ëvŸ÷~’‹#ËA êSŸ«[¯×%c‹vøphÎBYIw«×‰Þš†¥%2-á@îöóby·9”ŽÀ•ÕàØ¦Šõ‘Ãñ¸¸9SZi§FAØ ô¶*¾ñ¾Íe^|ÿ;úë†à7Õõ|EÕÿuÈA? ã¡°CÀÚÑñEC 7·­´fnØìÚE«°Åº™3 ½Dë›YÕÝ”†#åÍš h¤ÀÍïäTrõ‚ˆìÞ;/ýUNB,A7Y·CÉv ¯3ò„|å %È©¬@Å9i©[La[L»jŠ êzá yv¹¢q-H¦ªÃÆ‘ZæÉÆG°Ó~mƧþŽÊÇŽËçÀé©êïi¹ ›\Ö"|ÈõÅ\HšÎ™Œ-·‹µÑÉs³8¹ñôc˃EÌr"c¯œM¡½˜(ÝíÚgƒ>d:¤ +ãvK˜GÆ>[ÇcI—ô}XoAèL'=‰@]j{D:6hÝt Á”øäƒñ bêÞ 9 ²”sTP¼úu›Ñ#™˜gű§YäúZ©ëYý8D•Ú¹ ±:P2“–Õ—5ŠÑA8í×ðç¸z+Z+râ+‡_ìV)È[Ýdåàˆ!–(?fäbˆ‹¬PêàÆš&pá:×rV¯˜ývj8Ø$,ÁIvb&»Ó|ü ;+£ͬI½£_ìNë›Ìbøªf÷З59÷nH_Œõ€Ìb‰V»TÙf l<}ê¤ U­*2´‡eÛG@îìž+€Í^ 3ï‰Q«”U¯Ôå¥$?Ç:"ׇh}ñ„kÀ[ydºkV§óÑHp—‰4% å…i™ê8Ú':£hýâCÂÄRAÌ„°*k«Î?ÍSòÌ“£2#[„;Qs \~dž<„˜‘÷­•%g"€…Ê9îÅ€0dN¤“ÐÆÌ56öŶ'o®_;³Tm7g.ž°á…k’ìÁCDû"Õ¤ÅNõnÔŠ>æm¯Y#׋IWWŠÀ‘žhÆ6Ž ì97Ùª þB˜²õµÅSe¬\׿¥=O!‹ˆfç‡\¢:Òs+y„ xFkÝô¾'ó¾e×A-X\«á ên ±H`u­¸Ìc"Ðàæ†éÚ/mVd0ìuÀfŒ ±ø>‹‹/-\{b´ȉøF2+‡ƒôk;Êýj×ÃIѹ‰rœy ¾sˆÀÁªˆñâœÂS%•Ë—Ã2 SdÀZGn«l~˜pê»2qöYÝ*åAŹÆî]Žy…žt¨Ú±‡,ç5h‡ ¤ÜOKÛÉÑ<:¹c~î×âoU?¦h†ôh¾¶F1ƒ¬n ]ƒü@‹››¥“m 3—?-L¾%!WBÂÊû|påFž-î)Å §ðáê'ýß‹èM™ÎÍù[1ßq)r™Vt/Âëµb>J¬Uaèõ]Û³v€hDwUq‚ÕÜ‹ðlD· Á#ìñW6-ƒ«Ÿ*AuUqåëm:äa 2w?XŒBô»ôMU;Œ’“,­³ô+ŠðóÉ”V3kJJ‘ºY³íDöam31uÀi3OQHQ"`R¸ö[|† Þiùà 8OåTYÕ/arÎñx-ÀrãlEy=¼CîÆš’ÙÌ)­¦ß^R~ÄØ¶¢K–×IÈeà‡Sµ¥-€´ ]Å"þÎqá{NÚv¬×Ÿ¯vð,h¡¼—~BÝ­Á/Îpy¦€‰Û‘”ÍBÂUwH/þZ®š·5Rz®o¿]'•#Ú{!ý6¿Y÷ÞÈ{ó5°±ynaà7/[?9„µ °à¯Ðñ…‘]¼éõ‡õ‡V†‚›ÇM×t7 ‚D¼Ä¨YÐ,o; “é¶Ä„|ð(8çz†N·LàÉbF¦RØUß‹ÁÏ} B×!;€z0£=“Ùr\Åë>Ì´ì?f-vÿˆ*2;<[àÆÙiD:1£_(&|0übŒ‘—\+-àC[¹zÃ|f%Êf­\ZûÎèŒ-äŒ!~C|'5‰A0HZ¡Ñ±è/ÊÎ18ɇxXÒ·õï 4`dNŒ;X^êh‚¶ê‡1kÁO°;íæÀk°¹ŸFLÀübÕMÝb² I(¹]÷l‹Ç˜¾Åc4»·š§=¢d“«çµëB/¸nÒs6Þ"…îšãN\dëYu§fˆ‡ÂîïtóP…+§—¯ËàH¼á¥L4¼èoùçôÓ§T_XžðQÎB`­ÓÓz<ÉE´QÂñ·H{¹Ëj¢f›Ï·aÉä„(IÚ8=ŒÚfÚpdR6wy콩¶\%ËèF>c9 ?€É‡nvŽºí0]h)xÿrÅ*G”ûÆ®œÉEUmªB%Zkż–g± ,ü,·Êpu@*ÛuŒzTÔé°ÓÄÎ5"Š¡aUøP^ÁeÍ-lu¿õ‹ª%äU;DqåÄsÉà¸zpöÉÙ~kî 9Í¡Ü[¸mÀC§MwÑ·•ѸýáTF`Ž¢¼‰Þ™+‘×öj_ªËwˆ p€foÚë[l Ùen¿"yxÆ(Ï ! PÛˆLÙ5b-UÓñôbF85eÝb@©sR¤$¼ÿh]ËɤƒêTäEA?©D{-º;»K¥Õj,äJ™*ÌÌP–y~‰è_¶ïD¯¤z|Ö˜£Iâ÷Oœq°jUZodœN±2 — ˆdgñ6ä¦N‡°Þ˜×êÿ3´²Ž ³‡5û~Fqºt¡©3ôÝÖà‰.mÁI¢±›G˜D*„;{½ß­#å¢ÍŠòT¼;[ä‰ÄЧåÊ´Øßmaõ箬Gæèm`ïü[¬kjÖþ!ONCÈSYáÏ}'2ÎEâ\®ùä`7xý•œ+\AbJŽH‡”<À )ܱ¿’G.hL%"Ž+K<–ºWYÁ¢ñg$fëò(1ðˆâÙ÷Ëq{ARnu‹O%V¤7+ˆü¢Ì–×t×Ví¦J6y ,§]H5~ÊûV€†‹šŒØD²!ä2b»7º_)Þ@×ve^à– ¦ÖhoÝ|ÑL=B<¼«|ì‘ÿƒºÖöÌj¸¹a:A<ë²x<¶ ¹ǘMäR‰×Ä `8°Z»àƒDþÉI;zM(ÒFCsCÏÚ8ŽãSOÖ‰dœ³ÕÝ´(7³H5‡+1ò4\V¿ó àþ«¬ªp\^Eq7Â6`°ÒfÛ^tþ!ñVêøü™ƒNÁíBkõ†ÅØMÏù±áz s`I:—r L/‹$âÝ•=’ò-‰`kx•@#¾­FÕ0S(ãäÄÒ WwÃéÙïá ùøXïõqáæìêæžØxé¢k7r}¯=y"#ÙWn·Ñ˜×Oƒ©n€„ˆ uV¹)⌑L4sX7öÝ{/ôðkÌ ß>§SBØ=óž8ô—ÝhZ(åÐ#ÿ\Ô!¨ª ´p8 À8ˆÜN"d 38OàÃýlS¹É {×B´W \ÂÑŠóò+¡%@­:Àµ\ÎwW\e´ÁO>Rñ Sek83°šr¿¦[éÛ[ÄÃõ]6õñë`¯™eËÁƒ^ï*“µë¥„ÀºåPal4s¤…íH‚ aÉîKlšã2AŠ™ãÄ4ó°x„íiB‹HQñ˜Ik/eÿ²ýÖß!‘Uå4‚æH±Ž¯ØÒ(€;Æm¨Æ©„Ëqa¶D@hWÎÒáp ã°UœÛÑ0dg S™É·:èWÓ€#´ >äœ ]µ^U(6IÍ©¬Ò]»2û`å÷i]jÉGn-¡;¾ì|(¢z{?²A´~²yÊélrAfq:·ûë7¶‚'¼Ú&Ü|‘÷ªk&3¤Þ&Ðû34ö…¾Ñ¨xävò"1jç£Ug\i¯e‘[œŠÔÐÌŒéWJìEì»òü°†!ÓÕºNë8peóPÂFîé‚Ô Öª“Ë¢¦°è[7ê!M®kìR ylH_DüŠl}öõhwÁ¬›ò$DeÙ›˜‘'ñ[ok›ë°ÎÂBêÄrB :\8°¦œfå¦ÞFp*Zù½üú †¢TQ$®Žì•ë‚‘‰^gOV’¸EÆ‘îÛõ¶7šTRA»-×Ûq¿€èÅñ¥*‚ž‡›¸Om=NiýR”<0^9GNç8°D‘pä§¹`:HnÜu†« ¶x@P|ÆÕ2˜¿ÑÅIG]så" òtxÝr˜©ìà™)éð°žöÃÀ¯^ŸQ8Jg¸óv÷»û}þÑ;W©j#à4?½¦áá2„_ÇEG"»[lÏ üGúz/ÐÃŽê×4æý±(u†­“ñ„s÷Ž×9w(aÅïùèGµn©§*›1ϯ»Ñðè :Ü,9¸m¿…¤·±1ÚšÝûaÆÆ(׫t43ÏýÀ+ñÛXdm¤‘ÙbkÍwáf¬{}?x‹õ©’äc©dNÛ~\Nàtl•ò Â/ž°_ôÝ[÷nPV·`SDJA`†x IÈè2ìò½Aä6Ÿ„±ª†Âx°œõï†|R" hïÌ£ˆ€“;Ãåz"`ãï&fLšF”÷ˆSW7G֦džŒ‹Ž¹£”ñŸ±ÞMˆÀÑùÚ~œ&È·céø D#B \wgˆ€*†uÝ` ³$`ôÚ24B-£’@²¾•.Ä…"’@é‹×UL5¹ÿ¾û‡bëɈ¹Â­TµŽxIAô’B¬ÐÕÜV6C‚he„ €]8G6}#ØŒ°+ƒð9Ww;O}¹õRChý KJ:ITà㫎7"ÐÅ1KÜóP˘áz¥OEG6q?öœÝŒµ>/ úª‹ò`ë˜pß}÷­]ØG›/¯…8š7$è;ÔAI›¯(ò{š8KGd×%AªóxDv‡¨cdžËßôë:!Ws#•ç8Ò”¥ãKÙv‰ 'Àfhi3" ŸÝ½95*¸µÛJ& }hôÜ䤗j@ÌyÂC=ó%˜_ôý A~€t"Pûï8}Pšî€ƒý}|ægü^<ïù/Àáê·>뙀g=ëÙxÆ-·"g On{ö³A‰ðÙŸó¹¸õÖgáâŰZe|Ögý~Üté&pθíÙÏÆç~ÞàÜù ±ÇGIk.Q=YYËCô½žˆ€H9ÇQy6Ÿõ;ŸÀøø Û×&é®ueÀö#Á†D ɘ˜.o»EŒ51ßìÕ¸çl¨—†J›©~—íÀ{î¹§ì(Ô"눻Ä4<Žuêvô#We+‹®DKrÎø“òËð«¿òV<ãæ›ñ’—¼/ùgàé7ߌ—}ò'ãå/ÿ ìíÃ¥K7áÅ/~1¾âÏ¿ÿú_ý >ïü<ç9ÏÅ—|É—âßýÜ¿ÆüƒÜw¾ú/} ~ê§Þ€/ýÒ?…ÃÃUlu 0šÇ\WD ræÍZïÎg\d·Xk#<ò(V«FüØ’‡XI'$ã1sSvz!û±ûQ|ì‹>¿ýÛoÇ{Þýnü»Ÿû7˜&Æ/ýÒ/bµZá]ïz'ÞùÎwàܹsøÞ×|'n~úÍxûoý&®\¾ŒùÇ?ˆOùÔOÅÞî..œ¿ˆýÆŸÅb¹ÄÏþÌOcggg0±^ŠBGÐý<–Åÿø£iÚöæê^ŸŒøñ§ONŰZ­¼tÓÍ88Ø¿I`ÅÛ½Ó÷¼†(w7d6C i“Þ¨j€Ôá·Ur ÜÿýÕ5¸ïqäô½VÿX¥†D HC{{çðë¿ñk¸ç£÷ -|ðA€3î¿ÿ~¼øÅ—¼ä%xë[Þ 0ð±÷b<ã–[Þûžwc¹³ƒ·¾õ-xï{ß‹ÅrY`@„ûï» ‘LDÀÃu¦ÇËAŽCŽv”ºln×#Õ<·—ÛT8"À̸zõ n¿ãy8<<|àȆ›tlpxxøÓ/}Ù§óßÿ^½·oÔ×y"0ùe2T7Ç5Â¯Ä DEô°·m[„  ;.HHp„!áÁ ;sD@»ÆoHö“®,ú÷C"`ÄPDr°HDx÷»ßŸû¹ƒÝ½=€xÿûñßô&¼å-oÆr¹ì+Ñ“£Â¦ÃïÑ|ÍU·ŽC6kûº®Å[°O?8Î=qdf<øÀ}ø”OV«Õ¿Ø°²PëÆéËþÜW#gܼX¤{õÍÿûíÿn¿ãùØ;¾°Û*é†8ØFé÷­y\fƒ`”{„ûËÁžTwRqîïùƒ?á{9À>øÁöÐᙳ¿ÎJãcí¶sÇÕ7ñ“> ‹´†³3– ïý÷ݰI}oÿíwÞð»?á%¸õ–g®ÕM§œñ“?ùg=ü§|º\¼ `›ž éùÏ{.Òb½h¿·»‡+W®nTßáÁ!î¸ãÙ¸xÃùµùNrúl›žXiKžéiO{ÚzÀÀ¥›.á®»7SsθpñLÓ´Ö²°%×Ú€'AZ,—X,kó<톧á7ßþÞê{à¡qû³oÆrggm¾‰Ž…v›žXéØŽ@ÛôÄK”ÒÚÿ ÂÅnÀ~êg6ªï'ÿå±ÜY¿ˆ£êÞ¦ë:m%€'AJ”°n{Á¸áâELÓôÅ_øÇþÔ'Ð0gr¾W¯î¿h¹XÚè¹ziëÌq½§-x¤âá¸Yï»ï~þ—?þ£_½Z­0MVÓ„ôáоkðŠæKÑúz·èý§-x¤iÊÄß›K'Gãí.ÀõŸ¶àI¦él¬ñgÕî6=viKžiuMÀÉÓ´•®û´%O‚4MyÃ@“m:Išmzb¥-x’¤íiÌm:IÚ€'AJ©\pzÚ‰yKt®÷´%O‚tóÓoBJ©Øós¶mAEyøŽ#£ Ûuk)\½fqikx¤- ¿ÎÓ½þõÏùØ}Üûî~½Ù%À×°cBÂû#>‡6~éÿÃm¯þ–¿õ‘³†Ã6,m%€ë<ÝtÓÍw®&°Ä„g..º\/¡ gvœŸ|EfˆÏሠYxÑÇ}ìól Àuš¶à:OËåÎËV«¹rêF8WÎ GjÑ‚ïE`Çé.WL;=9ÏêúDÀÞÞÞïðÖ³†Ã6,m Àužrη¯V«z/—ðä^ìŸU Jf®ôÂ5×wõûŒ¢Xbýã¹g ƒm:yÚ€ë<1óËWõÒN ›ìJjÏáÙ‰özCWÉÁ‰ÿ%Ì}??ã.\Ÿ¾ô¬a°M'O[p§i5ÝÂës¹LƒÉ¸»½ò÷Jy._Žör{7A­kÍ!LÓôœ³†Á6ŠãìÊá¥Ëáàúˆ5o¹@âDäÊør½Ú%žÃÃn¼ñ¦µ}e0ÎíÃÁáa!„Gì.<Ö)sÆ;ßñŽø¯þæo<µvŸèiKšô#ÿôõÿîÒ7}+oW@áãoÔ<‘?q㮤×Ýwvûð°wöÎáù»:ö̧ℓQbΠ…t å;î•ÙÀjbäÌGÞáˆpáÂì_½ê¼N-ñ£>òæ¿øÊ/ÿÌÓlô‰ž¶ ¦oüæoÅr¹ü¤ÿ„ÿ5¢C4ó».bê‘gîžx.6Ùo¼ñ¼ûÝ¿säE `A„å΢;Ý×ô®Oë<ûÖ=9Axp°ÂjÊGÞq?M·Ýv+îàÁ*‰œöòcÜù¼âððð?¾ú›¿á”Û~b¦-péäÇ~ý†§=í¥†Ï ZëïÈÝMó§žX “ߢ‹„àŽÛoÃo½ýET>"%"ìíºÛ{føÊ/úç›%C^Ľˆ>®\½Š)­Ô/ |ÌÇ<¿ó¾÷Ÿ_¹|ù=_óÕáE§Ýð5m €¿û߃Õjõ^ð‚ü[®r<5"25œœ±”1›Ü…höå%«xßÉï§]<ûØáçÿß7áððpm¤"¹½ÝЇòµGiëwÓéPß°•5ïJzôòÕµáÁ˜‹ÅìÞò+ÿ÷Üû8ŸMC"àîÜõ%ßôõí_l£(m €¦ïû¡ýàÅóo‡SüI”zrÌAjf÷LqΞד¸m2T­r÷ÞóQ|Îçü~$Jøíw½oÿíwa¹X pno/Üì*¦jh¨#þ‘‘ˆ†t¸qwí»Ÿ?òh±4‰™±Z­ð /þ8|Ö+^ŽƒƒCüð?ù1\ºôtdæ#U†Ç#1ƒöïûº¿òª[N¿õ'^Úßúíßõgo¿ýŽ•­²YÄ :Wia€žÝ“D‘º˜±XÞó®wâ ¿ð ënpçÆú0xàA,—Kx®|þü9‡übˆ3D¦@‘ ¶ûK„Däþ Å ¨ì0ÖÏjµ' Þ(Yí Ìx𡇫Wa);M.]º·Þr ^ø¢àéO¿„§]<þáÁͷ܆ƒÃCä|¤ÍðqL„ûï»÷«¿ùÿú÷Už(i{À7^úG«ÕŠëšWd8ü]¥¦æ†UÅ5áÖHco÷>æ…/Âëÿ¯×ã¥/ýD<ïùƒ›Ÿñ <ÿùÏ3ãCú0>|×ݸóCwÁX.5XU9·o£`0R¶½ gºÐÎ;»zŒ¤<™ ”3ãêÕ}¤”ðÌgÞ‚½½s¸pñ"öWØ»xW÷÷ñëoû5¼ùÍoÆK?ñe¸²ˆÕ•«k,”§|þÂ…ïð”'Oy à[¿ý»þÆ3žqë·d©+¦{¤P»€¦ݸQÂ:wÞy£Ä $n½å\½z¿ù›ÿ÷Þs/ž÷üçã“>é“pË-ÏÀÅ‹páü9Üpñ"xàA|àƒwâ®»?ŠGy<üzä,Ò¢tA.þ¬—|Rèd }§øGßið*LSÆÓn¸.œ/0I ,–;HË%xð¡rI)1ö¯\Æ=wß…~äøå–gâ¥/})‹%Þó;ïCÎîÒ%ᡇü–Wÿ­¿ùÍgÚ‘3NOYðµýðÝï[é»ÿÁæÝ‚¶^ö¼có­z0vv¢C}£â…Ó¼–wË%ž~Ó%LSÆåËWpׇ?„}èƒ8î^ø1ƒßóÒÿϾí6ÜtÓ%¬VøÈGïÅÝwß[p±ÀÁþ~½ès…œ3˜3ò4ß§‚C'`F9ñwH ¨Ÿ)%€vwwðð£Wp°J„E*g V‡‡xôÑGpׇ>ˆûî½`Æóžÿ<ç9ÏÅM—ž†år‰|àN\Ý?0¯Ä³L\n6ú—ÿâÇw?óú¬ÃïýÎo;ãM:ëi8Óôê¿û÷¿ëÒ¥§-Ãéþy×#ûà-k^ŠÐ]…y;€|¡Tœfvvv«Õ!î¿ÿ>Üõ¡ƒ9ãÒ7ছnÂù‹7`±ÜÅ•ƒV«Œ´X”0á”s.WâÔè?Ì ÎâþËõ  *ñ$A~f0—Ûƒó´Â•Ë—ñðƒàá‡Ä•+—ÁyÂîîn}æ³pÓÓŸŽÝÝ=œ;Wþîà¾ûЂ'¨éò£—¿ÿï|Ë×ÿųîÇY¥'È4œnzåWÿUÜs÷]7¾ü3_ñàb±ÒfÈžàæÑÛc‰½&årv—‡J„s»çpþü9ìíí"-5T÷4Mxð¡q÷G?Š{>z~ø!L“ WBJ„]ììîbgwËå²ró…úçSJXM¦Õä® _aZM8<ØÇááV‡(ç"¹ª){çöpà 7â†nÀùó´nÙ‘`ÎàÌØ?<¨‡–L§8[á?&ž2ÞóîwÝrîü¹{èû^sÖÝ9õô”$ð·_ýí¯¿á†§ý)…ÖүϜA¯õ>ß0­q›0úï—'ËåÎ_À… çqþü9ìîî`µšpåÊU\¹º+W®à`U7ç «Õ ‡‡‡åÿþW‡˜ò„ýé7¿ÚcúÛAC <óî¼F2 ‚Ô"èú¤yÛ³ž/DÈ¿W®^ûžÒË9O;+ßÿ&•ÈöÔ€GjòˆÞ$ùjU9ãpU·tP.¹þ_<òÈ7½áuÿøÕgÝ•Sê“?ýêÛ~ýÎ_~ó¯Üþž÷¾?ü0¦)›(­›ÿ Ÿom}ݹß.Û ÐL›û—¦æ÷Eªêa±\FåØz/†=}af&ß¼q/s..Ä9_§F¿˜(.œ?;ž}>û³~ßýŸûÙŸuóY÷éñNO `gg÷à+þì—áÜÞÞ‘Á6·i›ñŽw¾ûêY÷ã4ÒS‚ìííÑ=ŒßyßÛqùÊóŽ'ùtªÒƒ¹3þ¤™œ:¡Ï¥N)¨¶guT“Q ®C!Ÿü±¶QlrV¡ëøÒma®ñ‰e–sS¼[3~ ¢¨y{ÿg?`x{‚ÔcÒ‰º-‡ËNåä¢{¢—ž²ÝBT^˜ñTêQÛ†I7Z{fÜzËÍxîÏÆÁáê)!?%ÀN‰h¹\€(Uý¹è¦ë§²ý§Ò~²¸û5S*•`­á²ÈˆˆÞà‰¾¯{ ­G ‰sNöD#üŽý©¯¾ .‚QŸÀ6Œ¢£"{A*vƒ !›0¢@øD­«A~°CD@ƒ´„CŽ2+aáH(Yõ"rífTïf½ñX¶H9gg OVî6(Ñ•ÀSžÎzÕžFz*€½×|ÏwÃç}þçÿLËÛ/\¼aoo¯¥Z›¨cMÉ#,9c!éùxEØzw@AÄdH¯å\YÀÕ›*ÁH±î§'Önì_”J`ír$&šZbð*pÌ’Aþèß³M×cò>TÙýö`ªÿÑyö¤NOå>ç¶ÿT†É“5uŽ–ÍóëÓqa›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›¶i›ž:éÿñÙýÄõ¸[IEND®B`‚( @ × × ÿÿþ ÿÿÿÐÌÆüÕÏÊÿÚÕÏÿÞÚÖÿãßÜÿèåáÿíêçÿðïìÿôóðÿõôðÿóïïÿîëèÿéæäÿåáÝÿàÜ×ÿÛ×ÒÿÖÒÍÿÕÒÎý}vqÉ{toþ|vpÿ}vqÿ}vqÿ~wrÿ‰‚}ÿ‚zuÿztÿwpÿ|tmÿwohÿphbÿnf`ÿogaÿogaÿogaþslf»†zŒ‡(œ—’ÿ—“ÿž™”ÿŸš•ÿ¯¬©ÿÆÄÁÿž™“ÿ£ž–ÿ¢›•ÿŸ˜‘ÿš“Œÿ¡œ–ÿ”ŠÿމƒÿމƒÿŠ„ÿ„~y!skf¯«¦±´¯«ÿµ±­ÿ»¹´ÿ¨£žÿš”þ¯«¨ÿ²¯¬ÿ´°¯ÿ¸µ²ÿ›–‘þ¥ œÿµ±­ÿ§¢œÿ§¢ÿ¥Ÿš®£ ›»µ²¾ºUÄÀ»S¾ºS½¸¶gµ±®ÀŸœ˜ÿ¡ž›ÿ¢Ÿœÿ¤¡Ÿÿ·³±Ã»¶³p½¸´P¹´°Q¹´°S³±¬ —”ÎÊʲ²·¸´°ÿº¸µÿ½»·ÿÀ½»ÿº´²ÿ¹³²ÿ¸³²ÿºµ³ÿ··¶ÿº´²¹¹´±²··¶ÿ´ÿÿÿÿÿ ÿÿÿÿÿÿÿÿþÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿ´ÿ*&#ÿ ÿÿÿÿ!$'ÿ*-1ÿ"&ÿÿÿÿÿ ÿ#ÿ&*.ÿ,14ÿ#ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿìŒ4ÿà…2ÿâ†4ÿâ†4ÿã†5ÿãˆ6ÿåŠ:ÿä‡4ÿä‡5ÿä†5ÿã†5ÿá†5ÿß„4ÿÞ„4ÿ݃4ÿ݃5ÿÝ‚7ÿÝ‚8ÿß‚8ÿß9ÿß9ÿà:ÿà;ÿß;ÿ߀9ÿÞ€:ÿÝ9ÿê‡;ÿÿÿÿÿë8ÿÖƒ4ÿ׃3ÿÙ„5ÿÛ†7ÿ܇9ÿÛ‡9ÿÚ‡9ÿÛ…4ÿ܆5ÿÜ…5ÿÚ…5ÿÙ„5ÿ؃5ÿÕ‚5ÿÔ5ÿÓ6ÿÒ7ÿÒ~7ÿÒ}8ÿÓ}9ÿÔ|;ÿÕ};ÿÕ}<ÿÖ}=ÿÕ{<ÿÔ|<ÿá„?ÿÿÿÿÿï”:ÿá8ÿÙ‡6ÿÚ‡8ÿ܈8ÿß‹;ÿÞŒ=ÿß>ÿÞ‰9ÿ܇6ÿ܈6ÿ܈7ÿ܉8ÿÞ‰8ÿ܈8ÿÛ‡8ÿÙ…8ÿØ„9ÿÖƒ:ÿÕ‚;ÿÖ;ÿÖ€=ÿ×€>ÿØ@ÿØ@ÿÙAÿØ~Bÿç‡Eÿÿÿÿÿï˜=ÿã‘;ÿå’;ÿÛ‹:ÿÜŒ<ÿß<ÿá>ÿã‘?ÿâ‘@ÿà9ÿà9ÿߌ9ÿÞŒ9ÿÜŠ9ÿÜ‹9ÿÜŠ:ÿÜŠ;ÿÜŠ;ÿÜŠ<ÿÛ‰<ÿÙ†>ÿ؆>ÿÙ„@ÿÙ„AÿÚ„BÿÛ„DÿÛ‚Eÿê‹Iÿÿÿÿÿï›@ÿä”=ÿå•>ÿæ–>ÿÝ=ÿß?ÿá“@ÿâ”Aÿä–Cÿä”?ÿä’<ÿâ’<ÿâ‘<ÿá‘<ÿá<ÿß<ÿÞŽ<ÿÜŒ<ÿÚ‹=ÿÚŠ=ÿÙŠ>ÿ؉@ÿÙˆAÿ؇BÿÙ†CÿÚ‡EÿÛ†FÿëKÿÿÿÿÿïAÿã•@ÿå—Aÿç˜Bÿæ™Bÿà”Aÿá”Cÿâ•Dÿå˜EÿåšGÿæ–?ÿæ—@ÿå–@ÿå•@ÿå–@ÿä•@ÿâ”?ÿá’?ÿß‘?ÿÞ@ÿÜŽ@ÿÛŒAÿÙŠBÿ؉DÿׇFÿ׆GÿØ…IÿçŽOÿÿÿÿÿïŸEÿã˜BÿåšCÿæšCÿèEÿäšEÿã˜Dÿã™Fÿâ™GÿæœHÿçœFÿçšAÿè›Bÿè›CÿèšCÿçšCÿæšCÿæ™Cÿä˜Bÿá•Bÿà”BÿÞ“CÿÝ‘CÿÛŽDÿÚEÿÙ‹GÿØŠIÿç’Nÿÿÿÿÿî¡HÿášDÿäœDÿæœEÿçŸFÿé HÿäœGÿåœHÿåJÿäKÿæ LÿéžDÿéCÿêŸDÿêŸEÿêžFÿéŸEÿéžFÿèEÿèžEÿå›Eÿâ˜Dÿà—Eÿß–EÿÝ“FÿÛ’GÿÚIÿè˜Nÿÿÿÿÿë¢JÿßšGÿâGÿåžGÿæ Hÿè¡Iÿè¢KÿäžJÿæ Kÿå Lÿæ¡Nÿå Lÿé Fÿë¢Gÿë¡Fÿë¢Gÿë¢Hÿê¢Hÿê¢Hÿé¡Hÿé Hÿè¡HÿåGÿâ›GÿášGÿߘHÿÜ–HÿéžMÿÿÿÿÿé¤MÿÝœHÿàIÿã Iÿä¡Jÿç£Lÿè¥Mÿç£Mÿæ¢Nÿæ£Oÿæ¤Pÿç¥Rÿå Kÿæ Hÿì¥Iÿí¦Jÿí¦Iÿí¥Jÿì¦Jÿë¦Jÿë¤Jÿê¤Kÿê¤Kÿè¢Jÿä IÿâžIÿà›Jÿì¤Nÿÿÿÿ ÿç¦OÿÜžKÿÞ Kÿà Lÿã¢Lÿæ¥Mÿç§Nÿé¨Pÿå¦Qÿç§Rÿç§Sÿè¨Tÿè¨Tÿæ£Jÿå¢Jÿé¥LÿïªLÿï«LÿîªLÿî©Lÿì©Mÿì¨Mÿì¨Mÿë¨Mÿê¦Mÿæ¤Lÿã¡Lÿñ«Pÿÿÿÿ ÿå¨RÿÚŸNÿÝ¢MÿߣNÿá¤Nÿä¦Oÿå¨QÿèªRÿç©Sÿæ©Sÿç©TÿèªVÿç«Wÿç¨Rÿæ¥Mÿä¤Mÿä¤MÿëªNÿò¯Oÿð®Nÿï¬Oÿí¬NÿìªOÿëªOÿëªOÿë©Oÿè¨Oÿõ¯Sÿÿÿÿ ÿå«UÿÚ£PÿݤPÿߦPÿà§Pÿâ§Qÿä©Rÿæ«Tÿé¬Vÿæ«Vÿç¬Wÿè­Xÿè®Yÿè®[ÿå§Pÿå§Oÿå§Oÿä§Oÿä§Pÿë­Qÿñ°Qÿï°Qÿî®Qÿí­Qÿë¬Qÿé«QÿèªQÿø¶Uÿÿÿÿ ÿæ²XÿÚ§RÿÜ©RÿÞ©Rÿà©RÿáªSÿâ¬Uÿä¬Vÿç®Wÿæ¯Xÿæ¯Yÿç¯Zÿè°\ÿè±\ÿå¬Xÿã©Rÿå©RÿåªRÿåªRÿä©SÿãªSÿê®Sÿï²Sÿî±Sÿí°Sÿë¯Sÿê®Sÿø¹Wÿÿÿÿÿê¸[ÿÛ­VÿܬVÿݬVÿÞ¬Vÿà¬Vÿá­Wÿâ®Xÿä°Zÿå±Zÿå±\ÿæ²]ÿç³^ÿç³_ÿä°`ÿã­Vÿä¬Uÿã¬Uÿã¬Uÿä¬Uÿã¬Uÿã¬Uÿã¬Uÿè°Uÿí³Vÿì²Vÿë²Vÿù¼[ÿÿÿÿ ÿì¼^ÿݰYÿܰYÿݯYÿݯXÿÞ¯Xÿß°Yÿá°Zÿâ±[ÿä²\ÿä³^ÿå³^ÿåµ`ÿå³aÿä³bÿã±`ÿâ®Xÿã®Xÿã®Xÿã®Xÿä®Xÿä®Xÿã®Xÿâ®Xÿâ­Xÿå°Xÿê³Xÿú¿]ÿÿÿÿ ÿîÂaÿÞ¶\ÿÞµ[ÿÝ´[ÿܳ[ÿܲ[ÿݲ[ÿÞ²]ÿà³]ÿâ´_ÿâ´`ÿãµaÿä¶bÿâ´cÿâ´cÿãµeÿâ±\ÿâ°Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ±Zÿâ°Zÿß°Zÿñ¾_ÿÿÿÿ ÿÿÓjÿñÇcÿñÆcÿïÅcÿîÄcÿíÂcÿìÁdÿëÂdÿîÀeÿîÁeÿîÀfÿïÁgÿîÀgÿí¾hÿí¾hÿë¾hÿì½hÿî¼aÿï¾bÿð¾bÿñ¿bÿñ¿bÿñ¿bÿñ¿bÿñ¿bÿñ¾bÿï¾bÿþÊgÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿÿ ÿ ÿ ÿÿ !'ÿ,+1ÿ66<ÿCCGÿKLSÿUU\ÿabhÿ**0ÿÿÿÿÿÿÿÿÿÿÿ& ÿÿ²ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿ"""ÿ ÿÿÿÿÿÿÿÿÿÿÿÿ²ÿÿþþþÿÿÿÿÿø?ÿÿü?ÿÿü?ÿÿÿÿÿ(0` $Ãà ;LPOPPPPOOOOONNNNNNNNNNMH9 ÚÝÜDÕÏÊÿÚÕÎÿÝØÓÿàÜ×ÿãßÚÿæâÞÿéåâÿìéåÿïìèÿñïëÿôñîÿöôðÿ÷õñÿ÷õòÿ÷ôòÿõóðÿôñîÿðîëÿîëèÿëèäÿçäßÿåáÝÿâÝÙÿÞÚÕÿÚÕÑÿÚÖÑÿÍÌÊH„~z/xqkÿxpkÿyrlÿzrmÿzrmÿzrmÿyrmÿyrlÿvnhÿzrnÿ{smÿ{smÿzrlÿypjÿvngÿtkeÿpgaÿja\ÿjb\ÿlc]ÿlc]ÿld^ÿld^ÿld^ÿld^ÿmf_ÿˆ„ Œ†¿‰„þŠ…ÿ‘Œ†ÿ’Œ‡ÿ’‡ÿ’‡ÿŸ™”ÿ¨£Ÿÿ œ™ÿއÿ‡€ÿއÿ„|ÿ‰xÿˆzÿ†~xÿ‹…ÿ•‰ÿ…yÿƒ}wÿƒ}wÿƒ}wÿƒ}wÿƒ}wþ€zt¬|wrˆƒ š•ÿ ›–ÿ¡œ—ÿ¡œ˜ÿ£˜ÿ¥ ›ÿ©¦¢ÿÑÏÌÿØÕÒÿ²ª¤ÿ³­¨ÿµ®©ÿµ®¨ÿ²¬¥ÿ²ª£ÿ© ˜ÿ§Ÿ˜ÿ¦¡œÿž™•ÿ“‡ÿ“‡ÿ“‡ÿ“‡ÿ“ˆÿ~xr®¦žª¥¡¤¯ª¥ÿ°«§ÿ±¬¨ÿ²­©ÿ¿»·ÿ²­¨ÿ–Šÿ˜’Žÿ®«§ÿ°®ªÿ³°­ÿµ²¯ÿ¶³°ÿ¸µ²ÿ˜“Žÿ–‹ÿ«¦¡ÿÀ¼¹ÿ£œ˜ÿ£œ˜ÿ£œ˜ÿ£˜ÿŸ™•ŸŠ„¤¡› ½¸´ÿÀ¼¸ÿÁ½¹ÿ½¹ÿ½¹ÿ±¬§ÿ«¦¢ÿ¦¡žÿ˜–‘ÿœ˜“ÿ›™–ÿœš—ÿš˜ÿžœ™ÿ¦¢žþ«¦¢ÿ®©¥ÿ·³®ÿ¶±¬ÿ¶±¬ÿ¶±¬ÿ³®©ýœ—’{wsÄÀ¼Ç¿M·³°š­©¥ÿ®¬¨ÿ°¬©ÿ±®«ÿ²¯¬ÿ´±®ÿ·²°ŸÄ¿»\Á½·ºµ²$±®ªÿ´°¬ÿ¶³¯ÿ¸´²ÿº¶´ÿ»¸´ÿ°­¬°­­º¶³ÿ¹´²ÿºµ²ÿº¶³ÿ»·µÿ½¹¶ÿ¼¸¶ÿº¶´ÿ¼¸¶ÿ¼¸¶ÿº¶´ÿ¼¸µÿ¾½½ÿº¸¸ÿ¤›™Ò£›˜Îº¸¸ÿ¾½½ÿomlÿwtsÿÿÿÿ2ÿÿÿwutÿomlÿlÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿþþÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlÿ+'$ÿ)$"ÿ($!ÿ'#!ÿ&" ÿ&" ÿ&" ÿ+'%ÿ1.,ÿ731ÿ30.ÿÿ ÿ ÿÿÿÿÿÿ" ÿ963ÿ:75ÿLHFÿ,*(ÿ# ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ)$"ÿ%!ÿÿÿÿÿÿÿ!&ÿ$',ÿ,04ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿ($!ÿÿ߃0ÿ߃1ÿà„1ÿá†2ÿá†4ÿâ‡4ÿâ†5ÿä‡6ÿäˆ6ÿä‰9ÿã†4ÿã‡4ÿã†4ÿâ†4ÿâ†4ÿá†4ÿà…4ÿß„4ÿÞ„4ÿÝ„4ÿ݃4ÿÜ‚5ÿÝ‚6ÿÝ6ÿÝ7ÿÝ7ÿÝ7ÿÝ€8ÿ߀8ÿ߀9ÿà€9ÿà€9ÿ߀:ÿ߀:ÿÞ:ÿÞ:ÿÝ:ÿÜ9ÿÛ8ÿè†9ÿ ÿÿÿÿ'#!ÿÿ݆1ÿÒ2ÿÔ2ÿÖ€3ÿׂ4ÿ؃5ÿÙ„6ÿØ„7ÿØ…8ÿÙ†9ÿÚ†7ÿÚ„3ÿÚ‚3ÿÚ‚4ÿÙ‚4ÿØ‚3ÿØ3ÿÖ4ÿÕ4ÿÓ3ÿÒ3ÿÒ~4ÿÑ}5ÿÐ}5ÿÑ|6ÿÐ{6ÿÐ{7ÿÐ{7ÿÐ{8ÿÑz8ÿÒz8ÿÒz:ÿÓz9ÿÔz;ÿÔz;ÿÓy;ÿÓy;ÿÒy:ÿÑy9ÿÞ<ÿ ÿÿÿÿ'# ÿÿàŠ5ÿÞˆ6ÿÕ‚4ÿ؃4ÿØ„5ÿÚ†6ÿ܇8ÿ܈9ÿ܈:ÿ܈;ÿÚ‰<ÿÚ…6ÿÛ†6ÿ܆5ÿ݇6ÿ܇6ÿÛ†5ÿÚ…6ÿÚ…5ÿÙ„6ÿØ„6ÿÖƒ6ÿÕ‚6ÿÔ€7ÿÓ€7ÿÓ€8ÿÒ8ÿÒ~9ÿÓ~9ÿÓ~;ÿÔ};ÿÕ}<ÿÕ}=ÿÖ}=ÿÖ}>ÿÖ}>ÿÖ|>ÿÕ|>ÿÕ|>ÿâ„@ÿ ÿÿÿÿ&" ÿÿã7ÿàŒ8ÿá8ÿ×…6ÿÚ‡7ÿÛ‡8ÿ܉9ÿß‹;ÿߌ;ÿߌ<ÿß>ÿÞŒ<ÿ݈6ÿ܈6ÿÛ‡6ÿ܈7ÿ܉7ÿÞŠ7ÿÞŠ8ÿ݉7ÿ܈8ÿÛ‡8ÿÚ‡8ÿÙ†8ÿØ…9ÿÖƒ9ÿÖ‚:ÿÕ‚:ÿÕ‚;ÿÖ<ÿÖ=ÿ×€>ÿ×€>ÿØ€?ÿØ€@ÿÙ€AÿÙAÿÙBÿÙBÿæ‡Eÿ ÿÿÿÿ%!ÿÿã8ÿâ:ÿâ:ÿâ:ÿ؈9ÿÚŠ:ÿÜ‹;ÿÞŒ;ÿàŽ=ÿá>ÿà?ÿá@ÿà:ÿߌ8ÿß‹8ÿÞ‹8ÿÝŠ8ÿÛ‰8ÿÛ‰8ÿÜŠ9ÿÜŠ9ÿÞ‹:ÿÞ‹:ÿÜŠ:ÿÛ‰:ÿÚˆ;ÿÙ‡;ÿ؆;ÿ×…<ÿׄ=ÿ׃>ÿ؃?ÿ؃@ÿÙ‚AÿÙ‚AÿÚ‚BÿÚ‚CÿÚDÿÛDÿéŠHÿ ÿÿÿÿ$!ÿÿã‘:ÿâ‘;ÿä’<ÿå“<ÿã’<ÿÛ‹;ÿÜ<ÿߎ<ÿà=ÿá>ÿã“@ÿã”Aÿã“AÿâŽ:ÿá:ÿáŽ:ÿàŽ:ÿà:ÿߎ:ÿÞ:ÿÝŒ:ÿÛŠ:ÿÚŠ:ÿÚŠ:ÿÚŠ;ÿÛŠ;ÿÜ‹<ÿÜ‹=ÿÛŠ=ÿÚˆ>ÿÚ‡?ÿÙ‡@ÿÙ†@ÿÚ†AÿÙ„BÿÛ…CÿÛ…DÿÛ„EÿÛ„FÿëŒJÿ ÿÿÿÿ$ ÿÿä“;ÿã“=ÿä”=ÿå•>ÿæ•?ÿã•?ÿÝ=ÿÞ>ÿß?ÿá“@ÿâ“Aÿã•Cÿå–Dÿä”@ÿä’<ÿã’<ÿâ‘<ÿâ‘<ÿá‘<ÿá‘<ÿá<ÿß<ÿß<ÿÞŽ<ÿÝ<ÿÜŒ<ÿÙŠ=ÿ؉=ÿ؉>ÿ؉?ÿ؈?ÿ؈@ÿ؈BÿÙ‡CÿÚˆCÿÛ‡DÿÛ‡EÿÛ‡Fÿ܆GÿëLÿ ÿÿÿÿ#ÿÿã•=ÿâ•?ÿä•?ÿå–?ÿæ—@ÿç™Aÿá•Aÿß“@ÿà“Aÿß“Bÿã•Cÿä–Cÿä—Eÿå™Fÿå•>ÿå•>ÿå”>ÿä•>ÿä•>ÿä”>ÿã”>ÿã”>ÿâ“>ÿà’>ÿß‘>ÿÞ>ÿÝ>ÿÜŽ>ÿÜ?ÿÚŒ@ÿÙ‹@ÿÙ‰Bÿ؈CÿׇDÿÖ†EÿÖ…FÿÕ„Gÿ×…HÿØ…IÿçŽNÿ ÿ ÿÿÿ"ÿÿã–>ÿâ–@ÿä—Aÿå˜Aÿæ™AÿçšBÿéœDÿá–Cÿâ–Cÿâ–Dÿá–Eÿã—EÿæšFÿæšGÿæ™Eÿç˜@ÿç˜@ÿç˜@ÿæ—@ÿæ—@ÿæ—@ÿæ—@ÿå—@ÿå—@ÿä•@ÿâ”@ÿá“@ÿà’@ÿß‘@ÿÞAÿÝAÿÜŽBÿÛŒCÿÚ‹DÿÙŠEÿ؉Fÿ؈GÿׇIÿ؇JÿçOÿÿ ÿÿÿ"ÿÿã—?ÿá—Aÿã™BÿäšBÿæ›Bÿç›DÿèDÿèžFÿá˜Dÿã™Dÿã™Eÿâ™FÿâšHÿçHÿçŸJÿçšBÿçšBÿè›BÿèœBÿè›Bÿç›Bÿç›Bÿç›BÿçšBÿçšBÿæšBÿä™Bÿâ–Aÿá•Aÿà•Bÿß“BÿÞ’CÿÜ‘CÿÛDÿÛŽEÿÚFÿÙŒGÿÙ‹HÿØŠJÿç“Oÿÿ!ÿÿÿ!ÿÿá˜Cÿá™Dÿã™Dÿä›DÿåœEÿæœEÿçžFÿèŸHÿæHÿã™Gÿå›Hÿå›IÿäœJÿã›JÿæžKÿé IÿèœCÿéœCÿéDÿêžEÿéžEÿéEÿéEÿéEÿèEÿèœEÿçœEÿçœEÿåšDÿâ˜Dÿá—Dÿà–Dÿß•EÿÞ”EÿÜ’FÿÜ‘GÿÛHÿÚIÿÙJÿç–Oÿÿ!ÿÿÿ ÿÿá™Dÿß™Eÿá›FÿãœFÿåFÿæžFÿçŸHÿè Iÿé¡JÿäIÿåJÿæžJÿæžKÿåŸKÿåžLÿå NÿéŸGÿêŸEÿê Eÿê Eÿê Eÿë¡Gÿë¡Gÿê Gÿê Gÿé Gÿé GÿéŸGÿèŸGÿèŸGÿæFÿãšFÿâ™Fÿá˜Fÿß—FÿÞ–GÿÝ”HÿÜ“HÿÛ’IÿèšNÿÿ!ÿÿÿÿÿß›FÿÝšGÿßœGÿáGÿäžGÿäŸHÿæ Iÿç¢Iÿè¢Jÿè¤LÿäžJÿå Kÿæ Lÿå¡Mÿæ¡Nÿæ¢Nÿä¡NÿæžFÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë¢Gÿë£Hÿë£Iÿê¢Hÿê¢Hÿé¢Hÿê¢Hÿé¡Hÿé¡Iÿè HÿäGÿâœHÿâ›HÿàšHÿÞ™HÿÞ—IÿÜ–IÿéŸNÿÿ"ÿÿÿÿÿÞ›GÿÝ›HÿßœHÿážHÿãŸIÿä Iÿæ¡Jÿç£Kÿè¤Lÿè¥Mÿæ£Mÿå¢Mÿæ¢Nÿç£Nÿæ£Pÿç¤Pÿç¤Qÿæ LÿäŸHÿê¢Iÿí¥Iÿí¥Iÿì¦Iÿí¦Iÿì¥Iÿì¥Jÿë¥Jÿì¥Jÿë¥Jÿë¤Jÿê¤Jÿê¤Jÿê£Jÿç¡IÿäŸIÿâžIÿâIÿàœIÿßšIÿì£Nÿÿ"ÿÿÿÿÿÝIÿÛœJÿÝžJÿßžJÿà Jÿâ¡Jÿä¢Kÿæ¤Lÿç¥Mÿè¦Nÿé§Oÿå£Oÿæ¥Pÿæ¤Qÿç¥Qÿç¥Rÿç¦Sÿç¦Tÿæ¡Jÿå¡Iÿæ¢Jÿì§Kÿî©Kÿî¨Kÿî¨Kÿí¨Kÿí§Kÿì§Kÿì§Lÿì¦Lÿë§Lÿë¦Lÿê¦Lÿê¦Lÿé¥Lÿæ¢Kÿä¡Kÿâ KÿážKÿï§Oÿÿ#ÿÿÿÿÿÛžJÿÙžKÿÛžLÿÝ Lÿß¡Lÿà¡Lÿâ£Lÿå¥Mÿæ¦Oÿç§Pÿè¨Qÿè¨Qÿæ§Qÿç§Rÿæ§Sÿç¨Tÿè¨Tÿç©Tÿç¦Qÿæ¤Kÿæ£Kÿâ¢Kÿç¤Kÿï«Mÿð¬Lÿï«Lÿï«MÿîªMÿí©Lÿì©Mÿì©Nÿë©Nÿì©Nÿë¨Mÿê§Nÿê§Nÿè¦Mÿä£Lÿã¢Lÿò«Pÿÿ#ÿÿÿÿÿÚŸLÿÙžMÿÛ MÿÝ¡MÿߢMÿà£Nÿá¤Mÿã¥Oÿå§Pÿæ¨PÿçªQÿéªRÿå¨Sÿç¨Sÿç©TÿèªTÿèªVÿè«Vÿè«Wÿç¦Nÿç¥Mÿå¤Mÿå¤Mÿâ£Mÿé¨Nÿò®Nÿò¯Nÿð®Nÿï¬Nÿî¬Nÿí¬NÿìªNÿëªNÿëªOÿëªOÿëªOÿê©Oÿé©Oÿæ¦Nÿô¯Rÿÿ#ÿÿÿÿÿÙ¡NÿØ OÿÚ¢OÿÝ£OÿÞ¤OÿߥOÿá¥Oÿâ¦Oÿä¨Pÿå©QÿæªSÿè¬Tÿç«UÿæªUÿç«Uÿç«Vÿç¬Wÿè¬Xÿè­Yÿè«Vÿæ§Oÿå¦Nÿå¦Oÿå¦Oÿå¦Nÿä¥Nÿê«Oÿò°Pÿñ°Pÿï¯Pÿï®Pÿî­Pÿí¬Pÿì¬Pÿê«PÿêªPÿéªPÿéªPÿéªPÿ÷´Tÿÿ$ÿÿÿÿÿÚ¤PÿؤPÿÛ¥QÿݦQÿÞ§Qÿß§Qÿà¨Qÿá¨RÿâªRÿãªTÿå¬Tÿè­Uÿé®Wÿå¬Vÿæ­Wÿç­Yÿç¯Yÿç®Zÿè¯[ÿè¯\ÿåªSÿå¨Qÿå¨Qÿå¨Qÿä¨Qÿä¨Qÿä¨Pÿâ¨Qÿê­Rÿñ±Rÿð±Rÿï°Rÿî°Rÿí¯Rÿì®Qÿë®Qÿê­Qÿé¬Qÿç«Qÿ÷¶Vÿÿ$ÿÿÿÿÿÛ¨RÿاSÿÛ¨SÿܨSÿÞ¨SÿÞ©Sÿà©SÿáªSÿâªTÿã«Uÿã¬Vÿæ®Wÿç®Xÿæ®Xÿå®Yÿç®Zÿç°Zÿè°[ÿè°\ÿè±]ÿæ­\ÿã©Rÿä©Sÿå©SÿåªSÿå©Sÿä©Rÿä©Sÿä©Sÿã©Sÿê­Tÿï²Tÿï±Tÿî°Tÿí°Tÿì¯Tÿë®Tÿé®Tÿé­Sÿø¸Xÿÿ% ÿÿÿÿÿݬTÿÚ«UÿÚ«UÿÛ«UÿÜ«UÿÝ«Uÿß«Uÿà¬Uÿà¬Vÿâ­Wÿâ®Wÿä¯Xÿå°Yÿç°Zÿå°[ÿæ±[ÿæ±\ÿç²]ÿç²^ÿç²^ÿå°_ÿä¬Wÿã«Tÿã«Tÿä«Tÿä¬Tÿä¬Tÿä¬Tÿä¬Tÿã¬Tÿã«Tÿâ«Tÿè¯Tÿî³Uÿí³Uÿì²Uÿì±Uÿë±Uÿé°UÿøºZÿÿ% ÿÿÿÿ ÿ߯WÿÛ­WÿÜ®WÿÜ­WÿÝ­WÿÝ­WÿÞ­Wÿß­Vÿà­Wÿà®Wÿâ®Yÿã°Yÿä°[ÿå°[ÿå±[ÿå±\ÿå²^ÿæ´_ÿç´_ÿå²_ÿä±`ÿä±`ÿã¬Vÿã­Vÿä¬Vÿä­Vÿã­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä­Vÿä­Vÿâ¬Vÿæ¯WÿìµWÿì³Wÿë²Wÿê²Wÿù½[ÿÿ% ÿÿÿÿ ÿà²XÿݱYÿܱYÿݱYÿܰYÿݰXÿܯXÿÞ¯XÿÞ¯Yÿß°Yÿà±Zÿá°[ÿã²[ÿä²]ÿä³]ÿä³^ÿå³_ÿåµ_ÿæµaÿä³aÿã³bÿã³cÿã±]ÿã®Xÿâ¯Xÿâ®Xÿã¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä®Xÿã¯Xÿâ¯Xÿâ¯Xÿá­Xÿä°Xÿé³Xÿë´Xÿù¿]ÿÿ% ÿÿÿÿ ÿâ¶[ÿÞµ[ÿÞµ[ÿÞ³[ÿݳZÿܳZÿݱZÿܲZÿݱZÿÞ±[ÿß²\ÿà²]ÿâ³^ÿã³^ÿã´_ÿãµ`ÿäµ`ÿäµaÿå¶bÿâ´bÿãµcÿãµcÿãµdÿâ°Yÿâ°Yÿâ°Yÿã°Yÿâ°Yÿã°Yÿã°Yÿã°Yÿã°Yÿâ°Yÿã°Yÿâ°Zÿâ°Zÿâ°Yÿá¯Yÿâ°YÿöÀ_ÿÿ% ÿÿÿÿ ÿã¸\ÿ߸]ÿß·\ÿß·\ÿÞ¶\ÿݵ\ÿÝ´\ÿÜ´\ÿݳ\ÿݳ]ÿݳ]ÿÞ³^ÿà´^ÿáµ`ÿâ´`ÿáµ`ÿã¶bÿã¶bÿâ¶cÿâµdÿáµeÿâµeÿã¶fÿâ´cÿà±[ÿá±[ÿâ±[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ²[ÿâ±[ÿâ²[ÿâ²[ÿá±[ÿá±[ÿà±[ÿï½`ÿÿ% ÿÿÿÿ ÿñÇbÿïÅbÿïÅbÿîÅbÿíÄbÿíÃbÿìÂbÿëÀbÿêÀbÿé¿bÿè¿cÿè¾bÿé¾cÿé½dÿê½dÿê½eÿê½eÿë¾eÿé¼fÿé»fÿé¼eÿè¼fÿè»gÿè¼gÿé¹_ÿëº`ÿì¼`ÿì¼`ÿì¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿî¼`ÿì¼`ÿí¼`ÿûÇeÿÿ% ÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿÿ"ÿ$%)ÿ++0ÿ228ÿ::?ÿ@@EÿGHNÿNOUÿVV\ÿ^_cÿ>>Dÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ% ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%"!ÿ,)(ÿ30/ÿ:76ÿB?>ÿHEDÿWROÿa^^ÿ^ZZÿebaÿlhhÿxvuÿ*'&ÿ!ÿ"ÿ"ÿ#ÿ#ÿ$ÿ$ÿ%ÿ% ÿ% ÿ% ÿ% ÿ% ÿ% ÿ% ÿ'! ÿÿjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿjÿÿÿÿÿÿÿÀÿÿÀÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿÿàÿÿÿÿðÿÿÿÿøÿÿÿÿøÿÿÿÿøÿÿÿÿøÿÿ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ÿÿÿÿÿÿÿÿÿÿÿÿ(@€ @¹n¹nÿÿÿ&)******))))))))((((((((((((('$!ÿÿÿÝÙ×¹ÒÎÇÿØÔÏÿÛÖÑÿÝÙÔÿàÛ×ÿâÞÚÿåáÝÿçäàÿêæâÿìéæÿîëéÿñïìÿóñîÿõóðÿ÷ôòÿøöôÿù÷ôÿù÷ôÿù÷ôÿøõóÿöôñÿõòðÿóðíÿðîêÿîìèÿìéåÿéæáÿçâÞÿåàÜÿáÝÙÿßÛÖÿÜØÓÿÙÕÐÿÔÏÉÿäâà½ztnªohbþqicÿqjdÿrjeÿrkeÿrkeÿslfÿskfÿrkeÿrkdÿqjdÿpicÿphbÿpicÿtmhÿskfÿrjeÿqjdÿpicÿohaÿjc[ÿf]Vÿe\Vÿe\Vÿe\Vÿe]Vÿe]Vÿf]Vÿf]Vÿf^Vÿf^Xÿf^Xÿf^Xÿf^Xþoga«ogb{rn"†yÿ†yÿ‡€zÿ‡€{ÿˆ|ÿˆ‚|ÿ‰‚}ÿ‰‚|ÿ‰‚}ÿˆ|ÿˆ|ÿ‡€{ÿ†€zÿˆ|ÿ†ÿ‹…€ÿŠ…€ÿ‰ƒÿˆ‚~ÿˆ|ÿƒ|wÿ}uoÿ{unÿzsmÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ{smÿ|tnÿsmf#ha[‰„µ’Œ‡þ“ˆÿ”Žˆÿ•‰ÿ•Šÿ–Šÿ–Šÿ–Šÿ•Šÿ•މÿ“‡ÿš”ÿ—“ÿ–ŠÿŠ„ÿ‹…ÿˆ‚|ÿ‹„~ÿ‰ƒÿ’‹†ÿ†€ÿˆ{ÿ‡€zÿ‡€yÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zÿ‡€zþ…~x¶„~y‘‹†!Ÿ™”ÿŸ™”ÿ š•ÿ¡š–ÿ¢œ—ÿ¢œ—ÿ¢œ—ÿ¡›—ÿ¡›–ÿ¥Ÿ›ÿŸ›—ÿÃÁ¿ÿ®ª¦ÿ—‘‹ÿ™“ÿœ•Žÿœ”ÿ™‘‰ÿ•އÿ“Œ…ÿ”‡ÿމ‚ÿ›–’ÿ’‹†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“Œ†ÿ“‡ÿ‰‚~"}wq¦¡³ª¤ þ«¥¡ÿ¬¦¢ÿ­§£ÿ­¨¤ÿ®¨¤ÿ­¨¤ÿ¬¦¢ÿ³±¯ÿ®¨¤ÿ”ˆÿ—‹ÿš•‘ÿ›–’ÿœ–’ÿœ—“ÿ˜”ÿ˜”ÿ›•’ÿ•ŽŠÿ¡›–ÿÂÀ¾ÿ—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’ÿž—’þœ•‘µ˜’ޤ¡›µ±­ÿµ±¬ÿ¶²­ÿ·²®ÿ¸³¯ÿ¸´°ÿ·³¯ÿ·²®ÿ¬§£ÿ¦ œÿ¦¡ÿ¬¦£ÿ¬¦£ÿ¬§¤ÿ¬§¤ÿ¬©¥ÿ­¨¦ÿ­ª¦ÿ¯ª§ÿ§¢žÿ¦ œÿ£žšÿ®©¤ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿª¥ ÿ—’!‹†»¶³˜Á¼¸ÿ½¹ÿþºÿÿ»ÿÿ»ÿþ»ÿ¾ºÿ½¹ÿ¼¶³ÿ³¯«ÿª¥¡þ«§¤ÿ­©¥ÿ®ª§ÿ¯«¨ÿ¯¬©ÿ±®«ÿ²®«þ´°­ÿ·²¯ÿ¸³¯ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ·²®ÿ²­©¥¡ž¥¡±­©ÿ²®ªÿ´°¬ÿµ±®ÿ¶³°ÿ¸´±ÿ¹µ²ÿº¶³ÿ®¬« œ˜¼¸µÿ¼¸µÿ¾»·ÿ¿½¹ÿÁ¾¼ÿÿ¾ÿÄÀ¾ÿÆÃÁÿ·°­ÿµ¯«ÿµ®ªÿµ®ªÿ´®ªÿ´®ªÿ´®ªÿµ¯¬ÿ¾»¹ÿ¼¹·ÿ½º¸ÿ¾¼»ÿ¾¼»ÿ½º¸ÿ¼¹·ÿ¾»¹ÿ¼»ºÿ»¹¸ÿ¯«¨þ¤™ÿ¤™ÿ¯«¨þ»¹¸ÿ¼»ºÿxvvÿxvvÿ¡›ÿ œ›ÿxvvÿxvvÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–– ÿ'# ÿ)%#ÿ(%"ÿ'$!ÿ($!ÿ'# ÿ&" ÿ($"ÿ,(&ÿ1-+ÿ520ÿ:75ÿ.+)ÿ ÿ!ÿ!ÿ ÿÿÿÿÿÿÿÿ'##ÿÿ)%$ÿ843ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–ÿ'# ÿ&"ÿ&"ÿ%!ÿ%!ÿ$ ÿ# ÿ"ÿ#ÿ'$"ÿ+(&ÿ0,*ÿ410ÿ:74ÿÿÿÿÿÿÿÿÿÿÿÿ1.,ÿA=<ÿ40.ÿ=98ÿ965ÿ@;:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*%"ÿ%"ÿÿÿÿÿÿÿÿÿ $ÿ"&)ÿ&*-ÿ,/3ÿ$'+ÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿÿÿ)%"ÿÿÊv)ÿÐ{-ÿÑ{-ÿÓ|-ÿÓ}.ÿÓ}.ÿÓ}/ÿÔ0ÿÕ1ÿÖ€2ÿÕ2ÿÔ2ÿÕ€3ÿÕ}.ÿÕ~.ÿÕ~.ÿÕ~.ÿÕ~.ÿÔ~.ÿÔ}.ÿÓ}.ÿÒ}.ÿÑ|.ÿÐ|.ÿÐ{.ÿÏ{.ÿÏ{/ÿÏz/ÿÏz/ÿÏz0ÿÎz1ÿÐz1ÿÐz2ÿÐz2ÿÐy2ÿÐw2ÿÑw4ÿÑw4ÿÑw4ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÑw5ÿÐv5ÿÐv5ÿÏv4ÿÏv4ÿÎv2ÿÍv2ÿÉt/ÿÿÿÿÿ)$!ÿÿÓ/ÿÐ}2ÿÓ~2ÿÔ2ÿÕ3ÿÖ3ÿ×4ÿׂ5ÿׂ5ÿÖ‚6ÿØ„8ÿÙ…9ÿÚ†9ÿÙ„7ÿØ‚3ÿØ3ÿØ‚3ÿ×3ÿØ3ÿ×3ÿÖ3ÿÖ€3ÿÕ€3ÿÓ3ÿÒ3ÿÑ~3ÿÐ}3ÿÐ}3ÿÐ|4ÿÐ|4ÿÐ{5ÿÏ{5ÿÐ{5ÿÐz6ÿÐ{6ÿÐz6ÿÐz7ÿÐz7ÿÑy8ÿÑz8ÿÒz8ÿÒz9ÿÒy9ÿÒy9ÿÒy:ÿÒy:ÿÒx:ÿÑy9ÿÐy8ÿÐy9ÿÏy8ÿÌw5ÿÿÿÿÿ(#!ÿÿÙ„0ÿÚ…4ÿÓ€3ÿÖ3ÿÖ3ÿØ‚4ÿÙ„6ÿÚ„6ÿÚ…7ÿÚ…8ÿÚ†8ÿÙ†9ÿÚ‡:ÿÚ‡;ÿÛ…5ÿÜ…5ÿÛ„5ÿÛ…5ÿÛ„5ÿÚ„5ÿÚ„5ÿÙ„4ÿÙƒ4ÿ؃5ÿׂ5ÿÖ5ÿÕ€5ÿÔ€4ÿÓ5ÿÒ~5ÿÒ~5ÿÒ}7ÿÑ}7ÿÑ}6ÿÑ}8ÿÑ|8ÿÒ|8ÿÒ|8ÿÓ|9ÿÓ{:ÿÓ{;ÿÔ{;ÿÔ{;ÿÕ{;ÿÕ{<ÿÕ{<ÿÔ{<ÿÔz<ÿÔz<ÿÓz<ÿÒz;ÿÐx7ÿÿÿÿÿ'# ÿÿÚ†2ÿÞ‰6ÿ݈6ÿÔ‚4ÿׄ4ÿØ„5ÿÙ…6ÿÛ‡7ÿ܈8ÿ܈9ÿ܉:ÿ܈:ÿ܉;ÿÜŠ<ÿÛ‡:ÿÙ…5ÿÚ†5ÿ܇6ÿ݇6ÿ݇6ÿ܇6ÿÛ†5ÿÛ†5ÿÛ†6ÿÚ…6ÿÙ…6ÿØ…6ÿ׃6ÿ׃6ÿÖ‚7ÿÕ‚7ÿÔ7ÿÓ€8ÿÓ€8ÿÓ8ÿÒ9ÿÓ~9ÿÓ~:ÿÓ~;ÿÔ~;ÿÕ}<ÿÕ}=ÿÕ}=ÿÖ}>ÿÖ}>ÿÖ}>ÿÖ}?ÿÖ|?ÿÖ|>ÿÕ|>ÿÕ|?ÿÒ{:ÿÿÿÿÿ'" ÿÿ܉4ÿàŒ8ÿáŒ8ÿß‹8ÿÖ…6ÿÙ†7ÿÚ‡7ÿÚ‡8ÿ݉9ÿߊ;ÿß‹;ÿß‹<ÿß‹=ÿÞŒ=ÿÞŒ>ÿ݉8ÿ݈7ÿÛ‡6ÿÛ‡6ÿÛˆ7ÿ݉8ÿߊ8ÿÞ‰8ÿ݉8ÿ݉7ÿ܈7ÿ܇8ÿÛ‡8ÿÚ‡8ÿÚ†8ÿÙ…8ÿØ…8ÿ׃9ÿÖƒ9ÿÕ‚:ÿÕ:ÿÕ;ÿÕ;ÿÖ€<ÿÖ€=ÿ×€=ÿÖ€>ÿ×?ÿØ?ÿØ@ÿÙ@ÿÙAÿÙ~AÿÙ~AÿÙ~BÿØ~BÿÕ}=ÿÿÿÿÿ&"ÿÿÝŠ5ÿáŽ9ÿáŽ9ÿâ9ÿà9ÿׇ8ÿÚ‰9ÿÛŠ9ÿÜ‹:ÿÞ‹;ÿà<ÿàŽ=ÿàŽ>ÿà>ÿà?ÿà>ÿÞŠ7ÿÞ‹7ÿÞŠ7ÿÞŠ7ÿ܉7ÿÛˆ7ÿÚ‰8ÿÛ‰8ÿÜŠ9ÿß‹9ÿÞ‹9ÿÝŠ9ÿ݉9ÿ܉9ÿÛ‰9ÿÚˆ:ÿÚ‡:ÿÙ‡:ÿØ…:ÿ×…;ÿׄ;ÿÖƒ<ÿÖƒ=ÿÖƒ>ÿׂ>ÿׂ?ÿ×?ÿØ@ÿÙAÿÙAÿÚBÿÙBÿÚ€CÿÚ€CÿÚ€CÿØ?ÿÿÿÿÿ&!ÿÿÝŒ6ÿâ;ÿã;ÿä‘;ÿä‘;ÿà;ÿÙŠ:ÿÛ‹;ÿÝŒ<ÿß<ÿß<ÿá>ÿâ?ÿâ‘?ÿâ‘@ÿâ’Aÿá<ÿà9ÿà9ÿàŒ9ÿà9ÿߌ9ÿߌ9ÿÞŒ9ÿÝŠ9ÿÚŠ9ÿÛ‰9ÿÛŠ:ÿÜ‹:ÿÞ‹;ÿߌ;ÿÞŒ;ÿÝ‹;ÿÜŠ<ÿÛ‰<ÿÚˆ<ÿÚˆ=ÿÙ‡=ÿ؆>ÿÙ…>ÿÙ…?ÿÙ„@ÿØ„AÿÙƒAÿÚƒBÿÚƒCÿÛƒCÿÛƒDÿÛ‚DÿÜ‚EÿÜ‚EÿÚAÿÿÿÿÿ%!ÿÿÝ8ÿâ‘;ÿã’<ÿã“<ÿä“=ÿå“<ÿß<ÿÛ<ÿÜ<ÿÞ<ÿà>ÿà>ÿá‘?ÿã“Aÿã”Aÿã”Bÿã”Bÿâ:ÿâ;ÿá;ÿá;ÿá;ÿàŽ;ÿà;ÿߎ;ÿߎ;ÿÞ;ÿÞ;ÿÜŒ:ÿÚ‹:ÿØŠ:ÿÙŠ<ÿÚŠ<ÿÚ‹<ÿÛ‹<ÿÝŒ>ÿÜ‹>ÿÛ‹>ÿÛ‰>ÿÚˆ@ÿÚˆ@ÿÚ‡AÿÚ†AÿÙ†AÿÙ†CÿÚ…CÿÚ…DÿÚ…DÿÛ…EÿÛ„FÿÜ„GÿÛƒCÿÿÿÿÿ$ ÿÿÞ:ÿâ“=ÿä“=ÿå”>ÿæ•>ÿæ•>ÿç–?ÿÞ‘>ÿÞ=ÿÞ‘>ÿß?ÿâ’@ÿâ“@ÿâ“Aÿã•Bÿå–Cÿå–Dÿä”@ÿä’<ÿã’<ÿã’<ÿã’<ÿã’<ÿâ‘<ÿâ‘<ÿá<ÿà<ÿà<ÿß<ÿß<ÿÞŽ<ÿÝ<ÿÜ=ÿÛŒ=ÿÚ‹=ÿ؉=ÿ؉>ÿ؉?ÿ؉?ÿ؉?ÿÙ‰@ÿÙ‰AÿÚ‰BÿÛ‰CÿÛ‰CÿÛˆDÿ܇Dÿ܇Eÿ܇Fÿ܆Gÿ݆GÿÛ…Dÿÿ ÿÿÿ# ÿÿÝ9ÿâ”?ÿã•?ÿå–?ÿæ–?ÿæ—@ÿç—Aÿè™AÿÝ‘?ÿà“@ÿà“@ÿß’Aÿá”Bÿã•Cÿã•Cÿä–Dÿå˜Eÿæ™Fÿå•>ÿå•>ÿå”>ÿä”>ÿä”>ÿã”>ÿã”>ÿã”>ÿã“>ÿâ“>ÿâ“>ÿà‘>ÿà‘>ÿß‘>ÿÞ>ÿÞ>ÿÝŽ>ÿÜŽ?ÿÛ?ÿÛŒ?ÿÚ‹@ÿÙŠAÿ؉Aÿ׈BÿÖ‡CÿÖ†CÿÕ…DÿÖ…EÿÖ…Fÿ×…GÿØ…GÿÙ†HÿÚ†HÿØ„Eÿÿ ÿÿÿ#ÿÿÝ‘;ÿâ•?ÿã–@ÿä—@ÿå˜@ÿæ˜@ÿç™AÿçšBÿçšCÿÞ“Aÿá•Aÿá•Bÿà•Cÿá•Cÿä—Dÿå™Eÿå™EÿåšFÿæ™Dÿæ—?ÿæ—?ÿæ—?ÿå–?ÿå–?ÿå–?ÿå–?ÿä–?ÿå–?ÿä–?ÿä–?ÿâ•?ÿá“?ÿá“?ÿà’?ÿß‘?ÿÞ?ÿÞ?ÿÜ@ÿÜŽ@ÿÛAÿÚŒAÿÚŒBÿÙ‹CÿÙ‰Dÿ؈Dÿ׈EÿׇGÿ׆Gÿ؆Hÿ؆IÿÙ†Jÿ׃Gÿÿ ÿÿÿ"ÿÿÝ’<ÿâ–Aÿã—Aÿä˜Aÿå™BÿæšBÿçšBÿè›CÿèœEÿåšEÿà–Cÿã—Dÿã—Dÿâ—Dÿá–FÿäšFÿæ›Gÿæ›HÿæœIÿæ˜Aÿç™Aÿè™Aÿç™Aÿç™Aÿç™Aÿæ™Aÿæ™Aÿæ˜Aÿæ˜Aÿæ˜Aÿæ˜Aÿå˜Aÿä—@ÿâ•@ÿá”Aÿá”Aÿß“Aÿß’AÿÞ‘BÿÝBÿÜCÿÛŽCÿÛŽDÿÚDÿÚŒEÿÙ‹FÿØŠGÿ؉Gÿ׉Iÿ؈JÿÙˆJÿ׆Gÿÿ!ÿÿÿ"ÿÿÜ“=ÿá—Bÿâ˜Bÿä™CÿåšCÿæ›Cÿç›DÿçœDÿèEÿéžFÿã™Eÿã˜Dÿã™EÿãšFÿã™Gÿâ™GÿäšHÿçIÿçIÿèžHÿçšAÿèšAÿèœCÿèœCÿè›Cÿè›Cÿè›Cÿç›Cÿè›CÿçšCÿçšCÿçšCÿæšCÿæšCÿå˜Bÿâ–Bÿâ–Bÿá•Bÿà•Cÿß“CÿÞ“CÿÝ’DÿÜ‘DÿÜEÿÛEÿÚŽFÿÚFÿÙŒHÿÙ‹HÿØ‹JÿØŠJÿׇGÿÿ!ÿÿÿ!ÿÿÛ”?ÿà˜Cÿá™CÿãšCÿä›CÿåœDÿæœDÿçEÿèžFÿéŸGÿéŸHÿâšFÿäšFÿå›Gÿå›Gÿä›HÿäœIÿâ›JÿçžJÿé¡KÿèDÿèœBÿèœBÿéCÿêžDÿéžDÿéDÿéDÿèDÿéDÿèDÿèDÿçDÿçœDÿçœDÿçœDÿåšCÿã˜Cÿâ—Cÿá—Dÿà–Cÿß•DÿÞ”DÿÝ“EÿÝ’FÿÜ‘FÿÛFÿÛHÿÚŽIÿÙIÿÙJÿ׊Gÿÿ!ÿÿÿ!ÿÿÚ•@ÿß™EÿášEÿâ›EÿäœEÿåœEÿåFÿçžFÿèŸGÿè Hÿè HÿçŸIÿâ›HÿåœHÿåIÿåJÿåJÿåžKÿãKÿåŸMÿê¢LÿéžCÿéžDÿéžDÿéžDÿéŸEÿê Fÿê Fÿê FÿêŸFÿéŸFÿéŸFÿéŸFÿéŸFÿèžFÿèžFÿèžFÿèžFÿå›EÿãšEÿâ™Eÿá˜Eÿà˜Eÿß–FÿÞ–FÿÝ•FÿÜ“GÿÜ“GÿÛ‘IÿÚ‘IÿÚJÿ×Gÿÿ"ÿÿÿ ÿÿÚ•AÿÞ™Fÿà›EÿâœFÿãGÿäžGÿåžGÿæŸGÿç Gÿè¡Iÿé¢Jÿé¢KÿäŸIÿåžJÿæŸJÿæŸKÿæŸKÿæ Kÿæ Mÿå Mÿä Nÿè Iÿê¡Fÿë¡Fÿë¡Fÿë¡Fÿë¡Eÿë¡Fÿê¡Gÿë¢Hÿë¢Hÿë¡Hÿê¡Gÿé¡Gÿê¡Gÿê¡Gÿé Hÿé Gÿé HÿèŸGÿåGÿã›Gÿâ›GÿášFÿà™FÿߘGÿÞ—HÿÝ–GÿÜ•IÿÛ”IÿÛ“IÿØFÿÿ#ÿÿÿÿÿÙ—CÿÝšGÿÞ›GÿàœGÿâGÿãžGÿäŸHÿåŸHÿæ¡Iÿç¢Jÿç¢Jÿé£Kÿè¤LÿâžJÿå Kÿæ¡Kÿæ¡Lÿæ¢Mÿç¢Nÿæ¢Nÿæ¢Oÿå¢PÿåžFÿê¢Gÿë£Gÿë£Gÿì£Gÿì£Gÿë£Gÿë£Hÿì¤Hÿë¤Iÿë£Iÿë£Hÿë£Hÿê£Hÿê£Hÿê¢Iÿê¢Iÿé¢Iÿé¢Iÿç IÿäHÿãGÿâœHÿá›HÿàšHÿß™HÿÞ˜HÿÝ—IÿÜ—JÿÙ“Fÿÿ"ÿÿÿÿÿÙ—DÿÜ›HÿÞœHÿßIÿàžIÿâŸIÿä Iÿå¡Iÿæ¡Jÿç£Kÿè¤Lÿè¤Mÿé¥Mÿæ£Mÿå¡Mÿå¢Mÿç¢Nÿæ¢Oÿæ¤Oÿç¤Pÿç¤Qÿç¤Qÿæ¢MÿäžHÿç¡Iÿí¥Iÿí¥Iÿì¥Iÿí¦Iÿí¦Iÿí¥Iÿí¥Iÿí¥Jÿì¥Jÿë¥Jÿì¥Jÿë¥Jÿê¤Jÿë¤Jÿê¤Jÿê¤Jÿê¤Jÿé£Jÿæ¡IÿäŸIÿãžIÿâIÿáIÿàœJÿß›JÿÞ™JÿÛ–Fÿÿ#ÿÿÿÿÿטFÿÛœIÿÝIÿÞžIÿߟIÿàŸIÿâ¡Iÿä¡Jÿä¢Jÿæ£Kÿç¥Lÿç¥Mÿè¦Nÿé§Oÿä¢Nÿæ¤Nÿå¤Oÿæ¤Oÿæ¥Pÿæ¥Qÿç¥Qÿç¦Rÿæ¦Sÿæ¡Jÿå¡Iÿä Iÿé¤Jÿí§Jÿí¨Jÿî¨Jÿî¨Jÿí¨Jÿí¨Jÿì§Jÿì§Jÿë§Kÿë§Kÿì§Kÿë¦Kÿê¦Kÿë¦Kÿê¦Kÿé¥Kÿé¥Kÿè¤Kÿä¡Jÿã JÿâŸJÿâŸJÿàžJÿßJÿÜ™Gÿÿ$ÿÿÿÿ ÿ×™GÿÛJÿÜKÿÝžKÿߟKÿà Kÿâ¡Kÿã¢Kÿä£Kÿå¤Lÿæ¥Nÿç¦Nÿè§Oÿè¨Pÿè¦Pÿå¥Pÿç¦Qÿç¦Qÿç¦Rÿè§Sÿè§Sÿè§Tÿè¨Tÿç¦Rÿç£Jÿæ£Jÿå¢Jÿå¢Kÿí§KÿïªKÿïªLÿïªLÿïªLÿîªLÿî©Lÿí©Lÿí¨Lÿí¨Mÿí¨Mÿì¨Mÿì¨Mÿì¨Mÿë§Mÿë§Mÿê¦Mÿê¦Mÿç¤Lÿä¢Kÿä¢Lÿã¡Lÿá LÿÞœHÿÿ$ÿÿÿÿ ÿÕ™HÿÙLÿÛžLÿÜŸLÿÝ MÿÞ¡Mÿà¢Mÿá¢Mÿã¤Mÿä¥Nÿå¦Nÿæ§Oÿç§Qÿè©QÿéªRÿå¦Qÿæ§Rÿç§Sÿæ¨Sÿç©Tÿè©Tÿè©UÿçªUÿçªWÿç¦Mÿç¤Lÿå¤Lÿå£Lÿâ¢Lÿç¥Mÿï«Mÿð¬Mÿð­Mÿï­Mÿï¬Nÿî«Nÿî«MÿíªMÿìªMÿì©Nÿë©Nÿì©Oÿì©Nÿë©Nÿë©Nÿê¨Nÿé¨Nÿè¦Nÿå¤Mÿä¤Mÿã£MÿߟHÿÿ$ÿÿÿÿ ÿÔ›IÿØžMÿÚŸMÿÜ MÿÝ¡MÿÞ¢Mÿà¢Mÿá¤Mÿâ¤Mÿã¥Oÿä§Oÿæ§Pÿæ©Qÿè©Qÿè«Rÿè©Sÿæ¨Rÿç©Sÿç¨SÿèªTÿç«UÿèªUÿè«Vÿè«WÿèªVÿæ¥Lÿç¦Mÿæ¥Mÿå¤Mÿå¤Mÿâ£Mÿé¨Mÿñ®Nÿò¯Oÿñ®Nÿð®Nÿï­Nÿï¬Nÿî«Nÿí«NÿíªNÿìªNÿë©NÿìªNÿìªOÿë©OÿëªOÿê©Oÿé¨Oÿæ¦Nÿå¥Nÿá¡Jÿÿ%ÿÿÿÿ ÿÔœKÿØŸNÿÙ OÿÛ¢OÿÜ¢OÿÞ£OÿߤOÿà¤Oÿá¥Oÿâ¥Oÿä§Pÿå©Qÿå©RÿæªSÿè«Tÿé¬Tÿå©TÿæªUÿçªUÿçªVÿè«Wÿè«Wÿç«Xÿç¬Xÿç¬Yÿç©Sÿç§Oÿå¥Nÿä¥Nÿä¥Oÿä¥Oÿä¥Oÿâ¥NÿêªOÿñ°Pÿñ°Pÿñ¯Pÿï®Pÿï®Pÿî­Pÿí­Pÿì¬Pÿì«Pÿë«PÿêªPÿê«Pÿê«QÿêªQÿéªPÿéªPÿç¨Pÿâ¤Lÿÿ%ÿÿÿÿ ÿÔžKÿØ¢PÿÚ£OÿÛ¤OÿݤOÿÞ¥QÿߥPÿà¦Qÿá¦Pÿá§Qÿâ¨Rÿä©RÿåªRÿæ«Tÿç¬Tÿé­Vÿç¬Vÿæ«Vÿæ«Wÿç¬Wÿè­Xÿè­Yÿè­Yÿé®Yÿé®[ÿè®Zÿæ¨Pÿå¦Pÿæ§Pÿæ§Pÿæ§Pÿå§Pÿå§Pÿä¦Oÿä¦Oÿë¬Qÿò±Rÿñ°Qÿð°Rÿð¯Qÿï¯Rÿî®Rÿí®Rÿí­Qÿì¬Pÿë¬Pÿê«Pÿé«PÿèªPÿèªPÿè«Qÿå§Mÿÿ% ÿÿÿÿ ÿÕ MÿؤQÿÚ¥QÿÛ¥QÿܦQÿÞ§Qÿß§Rÿà¨Rÿà¨Rÿá¨Qÿâ©SÿãªTÿãªTÿå«Uÿæ­Uÿè­Vÿé®Wÿå­Wÿæ­Xÿç­Yÿç®Yÿç®Zÿç¯[ÿç¯[ÿç¯\ÿç¯\ÿæ¬Vÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿä¨Qÿå¨Qÿä¨Qÿä¨Qÿâ¨Qÿä¨Qÿê­Rÿñ²Sÿï±Sÿï±Rÿï°Rÿí°Rÿí¯Rÿì®Rÿì®Rÿê­Rÿê­Rÿé¬Rÿè¬Rÿç«Rÿä§Nÿÿ& ÿÿÿÿ ÿÕ£OÿÙ§SÿÙ§SÿÛ¨SÿܨSÿݨSÿÞ©Sÿß©Sÿà©Sÿà©SÿâªTÿâ«Tÿã«Uÿä¬Vÿå­Vÿç¯Xÿç¯Xÿç¯Yÿæ®Yÿæ¯Yÿç¯Zÿç°[ÿè°[ÿè°\ÿè±\ÿè±]ÿæ¯^ÿä©Sÿä©Sÿä©SÿåªSÿåªSÿåªSÿåªSÿåªSÿä©Sÿä©Sÿã©Sÿã©Sÿê¯Tÿð²Tÿï²Tÿî±Tÿî±Tÿí°Tÿì°Tÿì¯Tÿê®Tÿê®Tÿé®Tÿè­Tÿä¨Oÿÿ& ÿÿÿÿ ÿ×¥PÿÙ©TÿÚªTÿÛªTÿܪTÿݪTÿÞªTÿÞªTÿß«Tÿà«Tÿá«Tÿá¬Uÿâ­Vÿã­Vÿä®Wÿå¯Xÿç°Xÿç°Yÿä¯Zÿæ°Zÿæ°[ÿç±[ÿç²\ÿè²]ÿè±]ÿç²^ÿå¯^ÿå­ZÿâªSÿä«SÿäªSÿä«Sÿå«Sÿå«Sÿå«Sÿå«Sÿå«Sÿä«Sÿä«SÿãªSÿãªTÿé¯Tÿï³Uÿï²Tÿí²Uÿì²Tÿì±Tÿì°Uÿë°Tÿé°Tÿè¯TÿåªPÿÿ& ÿÿÿÿ ÿרRÿÚ¬VÿÛ¬VÿÛ¬VÿܬVÿܬVÿݬVÿݬVÿ߬Vÿà¬Vÿà­Vÿà­Vÿá®Xÿâ®Xÿã®Yÿå°Zÿå°Zÿæ°[ÿå°[ÿå±\ÿå±]ÿæ²]ÿç³^ÿç³^ÿç³_ÿæ²`ÿä°_ÿå±aÿä­Vÿä¬Uÿä¬Uÿã¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿä¬Uÿã¬Uÿâ¬Uÿè¯VÿîµVÿí³Vÿì³Vÿì²Vÿë²Vÿê±Vÿé±Vÿå­Rÿÿ& ÿÿÿÿ ÿÙ«TÿÛ¯XÿÛ¯XÿÛ¯XÿÜ®XÿÝ®XÿÜ®WÿÝ®VÿÞ®VÿÞ®Vÿß®Vÿà®Xÿà¯Xÿá¯Xÿâ¯Zÿä±Zÿä±Zÿå²[ÿå±[ÿå²]ÿå³]ÿå²]ÿæ´^ÿç´_ÿç´`ÿå³`ÿä²`ÿå²aÿä±_ÿã­Vÿã­Wÿã®Wÿã®Wÿã®Wÿã®Wÿä­Wÿä®Wÿã®Wÿã­Wÿã®Wÿä®Wÿã®Wÿã­Wÿâ­Wÿâ­Vÿæ°Wÿì³Xÿí´Wÿì³Xÿë³Xÿê²Xÿæ®Rÿÿ& ÿÿÿÿ ÿÚ®UÿܱYÿݱYÿݱYÿݱYÿܰYÿݰYÿݰXÿܯXÿÞ¯XÿÞ¯XÿÞ¯Yÿà°Yÿà±Zÿá°Zÿâ²[ÿã²\ÿä³]ÿå²]ÿâ³^ÿå´^ÿå³_ÿæ´`ÿåµ`ÿæµaÿã²aÿä³bÿã³cÿä³cÿã°[ÿã¯Xÿâ¯Xÿâ¯Xÿã¯Xÿä®Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿä¯Xÿã¯Xÿã¯Xÿâ¯Xÿâ®Xÿá®Xÿä°Yÿé´Xÿë´Xÿê´Xÿæ¯Tÿÿ& ÿÿÿÿ ÿÛ°WÿÞ´[ÿÝ´[ÿÝ´[ÿݳ[ÿݳZÿܲZÿݲZÿݱZÿݱZÿݱZÿÞ°[ÿÞ±[ÿß²\ÿà±\ÿâ²]ÿâ³^ÿã´^ÿä´_ÿä´_ÿä´`ÿäµ`ÿäµaÿå¶bÿäµbÿã³bÿãµcÿäµcÿãµdÿä´cÿâ¯Xÿâ°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿã°Yÿâ°Yÿã°Zÿã°Zÿâ°Zÿá°Yÿá¯Yÿâ°Yÿç³Yÿç±Uÿÿ& ÿÿÿÿ ÿܳWÿß¶\ÿß¶\ÿß¶[ÿÞµ\ÿÞµ\ÿÝ´\ÿÝ´\ÿݳ\ÿݳ\ÿݲ\ÿܲ\ÿݳ]ÿÞ³]ÿÞ³]ÿà³^ÿá´^ÿá´_ÿâ´`ÿã´_ÿâ¶aÿãµbÿã¶cÿä·cÿâµbÿãµdÿãµdÿâµeÿâ¶eÿâ¶fÿâ³_ÿá±Zÿá±[ÿá±[ÿâ±[ÿâ±[ÿâ±[ÿâ±[ÿâ±[ÿã±[ÿã±[ÿâ±[ÿâ²[ÿâ±[ÿâ±[ÿá±[ÿá±[ÿâ±[ÿá±[ÿá±[ÿà°[ÿÞ­Vÿÿ& ÿÿÿÿ ÿßµYÿà¹]ÿà¹]ÿ߸]ÿ߸]ÿÞ·]ÿß·]ÿÞ¶]ÿÞ¶]ÿܵ]ÿÝ´]ÿÝ´]ÿݳ^ÿÝ´^ÿÝ´_ÿß´_ÿà´_ÿàµ`ÿá¶aÿâ¶aÿâ¶bÿâ·bÿã·cÿã·cÿáµdÿâ¶eÿâµeÿâ·fÿâ·fÿâ·gÿâ·hÿá±\ÿá²\ÿá²\ÿá²\ÿá²\ÿâ²\ÿâ²\ÿâ³\ÿâ³\ÿá³\ÿâ³\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿâ²\ÿá²\ÿá²\ÿá²\ÿÞ­Wÿÿ& ÿÿÿÿ ÿá¶Wÿå»]ÿãº\ÿäº\ÿãº\ÿâ¹\ÿâ¹\ÿá¸\ÿá¸\ÿà·\ÿà¶\ÿß¶\ÿß´]ÿß·]ÿßµ]ÿàµ^ÿàµ^ÿáµ_ÿá¶_ÿâµ_ÿâµ_ÿâ¶`ÿãµ`ÿâµ_ÿá´`ÿá´`ÿá´`ÿà´aÿà³aÿà³bÿß´bÿÞ²\ÿâ²[ÿâ³[ÿâ³[ÿâ³[ÿâ´[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿã³[ÿâ³[ÿâ³[ÿâ´[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿâ³[ÿß®Uÿÿ& ÿÿÿÿÿ ÿ  ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿ ÿ"!%ÿ''+ÿ-,0ÿ226ÿ87;ÿ==@ÿFDFÿJINÿOMRÿSSWÿYY]ÿ^^bÿgfkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ#ÿÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$! ÿ*'&ÿ0,+ÿ521ÿ;87ÿA>=ÿGCBÿMJHÿYVRÿb_^ÿ]YXÿda`ÿigfÿolkÿvsrÿecaÿÿ#ÿ"ÿ#ÿ$ÿ$ÿ$ÿ%ÿ%ÿ% ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ& ÿ#ÿ ÿ––ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü?ÿÿü?ÿÿü?ÿÿü?ÿÿþÿÿþÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿàÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿðÿÿÿÿÿÿñÿÿÿðàààààààààààààààààààààààààààààààààààààààðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿddcui-0.3.0/icons/video-display-128px.png000066400000000000000000000176411427175135000200720ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYsnºnºÖÞ±tIMEÜ  ýì½”.IDATxÚìÁ°çOqÓ"h[x&‡¶Ë^UàLÑÑWÕ³ÿ»_¢Ø6þÏ·qˆqnA ×+pƒ%Ž»»l·µ©3élÍ„ÜáeÚÞëÚlwI/2³ÚyžÏÀo‡!ôQÕÍNç1ÈЀÂùÝnwêðáÃFø; !È_Y‰ÀÌð«£ÕÊfLOw¦Ö­[›>+BíÂùÿý? ³çd¤l¢Í…D¥¹Àˆ¼ÇUµÈ3¡Õ÷‚,dÐ-þ绦P-Æ0³¬à =s-Údå¾hÛjAE|]6×3Uˆó¥íÃ^ÝîQ Ú|vý¤³{ôû¯qèÐAlܸ±dhÉEæÎLÙhõlpM`„k¾'šs\s¾®±þ,šÛ— &„s¬ì7Ðy+@gΜÿ–-_†Û·ïÂ,‡ª€”rE@r B´3ä?~$kç¡5ŸÝ>ãìß3fÌÂh4.}‰h£ Úµ©é·O¦y×ê\]cS0Ö*‚Ê©s˜ðQˆ„kqMGCôôöʳfÁ«\übéwNEpíÚu¼zõ2òßþìßîËÏ}ü«©–µZÉ£¹ä'µB{ÉÄ©É$½A55¦ž" í0úA1Ž&å^K{ƒå V¬ceP˜ Cœ;w´øªÀ!ž÷’>·kÎ×4Èç‚ZQ!bc@$íË/ Q€&1ó k¶íÁ‚•«@OAGÊiLóõ¹ùu1q?Œ´ÎƒQ§¥jìS)ZYJ\0¶1ªòËI¬Þ¸Å³ÿ›ƒø<ë=Ä•í[!‚oþî’e‡Y b΢Š$ù<4;¼rÀ·Ä]‰zâ:³ìälïÿšw_Î$Ø]÷ûŒE+ sîü ^dÀ®^ªK-²½¤Y0'€hÑä…‚»+G‰íÄ €5\Çýυ߃x­M``' 8ãòã½?óç#€ä 1‚@°CR¾=7«9ï߆\üD~’n;ƃ ó”T|½…Áï^KºE8Q»ÖòHœ3a~7tÒÁpïu04¬h5ä¥( ©Ä¶þúK>Ææ1ˆôœœ+N se;oÀÚJJN°|0þŽ¥€Äür¸³úYcüý•Œ@“­âÏÎþ=ãݽ$#)ŸóŽ?V#~³ôëÀãüDs²õë¥`;þØçTÆ,f |½M?楗— h{CC€ â~<Éx_ç†û|€ç”èáô¶å÷hý¹s̹È_Pº"ˆóÏ2ë9€¨ÐÐ7,ý‚(ÁJ/ØÀ'+ã{y¶¯K7`þ8“PFðWD¡Ï±œ^ÎÌÁŸ{?5=Je !ž†s‘&€"JlGZé2¹…ÿ19|Îøe¸Úu²ítŽÓÁpŸÁ—Gã€]I#{ R÷'50æÏQjØÐMùHJÔ}ê'óËúû}Ùs\{È' ak:ù-B"mÛ ‚7ûøg8@—“ÁBsŸ{=îY9¡8ÔdÐt ‘AÊÔóôD&•`O¬û°5¯ÿsðç3Z_ï´Sàí·í•tÐ+YcEõ×qÞs€Œ ôô8Ç;pA?çyÛE7ȘT4d‰êò‹Â~¬ÙÓÍuÖç¡ãƆp­ßÏðâÑv‰q64þ:à6ï23ˆÖY‡&Ù |õD¹ôô>·%"ˆ4ŽáôC­Þ+Zɺ¤¶‘á—ÌæoŠÝ|›(¥,ßÓ€ŠñW¯äËt#g¼á ™F¡O¾:^”r¢òpÐíK=Ÿ"¸‹Qì¦é9“6K9ɼN÷úYO[3è$þí·`;EpšßmÛÆZÌgÔãçÿæM¡äsÒ0/s¢_ìâMõ€ý¸¯R®|¿n00Ùw~1mþ±:~TþE Ôù­‡úV‹B¾=ÏõÈ¡v¥ (–® pàxðŒà\Å–khz½.ÀJο^'çÕx’{ü?"S5÷?ªKdg%â²â•¬~«áñöǼ&gÀÂþ<"°P1{³NcÁòá  áóóÓÑw"X;¢‚¥àI$ >Î_ÁD€}(©çåc'ê430À½ÓgÜœ:ïΡ&Ûho¿wVÏN@Õ²V¢ÇãÑ»T­Ýü‰@Ò8€”^ ìÛÊ5$¾1éi@ÙCz Z·Æþè \ìÛ¦ð9r½ì[2‚2jÞÐàãòêñ¿ýq>xNò¼nOÇÚ#vn’A¦cø¬h)F97t ¸nË&TñC@¢w`•7d^£Á—8aÀeÇ>äÝð øy-ç~û«K¶îÙœ…ñïÞïXå70ÖUÀÓ`F°—À÷²ø¶µ¦G@†ôÙóOf@¥Õ“ˆ#³}Y2à øy™ûýψÓošãôyŽŸñ°gRKžÔtñJ€Í»s÷NUèP>ä*Ïë9(É“¶3l»–kÌž >s¾¶åþñ %ƒuI‡v õçßû˜¹—éñ`€v¤=Öc)àï7•6æ5U•ôÌÃi¥Ÿ× "aL/‹ñ¶|©µëÿ$(pô‰ ǰ¹~!²T (xû}+ëQ ‡õùh›M© ’?Éé >k^åX>ÏÜÀ•½SʼÂó©©A=›û6ök N‰ üàíÛFQûsØëþ’;Xˆ­ŽßDœ@ " çç9‡ÓfVILq³ÜüÜwà u¢ϦýIEíÆAÉ¿@Vã{ygyÜ…‹5y¬iâ"|¶Ò<ɽ_DŸézNoð&c(ß|…£¤¤e~– ¶ÌTÎ!F ¯Ä~ž´SúúÌC!ÜÞ¸iÇú|‚/,Ÿ¸ 4ôûûN¦éêɈeõ‡¯ˆd ÷:{ˆÈ‹cµ_äÈ’¾,ý;ð;äMtvƒfü @Ú§”†‚j^-=Ÿ²Kôm1I1\×Úü óÑÇó3¯©çíÏÏf Üá<Þ?~|~:‡pðœuÝvü¸ŸAÙï‡^˜Pð2©#çÇŒ¸•k×Ïé;Ä>©Õƒþ¥8ìW2Võ`ý§­ § ÇsÐêò‘õ˜o+‹Ìµ#Èûš¿æ+/×Ì‘”x°\O™;Æ!nëþaD·û\—NAŽÛÅK¹AÂpn>ô²ítÚ:m7³š‚U¦ñ÷IÔ˜’x½D'U« ²*Œê™¯1ÂfI½ž+r;£LÊô-•Ü÷þsYƒqê×eΦû–Mô9> éic8lHf>o##0%ðˆ9”mO@ÕÄ[ wùˆ ¤p9¥ºWË›­ÅŠs,kÝèO ¢<–^>¯Ì/ίëtæƒ|~•4í½¸ P#`õ£Œé¼l2¿MkÉõúp’–/~¯Kjz¢¢k°nÆ€x—ýûvi8;Ÿ=×ÛxÒ#d …ýS Baöý—Vî)š_ªðN苉!kîTKÉËG Ú¬¹¤Ax•nû=.«Îõ~R¸ bΜ>/÷T¹Ë4¯§Ž’½:ôë¾€1(¼¾ (ÖÓ!ŒVäï¶¹ÃíH A;y·¼Ï¬Z¬/d›½M¬½maŸ=G^$Ò~<‡¢ÌO²|užÌqn·°Nº1ˆÇëõ¶Ï>~ÊG@ÊÉ"#°Ï‡’?ÍñÒÜáåä¦û2;ñ;Ùš~ÞêÄ0Æ|:E4ЬÓÇR˜?ÓOÌSƒÏÓ—€»¤«çt&¯˜ÎY†¦ Çòq`rØOG‹ –zЯ¥ Ü nÅš÷`´‚PX¾”Wlì¾uc9زXÄQepê-ü¹<ï=yj xda– ƒ®r=Ë'R€ö„uâ&à ±#% PæùÙgùØ£†æ/D.ï}1n÷x×ò»Çök®ßšDmôÐòU—ñ /×9ðJÜ(Ûž³y•weÈïFáüÇúŠäù’à‰ÀÈ{ÐB5þšz®g±8´ïs]"—e5Ó+ÉCMÜ’Œu•^CŽA|†Ñ{¨÷k¨Fà`Õ^oçÕ³zAc}ée)ˇ#€‡ÈY[ ”+dõÿ²I?Þ#Ð ÙX3N§v5š yè|<Ï£C{T_èžßeÈ`Þ%°ê¢sdL£O”nD¤‹9²@“„?+·zþÏK“ˆyxì·ómX÷},ý;ÕwëÇÍýâñò~p°ñ xTï5–? óàÅ$ëbŠå@tìm›¶œ[%I×(=WÏÏÌÀ¾v. â‡eÔÚv/?] h›ð±´ñ0à,‘?€21•oiÆ@ñþx'‚ n <š~É•™º‡Ó~$’Æ é´ÉÂe‰üøØzï¸å-¸m´Óáõ.@ôó:×ÿ À9ŸH*óºƒ<®ékùÖI^¥èQÏ ³¹®Ç’Á~¼îNx"4„„|q'¾¸Ð"3øþ·4y½®åFq”h g¸, NE›‰à3]É3^;€q‰'ÑËr»\K²V !ó!g «Çñm¼üÔ €'#Yü)5XY^ =/€ÉÈ÷ÿ`‹h~ùÛÿÌTÈ 4eÙ]ñ{T§—ýé:½¯¶éùÚ_eÆo{=#¨DÖ쬶iO7äZŒWй<Ë:èþèdEÐD%]/ÁËÇ–ÛI••zȧµrõ<8ÚÁèÑ$ëZ=½8çá[dÕ<ò)Ð+“ÓöêÆâíÚ  C#mîÝóå’ÔçáUÆË«ç“²Z¿j.Á¿#pêä'÷vl±h¢?&m2‚[G'~_™üôÒ³ƒìFë©ç­óÞ¾MŽ%ß‚º )”tÇI«{D=lyÜË«S‚tz ÖýSÃ’ø@“þ$tï¡Ìç8N,lY·0}Ââue-úgŸÎÛ«W¨”|=ñú1ͱÐÙQ= 7zœa¦Ÿ¯œèE÷}¨’!#üoË„— aLòÔYÿÛ—•³œo`äz¤lë†TÕ v=#i* /4‘t¥Ù½×%2U 5ß«s¸cu;_·:8“E&ލ9ú+ÜË=YP Ü‚þ™›tÝ» pó~&ç+l¨€÷ÜÝ»…4$2Ž%S8(‡½TFîSîÏ»±øq:JçpÔUN¹:8f:ø²,âùâué+nCT~üoÿ§£ „–‡ À3Pæ3WÄheŸ¢”bŽŸ[Dn­=š£jÀŽC D^%†˜‡‹Ã½Áu|Ü#ä,†ë³ÞÅÅòAX.«…i‘¬ÖFm9Ÿ»Žÿ©zÙ¯¶i7ŠMïOï‰ÏÀnPûŒ¡NNJ¾yíš¡x4ˆ(½S 2zü f§4Η˜WçHÅòQX—‚èäEÊT$¯BSK$| |diŒÈ{ä´uýüÌçèd²µÛ¯ÏÌ¡ðƒ±÷ó÷3rG ~%v*+•Î`wßW›åt™9?ïŸ5–G€åNhÑ‚éÚ77¡‡\û*ÞJšháJÕBÀ·\(7wYzM\=è†ÁI“¦æ[nþ{»¨fý°šð9ðÂèçÜPj§„Wîí67;–À²(S7ë—þ³ËˆÌMèIÞW¨­³9’“ßîëçm~ Aœ¥½kîòÝ“8ñvÜþ¶NøL¥Kº‰n¬á®®[éç Xþ$ T#Ø™3ó ÐþNøÛV—TvwÝ,ïRT·vê_žÃ¼WïNÿº†nû/å†Çœð•^M‡ó~Ÿ²7½| ØIÖX>kj¼®réà‡;ª RWÿª‡xWCDkÒ”±¦—0󦎹”ùÞ âdÎ×)“µR¯Õ¾\!gçR6‡ä¯cC]•/¨€Û6äÌÈ÷¿Et¢×Ã}ЧÛûÈdÏ1-J­ñÙÉ‹Þð£Ò/ûþ(ïÁŸ|'…ñ‘_Ÿ@ÐÏsš÷åH)Ÿ¨V±/—÷¾ÝÊŸ¤bdhÇ<6ìÀ 0÷Oö’ >Òé3‡d»ûX» ¾1µ\Vî=¶X…‘a””KW`ù8 ¼ÜÚmíý¿þ5€ß¾ø[AÇC~ q€˜CÉbÑ’¬Õ›öŒtzZîþ¿ö®Èm_y»¶“ë]ÊÌí33333333333333ó{e8N“s[ÒKØÈñe~“Âøë¨+ÅžÔÍ~ZíJ+‹ú«<%qƒ¾'“\dô õ’±†ßay ‹bD—ûNâ3ÌwžƒPÂ*÷uF/º]Úc{^]2¸U<öÁÛâ5$7¯ÏÍÍ¡xæ LO,.¼“¶ûa“6gмFD]¹l+-?ÀVÅ'`¦gç1‚Œ8Gò²ªÇ2ù‰ŒöÜÐìÚµ S““ƒ¯€±±1+•R(—Jغ}Ž=‚ùbQH‚´iíž-X1Á‹)E®ÉgÉt®t$>û?‹]:”òc¦“Fî—f¯Ò[mj *• ` ú“Àm»$HxÕûöîÃ_ÿúg\æ2—ÅК5˜šš‚†ƒøÆÇÇðŸCÿ`ûö(ÿä(]þŸË@[ÉÌ(çm¥DôZ…C‡þƒ½{÷ו|Èþ ëÖ­­“-ÄÆëÊÇ¡ÿügŠE”Je”Úó›Õ¥Mç;E—„ÚTØó‡Êå"†GFÁi=ßþÕŸ¶Î î‘Ûfb„aˆ¨Äbþu°CÙONQ°ßÿ¯ý³­.Dµ °ŠÙ™Tk5X‰`5k:IÓ[ðâá à½$¤‘@VXËå2r¹œÕå CÀ®zëÝáÇ?ø&´:†s$ƒ–Ä*01*Õ*Î-2ø~€k\÷ÆV—ƒd=xïþÿG½ÜBk5„óa칇„¢&±LhOòu½È5éy$ù23W|¡¡Ë>reãV·¾­é^, ¸Ç=ï÷¶›ßôúÎòÅ/óExÿ»žZ*•„DøÜg?MXÁð±ÂqÓ›ÜÚh´áµuLqªnxýë#”¡LÜ –12ìÙ»ZÉyC£…Š¥Z*vîÚ…Z›;s¹Ì‘Àó‰"GF øö¿s•'<õ¹/g–ÄÔ_üæ·×¼ÎÕ¯¥M÷š`¹£9¥¬Ð‚i¼õÍot)£Õ¥”ÒÐõk+Ôj‘CâÌ,{DQ„†¢»qô؉ô}Ì xZgXî¨Öbë €ÌX ÐNÆR?¤G+„Œús#…‘BÉÝ„gu:ËÚ2ÕLŒ:4|Ÿ{Ü%Ì,À2„ÑØ³†`j¯?ˆ¢‰»V%µ¬VêDãÄøønÁ2DF˜½qƒ¨KÙÌ @z=º­AoÂ…Ç´7#À2E«½€±½_ šJïNJH‚KmôžÌ¸øÀ‡?>±vÝú·¾3"uNØf,-‹¸ 9W?ŽJ¥¢]e$bÉE^Øzm20ȵÌvU=ÏÉR6F£/Ò·,”â8úz±8ÿàûÝën“™`x¤ð"môkQ €» çÔ{²áÑ}´ºU¸ŠU+¬µ½¢€5þÀ&£õ¥Ña¾J6)äIEND®B`‚ddcui-0.3.0/icons/video-display-16px.png000066400000000000000000000011551427175135000177770ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÜ 7öÞéšúIDATxÚ|Çq1E_7°ôž©è¬³ÒP|JAÞÛ\èÉ û 3+sãT½Ú¼?««­wÙ¦§̬jáøø˜“³SNOðë×/Š00 ¬vÞ[=ÿvËts‰"p “cØ8ˆuÔÏ€dµ{È‹gçT¦«ÚÍ=˜Š9îÂÇIŠÖÁzIà¶+Õ ÖwAŸÀ¬,xBqãa¡ÅÄjl¦dv«´û$š;¥”àXO,}ÛÚ´•ÈÕÜh½’½cC&œÌŽ1õ$Ë ³ÁÑ¡ÖȾF@53Z”göÀLT\C0„2QoXl~Æß€>‹á”L¢ÇòŒI$`3°‹\{b[Ðß#›èmM)•H1E`šÅ„!û87À8/ð7`𒏹£zY„Þ;)a (QÄ8„äÃZþh Ü Çé‹$ 2(ÐŒ-rz°½ýƒ•þ’ÃC®®®ˆ!elRÌÞÒÌ€ñ÷4TwòØ÷êíG½}ÿEíü#2'«°\^UYù+++8-üøñãÿ? ßÿäƒÃàêõê+ͺ…Õ€}‡ŽMæáåËáæâdàâädàà`c¹ý09~ÿþƒáë·o Ÿ?}žìhk‘‡0ðA1>gâÏ0»‡Ëápøò÷¾÷½ßÝø¨q]§ÓÙ÷Ñ~TßøÆ7xõ5×dâŽ\­{rµPÉåð¶[Éeðœ'F!@¬'ÿ‘$§:Lêù³uEá6ƒ1d¨pQ†©ŽöQÐ8û«üçÚ~޲ènS_ˆ>c™cFepìè1üñOšÿ¾hšŸ÷|±Ý²óh;ÓW€îºû~|ík_ç/ùKMrÓÉ¿Vpé÷ûïúìg?;Ýù%-ì†ô‚^; Ø÷ºIÀ¾¹DR·õ/ùD¬h™æO :@1FÛ‘N3 ÛÐ>”Œû$®ºú*Üÿ}èt:˜õ÷:wE;rl$†ýC„ðs¢èøá~ûb™òóž+©]~4Ûéœ>”e‰Ûn¿Ÿù̧9ÉM%€É¤]ýïÿüÇw:—³‚¤œoµ'V…­IÀeF–„„y;‰sN N[&'¹uL#’Œë(PS»^¯[o¹7Üpn¹ù&0„ênæÉ8a¦Ï$¿øªì”Äbýî]»ñÜsÏynI$ãº0I`B¤ÿýïsÓÜÜ8E‘Ÿ¡ @δ~·Î. æÅÚ®¼Û§»°¤ŒqÞ½Ý× "U:.ö#§aü×þXçõ·áò—¼(Kôû=|÷»ßÅ?ÿùO¼ðÂóUL‡ÈŒš@=ì»’Ñ–Ãr:þébýÁ«Ýß½d’yy.L„²ÇÜÜ4x×çR$ µ%e“9ã»aB={H Ù©2:fœÕ&Í­k¯í¯jsßó8þ£/!àØñcxü©g0qùåW ¬î”W]u 踜ÒL~£ûtÛ0Fœ ɦûÛßqäÈ‘ìÜ䓹ýµîB&¯¥Íþ@²`K„Z$Hhd÷X4·‰»$êíŒÏN¨kÇÑ|×·qmI€ SŤò®oßÛw} Cz`OÄ3ĶáH}D­ã"A ñî¸oÏnm@'w}IN¯Ú_ö‰"øÙÏ~> ~nšOl˜¿æyϯµI¤‹à#ˆ2Ürpr;›Ê‹b½ŸS|ÞnýŸŠH¶ˆ“Pˆ‰WÆOa±ñ™, (èÏp¦ØØ®äš?‡H¾œ}Jœø„?Ç(ýY/ý|ˆªf´Cl“~öKí’Ï}Æ"LúDjSýF÷Pâ7þ3†'Ž¡~7Ï©qylóÜ« o”_œžmÙÐíŸy0{ûî)y˜$ÿ½ïÿ0®¹éFt.¹ ñ+ÕUP;j¨~HQ)s_«NÖ)Å)ï-ïKå‹^°Æ4¸à·ü"D卑cʼ¸xðmxìía 26îB-R‰ÑàŽïß…ÿ I 977L>¬'$ Wo%ÿ wÞÞe—%gÓ•3_u:fà5)eܱmOjQ6%n$:NkØòÌõ[¹¹ —òä&ÚüŜ×Ü+À<'¶õœ¬ÆÓœéçtñx®§Hœ<ƒ,±SíssóW€< D§.:ýÞÖ—€+0¹vned7ãWk>Zf_WÔ’€‹“4Ô:4Md͹E2”Ù­¾œâØÐ_û«S »¬Ò£2–plX‚Or®Ñ .eÃ:³Ì/§–{Ã_¢ètèìz#¯Vx×árŒ—ßä­OäªÇZG€JAªÙñ¬ÈÅ$?ªjªòAϽ?©åw YÑ@ …ÙIYº‰IDˆÖÙøCÛ?\ò¢n°c†8lG'†ÊþÕB4d—kºKriÞhf=æAžW×~k™YÛJìÝÏYó€Éq›5‹ÀEí©WùIO(Fâö2XM‹)D| NîxÕae=éçi3¤WƒH Ub-¿Ü2,Û:X÷Õb…•ŽçÌñ¥· Æò4-ÒHX"±™_ í2˜ë?¢ÿŸy+Ñ’‡a–«{öÿvîŠö2žˆ30'ì9 ®àK²ùf éü,<[¸0ż%Û †.{þ<×äÝ¢-P¡qÔ7"øT•úÖæ1IŒf&Ì`ën˜’Ö"$æ¼#4O’A>Ë¡ä!îseÈ3çGlÿ± 7E¿ò¿¹OÊÙ4i4φãìÙý?J*¢sÍ8úiÚ©ò>e@³ß£9eÿ¦¯nô&gB:Ï&bs_ >éÅa“皱Ƅ(#"  &¶·57¼mÐ{éà_â>–X3g=u8f£ M£‰î˜ÇûÝ_‡A‹&³¹z?מ;âõd£ÿ!׋.œ@ìåèy€¨èC߄쳛+%8‰®Ùw¡Ê°îÆ.pýê$ ëû|Ö'¸S ˆ=Öæ%?î B ÀÝ8¨ŽGе\‚ÕDÆè5·ëc`úùœOÍ)üE }~F r™!¯áyïÔêå D=dçw >|©7|͘²ŒçeOýL?%£[U¢.¯›]%¦ÏTI]·²dÞ 4e@e´4´Óúü9üp:òÓ¢MæDe¦ËCÙT¯‘Mš†F;PÒ|3Òͼœ cd$ݱ5©%÷uI¬ù÷ô}/@£®€pÜÇJNº„qÈl>Æ ,ë9ÝmÕœït ªŒCÇ4òU¡œÛ.p‹5qÝO±@ô##^ÿºQ`ƨ¯yͲ³Q-‹Ä^Õ[æD8Á\‚R«f QøÛ”Ì æ*Ô5ܰç>Δ›‡Â ‹V’“&$ ™Ï\‡ÓF‡Gú/ÝäkÀÆ 8vglÝ3ß ×(çÆ¥ñ[!¢)­Àê®]C~:ú•Éã‹Â!xøFBykæˆHe§ç`l 9H!Ö“ŽcuÂõ‡ƒ~ü2À/0Þ6kš¬¬Á„zþ¬9#zÖïzå#W¦‰—×ÈÇk’o:N³%Þ¬Ømß:öø?A}–IR^uÂ19w%ó·ÀÓ¥ôWjó^ω¬l¨åÐ`¯i‘—¡óÞ¤5js`é Û„OS@xÙÏû81.³‘Œøú4Îàt.›9‹½§ŠãOeúÅð…ÃF“ö c¾æš&g ïCÑ™‚@ý®½‹µÒôl;Ýï¨DEÛkŸ ¯£;x¾]³ó. É Ìç´Mh˜uêÜ…ÏÚ‘ ?/ÁAëýà¼Ü8F=ËŒä #H%0\),go rBšðÈØÓkð°{GƒýMƒ2¤s,¹­ænÀ\R=òµb«VCí!kAÇK~Dä¶ÍDõ”ˆ%Ïžc 5enk<¡Á†=Õ5š,;KNóˈxÖy-ÉõnÐ[Àù‚WdÐø>ŸòÎO.ˆf†/<^"ŠØÛÓ|± ºå«¸ûö[}LËšS_t< c‚åäÐËþ¦î]”Ü6z§oô¬ãä;ßÿmþO‰½«éï±Ä‘Z?ƒ ]yŸÝ}]•²CQ#Š"@£ÑГÌËÎYNìò;5¡]"ú¦ Gï AÎÏæ€Þn1mÒM–òæ¥h'Ãÿœ5p¢V#Ë4õc‘¼´6;ûZ÷×Ð?k›Uqçx°Ð¿¨ ÐhKtÁoÍk~¯—¯+¿µeÄÜ8òÝ>u;pØÀ1ŠJìuèF X™ÒQüx´šâÆ&OŸ×!\¿nçŽg:³kì¦.µ³Ž¸=±Y}›tˆªØž!Θ¢ñ3Ä Jî>o‹n|Àh5Cà»eØÏ·‹Ëól©µô|_90ýƒÜžAà ËY|ùý‡,Ö E~?wª Årâ™?[Ðoüeæ/:&`X `ÓtÔ±Ë?Ù9çÅÊë gss“kÒ6°†?jÈ8] [p”ë’¹?îSœ›Ñ„ŽX21z£7j°Ô…@øÉ)桲}ûŽ zœ7Êó•»cÊ®‚ÍC¬ãüf  m†ÿµlc>BüS>ÚPÚtþ|‚ òPÐB;p”`NTr ®úÜÛ0øŒÐ[ޏ¦ O³ß –`ÑÌraš— ñŸ!ùËàÃ%¦¢T¸ÐìHk3h.çˆ}¬¢¿W IW ô06fZQ'”4óõUösÉjÞ2þ‘ï4“îÀðà$í4àøŒö˜ã_·úýøìmbÖÅ­*Ò´ñyqs¥Oò†&l4³%XÚM̗ؼ3×M[Fx–ÈlÝYûG_ý¨^Ó”‹bŒJÏÕÝñäÁ1”ÃË Ç9\JÜç“WÐm ¼%*qb“JÊD‘Ë/¡µ×hîû$ËpõGÌézMއÿ‰±4˨{ ÇN~n­ŠåŒ]º½Ôqçjø£¦½Ã©Ö ?—æeÒÉ@Ë^ÙšŠ@.†Ê‡ÿ±Zp"$p´ƒCPl ®íù }{ÝÏ IcE*5·÷l§#[—S'ô¼"˜–ORKÜZy½7‰RQ&4VTßÿ_7‘O¬~"²ö±§<Àqzg¾¾Ôzïoû6Ùø·›áÛ ›÷ŒŸ|PèÜ£þrð^8“Ï6e€(¤ÑÉ1ä>ŒOOŽVÏ9îê¼>“^8(Áبh{·ŽR«/®jÁ*ÅZÏ6?ãèPd²[*ˆ~:h£½½ôNo®ºLï?h-Xýúè9/ºÙ‘!´¿D.òÎKßÿ¨¢o—ñÒÞÛ½¿:žu±G6:¶‡À>%˜Í9®òty(sü8Ç…c>H½g qð8×"$éšË»ËÁÛp9ùTÉÁg® pf¾®{ž}K'R¬Ã7UD“3”çç  ÙA°«4nº›©Hl¯ãqÛPû^Kåã26­sÈþñ+:~}ƒŸÊÔ¶¯Í9㸧—ðø=÷Áí·t./ê}·qY}H€F+ÂàpÈ+Ölúý}ÚØ)›¤Æö%§–‘—e7éyP7l %WÓPòûGôPôQ^í¼Z݃IFR©ñ Þ{”2|W+8Óë%°39X{{q^Í÷Ëm³Ð±pç¿w¾ïùF!¤tóöÏ/_î¬=‡\k/. –åÁÕÞÓC÷ÈØ÷6Q£ôÙT5ÁM‡–±«|=gìØprÿ0ÿí³3¼ùžüL©'<êÀnŒDø¨Ÿ¯OÒSŸ@ù˘hàÁ¤a•OP_š½²'_õ^S1Åò_ãߊøû˜Œ|2‰¦ m]y?Tu•„o¡Uý<®Aöòp"ð\·œ$¦ŸŽ èJ€,¯U/çÆEÝ®³†LÏ­4<â§Ò[?{3 ´p—<€Ê¢éa¼ì* ªš>‹Ó^ýx8(âÁ&ë=ú…ž÷3ò^΀­õ³ôø··“£iz,àŽs죵ç±÷/÷z’’÷FLï}÷3<ýÅŸ8gíØ™…Á9ø„Š@‡dm0òâuã#”O™ IÃG-=_o,ÝÔœïjÿE[î ³g8Íã>ÚŽM@õ ÷€l¼BM•ƒœ <. |‚ä †ÆÚÏ´(šJv9¡í¸¶5¼åûeî+šqçk¿âÿ;ÑÒÙ†>Ô…Óo_¯ÿYc-‚RêG {yæu ]^WîÖÍýšåÑxþ\8é=âºíe2á'ˆ8:ƒô¦çç¹êÑò4lã8Ãm°ê$—²Éi÷úÆc|·Pþëo^ùr) =I™)uæO(éþò° u’ÕJÊs²9³ry›îÓéÿ‹nÿègç¿;V2oaþׯå>ÂdÏÊ)NʱzŠ@êivB¥¦­ é:RôŸ¨ÝIà‰ƒÕ°“l´)nÂÇ\Ž£?_lë͵ÉÙC÷Äò=~öäŠ-aä¥ÅF“Uä`í=BÒf7z­Ã(U=^ÀÆL>cgYôp®²_îgcâíü'Œ_”Ûîºd–ͧÁãjølÍ9üN|v?˜×4© 8ú˲AÈ|?R°X?Ûƒ}Žteûƒ âh Ònî=¸Å™{)€Ê <_Ë¥)òÑ"ì@÷»g`„ª^6ØdÔÓ ñH±íØå ›Áô)ä¾¹ò:SöÛé„;ÛüûIõ^ÿòLŒdõú#zx‡~µ Y:ûVÊûí÷ˆSY>x7¨Ûðò‡7K'Œh¥»nÁhÖËÓûŸél`?ÿçÝ"z³£ó¥ñ”#o½º"b [f°'4q€@–¡Wã¦z.мÞlçµ"ºCX·R +®rgâFRãª+q±Žå´§î8Ç·éšÓ¥áó7@±\¶ï :º‚{›ág;ôìÊqˆœæ/N¡Vмt`á‘ä£I¾LOé6㵎ð!Mô­Ôx&ãF>h9ÕuºTÌ¥ôJÙo4×Qj:Ý™"ìíúåÂÁ†A3\ªÀs®\?&"ëtcÔùÞw½Ú)ªšeÁ Ç5ÛWàOÒ®MîS;ñy§.Ü«Ùg»Æ×?~>ºÔPqÍ•ãz:0Ê)ÝÆp€ØÍuËìE6°† ˆoóIR€Â …Zu°0ü$ö«+ii¤ëML?ûKÊ”å5$H•éÕdÏw*"ÿ~‰aâˆ@†­>iÙÎsµN»d•ù ¥ ¹Ž4ó0ƒ -?¹4Çl$}Ìç ÒRyº†ne¿9¡^Ëß)â«F<ðqÁì9.›5Æ?äøWãÏé9>LMq†z=ë@™¸Ö/ïeyÛùýúa q<„_FŒ~Óǧk–ÜŸÇÔ§ÄM®EVçƒÓ6ââ¦A‰·»°Ô(ßÐÓŒÏn1žq å•eŽ­›úŽ0¬£Í{.¦%ŸHOû*Çžó¥Lyˆ¢M×6ÛiP«åêø4zAäÕ×!™Ú ?FŸý})Q:$îðæó¥â"Ö†/¼[©ÀÚ ¦¨,)S\­¨JØ>0€Xuº¡‰Ïçøgµ[#¢H™®¨v¼†qÜíl°¹!íÎÝ›ì;…^œ„ðoáÍ#e ]jfYùÕ¶c—Ë_r¯Çi´}⻵ðV\/ì¹ ÐùbXÖVöóc°©Ê»»ã×Üc=ÍâãǯÿG•ô—oCzåîØþýlOôÁpÏyBädö §›ê„ÂÁôwÏö-zœŽÊ¨s‘9$Ë-®ð÷M¿~ïÃèZ‰#÷âÂðò2äÀ@,JÇ¡ÎÈâ‡râ†kO@ÆÐå›x˜àÏɇö·0N8åã~Kßkÿ—‰n?ýs0;Í!¡G_–ÇÉ^‹ƒµñL´h¼ó{bÍFÇRFuÉ ¬ˆm-<çG÷ö¬ò %êøûÃ@Àn°Áev”»¦ª­·éò™#Uà À ‘Hˆò:'Ë^Û5³†Ûhò¹‘Idr;TRùòVZÀ€÷q[æ„'o^;Ÿÿž¨ûëÎcøößíÙŸ¹³¡>rù±BýñôÙ¢0FÀýãF?÷ëÕ¦úL»´(öi¬ËO£‹Cw£Uëæ½ß2¼XšSÅ—mEšöA)@¿ $Ô´†r&/?çïãq=Å6û¾}äî¸ÿƒ¼Å -ƒx·r°øŽ¡"k鹃LVM» ï¾ö¥£†W† £·ë>’ÖaCM¬å§ÐìíR5)fz,Ár~š>®qQsÇÿûÍðý @‚&+"ç{-‚‡6^‹?ík溸ó=À`åaŦ‚†k›çWû®nø€ W;Îq^”´&š·ÂÞYÐPíÉ(ǹ0þå±×ù ëYËÐxTÇŒ™ü‘b(wrUŒ|z¼Æò¢¥ª··àXÔè}“ œ[;U©y^¿†îüŸïoó¡kâ‘×/ýfËä´oÃ4^~ÿ?oß.Í#ÝÎ0sÜŸ>”?òÐ5;ÿhª}y ©KRª—§O¦áJ’WƒÅD̼<9>q‹vøˆ 8ø2 ·H¡ª#=©ìžw ù==¼ºÎBzþˆà‚¾þ6É÷× ç@‡–ÆI¦ž¼Pæ­Ê!÷-¾]÷·…Á$û>Àݨk^¦õ×[j:Bo?+*ñÐõ6äýZ¾gI/¥?–æ^¹=šŸíæy<Ž)šÉ¸SÒC|ž÷úˆ#òsDôAˆSøgàyÎ|îCpä˜ h@ p¸ 8¦ÜbÀf€RTaZÐúE® [ªïú±aìh$sPmÞŽO¦â-÷¯O"#ãŒB޲xäuÅÂ᯶¯ÿrR«ý³`F~:_Ë_XŠþø¿®†ýÿSRmŽ¾í´æ2ç? õn,Å"zï½ÒÅÀq>»‚YxŽMQå9CzÝÍwó¿MU}üóf #¤–3ûi¸ìVA2æš4H†|løã6˜ž,O–.e=‹)Ý,<^|Oc3Ò¹é5æKü{¯_ÊÏHxƒÆ0ôÔÖë¯$ažÛx8»ëwÓ¤{ïÿüÿÊã·¿Fìçß~F÷”Ñ(ÄöaûXcß­ñcŽeÏЦ-U)ž ™H Ó·Ÿ›õ(Ïù> €søY¨Àí Ïlk»çê©Ï0Sý0ÎOg,žóñCM„ÞVY˜žÿ­#_×·uö4ž¨­Ã¡ÿÇûry#0ÉÂÍúìùÔOŠ2íŒà_t3®ˆµ™0Ì6 Õœ®·é~Žùë3·>×N]uþ¨F`ù_§ÝÀs ÷€c¹cË×ãÚr]¡¤’ Ÿ¹AóZøgŠ: Â?yÈÁžþ©š¢¯ñòú¹P»ºwì ç{-úVÿü/p†€«Ð"ßš?ë}ÕwlÄ1®‡™©b¸F\‰Î”ôÕÙ(/“|…A'áý[æš1ì…¢óÉÛêëž[O¾œýî°ŒPQêZêÝæõ„KN„¿=ß2ú ’q„Úó!æeØ—Ç÷ö—Á‘||/6EHäú6(¾dù¶óĹZ#ë&¶j¨éÄ@&—w @F„ƒʃkC¹¼…ÞA¢¦çß­ó…Éô",çU¦…{¾ÍöÛcÒÕ9©ë8°éîýñ4%Ê\s#s›­Ô:0Ãð …ûv¸!<ÌÜ‘Ÿu7òÄš×x„D;÷vΙž=ÖhC][ýõ|, ø; ..FćËZ:Fš’”úÙhÇR²‹Dذ Î(ƒ»ÐCºç§ž’ ËæõŸfÖgá¸{ðˆ/ÇÛç%ó5»wêxecŒÖxùð]©»Ö¡ÔVsÝÛ…É …‹;¨À†Ž^úæg8áx´@Šg·a<Þ“©:š‡ÇÕÄŒ9 |ýX/uJµ¦d¸âÿá!¤¦ƒ0å³E¨ç‰Uèm§wßý·ÎaäÁH'8æóÖò«Qè:ÎÏ[ m~F¿? =[ìb×eæßtÇq|ùø–ö^x|ô|¢6¨'Ì}9N[²C$3¼îzMŠë¸.Ÿh¤rnäî+1&5¹ùN Tu†ü \fdå­%Œ_±yåŽÏß¿ûå?@8•ùˆö‡Q²î¯#w ðÅg`måÚk™q7C:­=ÞÁðïA[î¸Fªç_×6Îü8 õ¸;xÈçDÆùöÚ+ãpdÐ"ÞhŒ­=wÔ,3wîâš?8ÄTóçþ7eÆ)~¯g-ÀNUú¼qŒk¯´×ô£áy‰hÓ%î‡_c½¾üÝ|îXÔ¨6éý¹ däôï¯àc›¡Ð"OU´Òâ±V–ùb0¸ÕIÅz.•Øó D$;2çò:sVÍßÁý{ŽB¦Mrç'¥Š•oe?‘K>YZÃKn¼·‚_ÿÏš÷Á%:1¢Nü¯ÿÒÉZœÝ& F •W&;ñן¿ƒÛ“ö™š¯ù,7cß¼ºb̬➫ô`:ÈLŽgÐ;¼? (¤šòÍ"ÈÓ´[rк„s¢ÙCñÈ÷Žuãç¯mùYDÎH#F.“TCº·Ìrno¶Jªùú}û¼ŒPæȧç”ßÿ$˜w^`D£ÓµÛOfäõäùe_Cýk³Ny#òìõ~ýO”µæ†´S¬¨ñ°=ÿ<]Ó,©+)%©Ç‹Tô0â¼$£î lãgrmzwö7½;˜ª€Hc…ÎMŠ}°ÃÖ>Ñ^!ôÒQ\Åx ÷ð=äïCQ‰V¤rAnÄŒU—]ËÌ·²k‰‰älî˜#ïB'í{’.ƒ9Þ{çgæ¢ÍøíGÃ=žk^{óë_ÿÙƒ/ƒ°#ýE E¤„uÙyXZ-Ú§ìõr¼Z£šs@΀ã²gÍyihè¤&+|B3•ïu¼wé x?þ¨Á ²ñÑÓ±üÝ7óŒñ¬óg qI` Žç-gåç¹yqèùV7ê.~øä7Ì5èCŠHš&Ï{"Î ¥‡mGTÛ5 Î7ÜíÏš[·_IÁ›‰Ýñ²4ö3µyFu¤ÚË×ø@Ïð²b…–´ñgröÂiÚ¿îÑòºÚ ¥dú2×÷êY¤}¢„m÷ŠRA‰N B#µdNú@€œAþã‚í@f'ºÍ&;¸ìí­l¯RíÛ‚ÈFJ®"¼o„¬€®\²œ/ã†+¸¥œ”LlÖGÌ?Iï]e `]”ì7C0ʪ`oõþ@xØi¤ƒšû,øuôßøÑ.o5§7•_Qv,eÂŽ!ÒE;3Hfpö DûÈ7¶¦ºÉ|Mç7ÿgØÚ/Ÿ½¤øöíÊîVÆv ¨(Bý[þDºyŠ?p7¥y)ÏPUDYÄ@Vß¾>…L—Ÿ¨ÝóÉ«§°sós|F­ÈÌ¿Jö|Š€³?’ËÍ|žGÙnæ•98YVêŸÐØ|Æ.jT¨+5;X'ÇÕÔÈ…¡#ƒRÝ„Lî>‚÷˜eàËﯗðX‘mZXûøy<„Õò—ŸQ Ï+…÷‡×¯é"…aZõv™ÁV›±]27ëX•Á81trÏqÑÄÏ&&9`Sž Rêd™zm ³ì‰¨2YTY½˜éCO%!jô£4-)ßdžµ´ïÏŠµ<üÌgçQâÂþx¼…]zРتÐ'o[÷»a?T€Ì7MX%ÅëYýUÞ¥ôâÎÏz˜Ûÿþ×ÝûiÇŽ{ØVÊG˜ÆýòÏÔãq%óŒGþiƒôƒ 2{’Õ<¢¨ü³ƒ̿ݿá<£¸‡½Ìåyó„Χ×ýýÉöåTäq¼ÍÄž¼¸â5ÏÛ!¼oF~«׋ SŠÄŠh~?I0Û Ü?ú}Q º8÷%DwbùÌåÓ²œyf¬]Éòãµ´s/üö=€J_t¾kz}¾8ãÏrcò}ù½¦UÞùœ¾þ—’Xít,Ók¨Ø®Ÿõ¤ <ªm>( gû›B ’”c<‚M¡½í(í…]²k¾¾Þjþœ÷R ù ‹«cq|ý? Xƒ¹rªÃB×f½&ûR“ÿXöZå;MYd¦úX¶lœVÑä<-•ù2ÃÇó*C²Ë— >¾ú›éõSú;Ø|â(rDq0×½c‰*A~nÞÖ|–[ ¿sâÅÃ^€Ðä&Ù­£4ì<ËX`æ­5Ô°ìíRj󡾟™,–þîÆwùög•F¹”<„hÙÕÏðGÚ†ãxò­ó!Í%¹4~+¿¼Ü=BR‚&~ü·Ë½=ù´7b‚rªY'Ì™3Ïì÷à›Î¯§¢âóùü`i;lƒ!m®O²ŽJ9\v»!–Ë {B_Ö£ ÙóÉyI¦cøt?Ïž°³bæ$š‡”€·ß'6‘>¸ú˜¹Fˆ²”×ô[IÀ Ñÿ4λ¸Ydø|݃¥¤ðj‡e>Jò^¥ê*ðioRâR^OöäÏ⛈@MÕSìr1ù¶ÒLj¬{KÎ÷mº¤ã±a¡+çª+ßÅ,`ìªøû´‡ÎõãF‡3Ð#/ð­ó;• ±Gå86c[ç)xèÜ)Ÿ÷$äݪLsgv—®–`”õÜÙ>}ûÌ Ã£GòŽòë•¥ÀQ:æ9Âpa‰À$¿À‰!\Žî½ñ[P–›²àŠ‘o ¿/·Š-¯ÀÏ(#ˆóláäíüµ¡½|-±µ«ÑœeÀŒßçrhÞåj¨ÖƒÄÖç¶’³ô‘:¦ŽJ™NÑ£§+{ÞÁ5¶§Å²kéîåÅßò>§ß7Ôl v'AËAA·K÷õŸçšpÀ‰òYpVcÖñã{õA£Áš2`ôS‚%¶ å¹Ö/EŸ ñ!˜?2ž[pך|¯é!«.ýu ý5ÈyÁNÇ-+t˜Q‹7&ßè:¨¢ÐÌëÝû›çÄmÇsÿ=«ŽyN¥0–YMÎ@·¶wÖÕc‚“—Ço¸þ  oꑊ*<õŒ†÷?n6È}ïqúZ¡Bj?ÁÍÏ^€bT]W’UÈÊÒ‰Mà0€f—GXm±Fž‚ Z—Ïçó;Ki„aä Ûƒ|’Â6ƒñ2¿»}îx)±ƒÐ4è˜}[Þ†Øih|‘°=ëºÓpvv{ÅþóíÕ% íÄ®!FOGã¤#Çýõ?ôÒ¨yɃy¿5¡¬î ¾¹ÈååÊŽ=-aŽå}óå ø$àçÔž+JÌó‚ñÇ2Et‚9Ú5Ù€‹;puÜÏÁ5ÿÇI‚Mû ÁXweKª¶g÷x%œ.RŸžÆA)û 2Ê”£ýž-GHÏK]~”ýôåÁH¤ÂÏÆ˜Æ” ùÆÚK­ÃŠóoF¾<ÏÕëk|©Kô‹8ÉNŒãºI|]”ßõo¨jÂ+ðÚ‹uçñÇÞ_½¡ó<í«ôtlDo†¿¬Á”ÑÒèµSPÁ³wÂÒóœÃˆäÒ›[™^®ð_÷+y)zd®ž*RL”¬Aνž¿ƒi×WJÿc¦n'ló]"€¥—¨uã÷N.AÝ& Ôò÷0x€Sܘs¯Uyøn{²W7zŽR9Ò–Ë·ÿÙR‡°—Ù»a¥zg–†H‡«N<¡à—/‹Ð“*½¡·<ïexÿ7¯ÈfÛ`Ï5=Fä Ÿ—Ò:öþ:XÇPÇ eø—RÓ<Äï³î™@€Ysr+¶)Çwš¯ôø=RâËÙq/÷ƒªX¿÷3&Y²DÐi=rÈèÇDüLe5/;€çxîÇŸ#Ãzé¯þ ÁgdxžðŠ 6/ßÿÜØÉë¬IbúMÁ{¦P¼ÕË—kj1íÒ®$Íò"äÂtÞ.~j'–PZÚ×í8¶ï¥ âËÇŸQÆ17kñü¥¼ëðøJ†e)û/2: HgrM¦KмüzN‚¶«ÅVÞ¹±Tå<ŽàrpNB:Ìz`¾Ezx)„¡œ¥l¢B¹ÂI}Š €¸˜(R}ïs–Ã@<2ÿŽœ?Ÿ—®B ‰ÔÈBa\@™ê*õ<ßÞî"Hqþ1Òÿ,áŒÆKyµxÊ¥—ßn âŒ0¯ß5¦š±ññéG4é`Íÿ?6ú†·¿÷N'O ×Á(,Ϭ†G'ürÚ3õRp#>—ãÎu;Ç9:¢ õó™¼þûz–J3zUQM­G6âøõzFÍ(°uu¢Ÿ§ÆÍï7`Š xãrD´ß7Õ{þ®R çÚyZ4näÚTòC0t~îµZi·N-’.{/*¯eȤŸãÉBSª×K]õ\>Î#3Ô9ÐË“©‡ZçÖÁèD¨/ã>®_kU:¢œ ¯š›QrµËƒg…g¬H`qýSÑ:väl ŠhibV¨¬;úŸ:ƒ­Ó&¼äÇûUËD'p„n*ûŽ”:'ZD¿QMH?KÓy~„B}h¦Ïe‘.þwö#f$ò³ñ«‘À¶©wÇu⎢•s>7¡CÓyÏÓºÇr[I»3öÐÎ~JËà3ò,ÝŸEÉe@UгtbBøíóÖªß>à&vn57¦ÈG "¢'’b˘›~ÔVã4~ß(¤ß¿]_A«Uu±ÔùVUýðú!~*Öoh¸–žªo[·ŸöéŸ'6£oRcÜ%|Ö³»‰8@K½¸¦Í«Cëë„&BÕØøw€ S˜*üì0ìU SóƒåHÐP„†žŽ;›|3+ºë|Õä7ÈHTÌ0µŽ‘”’ßÏ%éƒ6€~@'j„;b“¬8Î1„Ùfg•B§ÎŠüJŠæµ-ïÿë¿oC=¤¼â+Ôl¼äã¸,tÕ¸ÎÜ*“J¯ÞìÙ¨ÐÂ]}!oyõþ.¦:3(>PP}‰·ðêŽÊvÍçs”¸iR…¼yä´šÑ\i ).°÷ìhmÔ`vHzg§¦4KF¦é÷?+6ùK¨ìgXže-™r…§~&úY ÆU”—Ó5 }6ö~—­¤h&¸§V2ÿIÕ{„å—¢ ØüÈ s'5ôóâM—¿þë¶1Œqÿ™Æà  nÌkJ¾üÕ뇈‡Ž;ÀqN5JM‹ôëå˜@ÃäÄÜ>ïµxâùŽ~̽˜—r¨ç8=ìæ‰•’á)”1c3 , Û,óÚ5@Y o®}">gõìçgø–v ö”¡^<³ƒÏYzrµ´•üÿ$õZÔ¤G)Æ÷¼X“Þ¾(³Î›¼úåY+\LxæŠÏÓq†F”ŽâݼÒ×o×É/#Îu6.o-7N~‹ ü þqÍõg ÂXÉüXÃBkw²yã–·¡–1‰Uß.³2&ðE@*HGFì£Áç)VÞŠºbj´ìð„ˆPòØú·cm…äPŽˆ¤Šá„£Gß>ŠíG—¨þ½—@öZ:R=HX9r=¢ K…eĉýµå€cwÉ~%â0SÏ,!VÍÿù¯MÖ{à ŸHt>ðzÙêújöthæòÆ8rUQ¢,õã7ÖŸ@ˬªœ›ë‹é|ªù ¯ƒ†½Î™1³qé'9“7A ÒÙèGŽŽ:~b4ù¬È~ªíW mĨ²èÁ|`p-bÕ[ª¦Û¿ÌÝÑÌ%`ÈŸç…H>Î8¿M@;°Á\ Œ¡G(¯¹›ýÄÛ†Q [š­éÄÃÝ…óþ³fûk£š„úé­ÖXÊéMl”£îÜ,±­ÁãÞÂ|•R)ÆH/¢ üí-@ê#/Ý2ðºÖ^éåï•(É o`^\Ã47’‡Çíõ¸19*ºo6.ï\—Ãýó˜0ûi‚PÍûʱv2#uIþ¿õ”³*nê&›±V&« ÷1™ žÙ»¼ ñ’ÍH §”S€›l5(ýØ£4x3ÔbÖfxï·?o­¤ãKbÐÐË1[$²¯sõí¤fFˆŸ´ÓؽY”rcR¶÷•À ¸¬Ù~òÎqÿ<®‰ýÿ äµEpf©rܧ  £©¼î|’G!=ËgoÇi²X$vf+*Y„!ý…‘p²Ù=øTuü|éÀ+øõF¢“rEÕ*ø2Y‡HV7Á˜±Þqh›ï°4Ç’¢ihÜÆ\4H äÈ•"¯l¿6¢ÁÜæåûu¢OéËÚÏãœù4œT Ÿf]>—»ÌÕ9Þëø¼ã ’ðÞHvçú¯»‰'ëמ޺-¥a)!ßáž—APçýˆÏhÉE~zæç³¼]jViІ î¿×y@Ø®z]»óì2¿øD41ó.cb ¬¦KdIµ(ç+i /á ô<Ãåð:Ó# V¥ž§mm¹¿˜A6W š<.º¶} íþúŸ›´W’„Ê­£L—ÆœÜv2.-A´Á{‰w`õ×ËZ#N>5Ò›³«™Ÿ ã¾‹ù;T}Ü1CâŠ7[y>R¼düGgYK.5:†{ÕˆÒŒÃ~®N81s—–ŽQzšJ­û†®Æ¥HpRœÛõÈu˜P­|Û£|i‡¡>Ÿ ˆÊM€Šæ¼+°ýRhÆï¿þ«J#eÄ’‚ñUj«Óðå!ÌI½<µÞ6ö°Å/ÐÁpÅ5W³Bæ«ÏÛ!)ä ¤Á7hr "—‹XvfÈJ¼–!„:—¹)·gGÿþsW áûä¦g䯽-ù0b­Í:ŒM[#ŽcŸ¥aä§p I&Ïe?UF }<‡ l|‹3>B„rY=¥Ô5gB¥‰–7xÑÿ·¹xs÷6"kéì?ÿëö\®I¾Ò á²9©‹ï%Ây¹}þõ2MÒ?GðÃ%ëî%Ìi/ɹ‰N7ã{|s™‚§¸§ð؆w?бëK6l•æÐLS;?þf  ¢)JšÎQÙ¹aðîï›´yl}Ïè:[*i—ü[sÏÌ><Ð*l!ó3àb!­z!~2c 0!Ü>¬©UpJÁ CXsrM ë|D³‚à#ݰ™z)-áS Þk°†Gç@›r©éØQ¥‹ãè™õØÞsÁÀž)Õ>4e?c.â& ÷æ`\…KÈ¡ôÜÓa‹žj?¥¦÷9!™eü×÷—Ë#[ÑG>cô^_ªfhÉ)Í%#–˜¿À¨‘mÉÚgÏ#ò1`Þï¯9d%Ÿ@Àá-9y™ Sî;5^7'0Eï€ÁxÊ1îŒäíÞO>Äá‚yms5.Ý6ñ16C×&Ú²×LêPÿ’õPrÞû¹¥ %Ì“Áí̇0ÉÃûý­T»Ê€ä€P‰‹ôˆ÷ï Ýu¦ îAk°¸SêP16i^®º~5^6pmlkÏš`E¾ÏÐxIò>Gy÷Ý­+K[Ô"ï¡ðmZ„6áùœÉ*#™ˆC;ÞÃÐÃÇñ^xY|¦ˆº(‰×òYŠØ1v}FØê?c”46ƒyRt¶ý諘øþËûe£Xˆ—Xª‘^®XV«K*ÿ·»~<“Øuô„ò;ƒº§ V½M‡ñs.ÀGŽóÏßSìåЊÂQ®yÞÞí#ÃÍ5ÿº1ý\ãºøÔîðÎx(¾H_Ê3³4g8Õw}­þƒ$¸¤ì>-%ÿ=æz0æÝ¼¿˜7ôwcôH’b»Ûì3)§NïÍ ;Ä{MÒŽ»æö·¼0™Qãåö·F“ïµBAiIŸ ‘BP«×¹åðð¡²ãçÈÇrý< e¸¯¸îÉ8ŽÉy:8?ºÖlÎ5•©à<Þh›Üþ&Æ=ñ¼ žÛ9“Ç=õcCB/ýgŒ¾ÂzE#­ë>ô#û§g +ψ¶¢|l­ÅððÒ,7uù‘k[+ó¸­"Ÿ3·xõµþ¦ä„|]œ[Ђðøëéëû&„A2DçÄÝr’oîÞ\µ…ñI¸ ÑÏIñ{k«g¸cг>àoÐúX=þSå¨LÈ ÊF›oˆuÎD ÉüƒÈ°TxF•EE$gæW뀅ø» î± |d›@Ü7ùëÀȵid] ^RÍ¿\zÿÜ ØäòøçÜ ] ô¾“y\£†ÁÅ_BC¦¼¨ðd?ñäõm†Í÷l<Ʀ$ðô ?nÄ ü³7¯¶¤ˆ0¹úêòœ. •t#LI75¤X(<×%Ÿ“æzrxf öàtÝ0”ÜÎF [¥nÞ~4P±’¿ÖŸ1¥¦¥‰{îyí£Ržž•óà'±Ùçmó‰@E-k»²ÛÌ»ŽS×åÛßž•7BRÛÑ“ùÃø’Üî*µ†š‘Æ3ñÃó°ô¡t`ÿ~I ñÁ@LûgpNuz‚e'`áòȈs†óôêAµãÊñû¿hóšˆûóºê>s†1¬SgäïqÁ ƒ}0z”íÙJÔ|¹çÅõ±ŒçF’§ÑÃë€!‹ã Ö¿/¯'ç ø“5ñÛ5RÆùŸc².¾à gQ„ß?´üßn½ý©•®ˆ¶_ÊAyc×V(…!¤†2Qœû3£.¤ÂŨ&‰¤õöù]jñá:aÔè¿<k¤«ôð3´îë¶±êå6¿p±S¼ã2»쟻ÝU©ÅmHfa ²píµüò̈hA4²w>FÞɺ9ÑŠsóüó\5—vÛϺK²óz?¼u}÷Ó-ÐHPkñMÈŒ8üä[©ï_ÿéeË-»Zõ¬Ûëm®Ñ|v°ÄÀQì†há„^^#ö"Ÿ“ø\?Ü;×ú½É$¹Ü_§‡·}'ËŒm€‰ÔÀßžøÞhzŸe%xµòlO(e#÷µ™££¥w½Á?qBŠzjGòœV†ÿe‘dô–×üX5hØ„VÖ¸|(×"3‚ü¤ ¸Õ¡Ã9íÐhtœë\^k~ÿóŠÆO¬™‡³ÕÕkÙ~Ìç“gŸŸaýÌòá®ÎÚ ne¿yâû¢‰fhà6eÓØÃûÞîSÖÙÇø~‡òº›á¦¡b3áçòzH. m@eë®PÀó÷Ñ\íUYòÒëõDÔIøLí?á–6‰W´k—Eðàஜ—Ñž¡` Ì<«ëxácð©R€üQ¥²ÓótÞ5Dï>ÔÂ7/5ÌðÓK4åŒx—4n¦v™†Õ½ÕNU\9¥¨úŸ4ZŒæ¬½‡X Õ•ò+†åµ×õÇ:?‡\ ¯FξÓª±ßJz‰Æ¥ønáVw"ñÍ1hT† ÜW²ScŸs±\Åï#ƒTlYžM½þn„ƒžZ†1¤-Å¢ëé#B¬×?ÕüIÑRÞ7aˆß·5´w$ÍIE =æÞ±JT.y”¡Wçf¢pNÏ9£/WŽQNåܬS_¾lJ¡‡u¢·ÏÓ\ëñyntü‘©Û6õÏlFE·ßnýËáy/?Ÿ<½¶ü}|ùòj*×ÔÅèìŒBØÜää§ÁÌï6ã ²x>žnt˜RnFý ˜üŒŒ’ÚIF&w£%Kñà1÷Oç$µ¼ŽT{[…e“˜kE,1ù® 3ÃUQ¯Aê7wcÎËl\?¿ÂjÂeÈÅ!*_ç·ÿ~è$Dº‚[žk`5é  EV:Ñä«¢Oy–5qß(¿` ’(¢ó“{/л?}ãqÒÛ¥ÊQ¢ó›_B%6–Ái´šÆ(ª6t¿§8jBúVê•QãÏVÛøb•\Ê ®îUÉLi@~„ÚŠ;é„v'»À±ÑRóäD¤NÚãø™"Æ->Ç‘S•¦Íú¨øË€Ó—¼…± ÌÈ•£—¤ÿbÉN»2ü^î®Bu×ít݉±á·5îžµ£ñ¨¾¹­šëíã•Hg“ßè°ùÇMþÀfà£vàé˻ΌMÀQV2]®;ÊlVÍïÿ]ž³4^Ðy7Ê—‡† ˜héF2ªÔà·©A#ö³¸"¸ÑãR±^“2Ó«þü:Uzùüˆ™%úà ¸‡m˜Á%#”dàQyi¢öc¹®õÌô3†ºx–GhÁ9¾O28Åñ^qß]Ú©÷÷‘_ñÀ†1ÓÕ‡ïG*N»LÀ†Ég%·!‚t>(4£V†9Ž©îSÌœîÊ€ŠM £Á&›šweškÎïEãµÊèj‹ð™‹h¢6ÙØß©Ñ:ÚãÿÆgÆTÙzî\óô-¤ºÍ°ê2ç£ÝWù}’[èTMÎ76P’g¡u½/Èñ¦z¯f£Üÿ"¢ÒV-ÈŽIÄ$ÒÐ98$æûg¦xè±þ¦9ÐsB³Íï+)»øù<'71ÃH&>I‡ÈC6ã$áÛ|PŽ•–òh5ÿõß‹Ãh÷àÄXg‰ûDÕ}Þžpúc¯zç E)~\iç˜1”™ïe<]î÷×=öˆ.ÌÒ"¾bS¶‹¾+#n¾/®8–o ¬—8µ§c"ä§§Ô$ “ ¾È®‘àu­A´áäéžÈ;#>e4þDœà¶ÈHFoY˜©…]æ¸Û ‘ëÀ6߃ ¨ŸË¢îÊaIùŒãþ!âic€Ç(i-ÞS9‡ÔóüÙ÷®F/Ù¼šR‘HÁ¾—×t×¶»I‰=#×—‹ƒ!xQH`KM{4{é‡ !¢²a†ˆ=Ѩ‚48pnQ |Þ\urR°a‡‰´üicDQщ„gëX5:•×r§|~”Úö”T~ KëÔXL1²ÌA9¹·)ŒóÑLÈwfzb–Ïp²×Î5–QÞ^ûößëü#IEqs×PY*;ôQ6k G²°òÑ BõHht ÍåBî²Ô#œ£cÞæb/Îúþ†Ô§ŸH…Á[NÔÕbv-¹Åôùÿ:^žr]SÈÙÙ¨“²^\ÓW•¶õY™ìI•ÑÆÕÍ ÌU’Îa4n«mü¨t¤ú°œ–' šnT‚¿däkÂlÍ£äDï;t^Œ{ô¼ 04”|ï÷ö÷ÿYÜ+h,5j¼¥¥=È ‰Ó b Œ"h>4€Ð8J/AÊiDä5¾Íàð}ô<5‚0vzñ”ýJ^¸`¤æ‡šù}Ò «JÓáÓ8@P¹G6³¿Y¿?yŽcº¯bÜ4KÐîÊ^#@F~àl8y§Õü<úžQ—¸6@ppEþ³šÓ –×¼¼‹À|&Fr€äòþÓeÏuxÿ-#®òKUóŘ/[žŒd‰Ä´²€‡}œ:ðx«d§ñê23àãóbê±o"Ÿ±­ôcº‰!œ"l‰æ9é”kóó&xT3(‘ù2í¥µ…ð‡HÏZì’,k°ãˆ% 4ñ_³EøÀ„{r?ƒ0 _3ƒ¬åî‰o&¾o€êY2¹\~ýëÆ‡ß¸ý!«Ûϧ_!¾´3”QèšžQÖ^F?nB#ùYV±¼¢ /{¸¹ôëKDø`º»#V5ðiP2Ú•†Žû袧úEí#–—º†-=Û¡úд#$ý½·ïJrÉ¢F¢%¶è°oý{|N3šÄ™j˜’`âȼûOƪ.–´ÇpV¼LÁÿ8ç¬ÏKùõ[Šm®|?Þ„Ú5Õ^ÔoÂùìm',.º*/U€·ƒÕËp  ¦¦žt9Þ.³tè¶çø®>hkÍ@™ç1¯g)m"’‹dY; Ú¼™îµì”gcUÈö۵ˈÒÇma½™Å<œGÐï8ø ˜ÚˆM©‘›âŠÌn‚ØŠA¶Øœò޲àóùÁä&°ö®9/5^ÿ,ë%Ô`ðN~›Ge@=†Ç¹‡Ç¹~Øs ø(½<'](>ógH2FfsÏÕšûöMĽí,,6»89i”Dø÷ñ…ÁOÅC¼½¼@ÅÎÓEõ7 [Á„l"÷rõ,JüÙõmv™cB\×ßt¶x„€\׬²•€‹E¬& 9aL3¾OIžá¦øýË€ÓÆ­Ä¿T7Ùè×oUãÿ\€à^Öž×C­|èI£î÷ä­±Æh>²F/½<ˆmöniGêGê+¼¸£0v±¯X:òäªã0¿ËÓ{AOÑÏVÞ<^ÃE¸çå'7¥økøõ$×ÛÄ9!&zòÑÌżžîWÅ{h‡#è:ì5ÊÙd‰ Ûp_X'RðR‚{`×ôa'à;¶Ï!IVn—×53?®” vVöý—É;ÙÀàÏ÷*Ý`²Ýâ\ÁGmO÷õ^_'võ_lþ*Ÿ(* R­6Q„û×X÷ÎÍéfó<õ÷¯e<†Ø ÖíÖÁ¸‘³Í>ýJïÇ[å0+ñÉ`ï‹'8xP3ר'&g± \.ouy{­oUz;Æw¥ÖUÚ}»F­k£åŒ³ƒ,ÕhÿêÎC¹qÃø˜ë÷ø÷\÷·S¶oz±…›± F¿¡ˆn³QºP!Åÿ3$’Ba•”¹ÙºmÊw;Éæ¦e©Ø‹X_¡ÏLoÔY@B¯K í¡O w}РˈØ8ëaÍvuÌ—ŠQrûêÜ8(Oå²»à¡~Eœ,+{«ŽS\)C¤Çˆ6{·Öà[ßßlYÊE4QB¤ï9]kØ4Ëái ÑF‰a390­åZª ±§¸­øçOŸ HU.‡,£Îu¿óÙÒmiUdF´$zF%‡½tŒv(vbDìºÜÝJ³5¬¼|'qëâ«q½§¤ µ¿Žuý¤Ž¢Í³`Héæ'€³$ôdÓØØ%-‹2¾ìM0ÅiŸd ¹^ËT°FÄ–°óC@Bu˜PbD`…˜ªØŸƒrçÑ $ñ.CÀ3É3úÅœ!26鞆(,ì!‡½Sx¿}ýåö®¨´ ’)èû ’'¬f²×œîc5"v=Ü× ÄUÌeÙzœ4Ž÷ Ñæ™sè hÇ*!0mUŠ«"§<¶îX›YðéçÌ2¬¥]L¶âׯ_µcw@`4ø©!_Ò–å›' «3·d&–æ±R ,wx©ˆ«˜u{÷p¯Up¿D0 eÇÉmSC b;!ž<$fÏ©{ÀÉ r&`º/ZÊ^À0vÓš¯¯¯§¿—!€¡V’C7HŠ›kž½sþgï+àãÈ‘¯_iØvbDZÃÌGËÇÌÌÌŒËǰœc^føÝÂ13ó]àÃÌd¶ºUßX¿Ž¾š¶ÜžóþcÇ^½MV$ï©T¢r©„G<ü‘X¸h1*Aí3g`3gÎÆô¶vh è0ĬٳÍ÷}Ÿ„öö™hllBh<ö±GKs XksÏ“žü4ä 0¨S¸F8‘ DœDfš¨"`½œ:IZÿ÷“k´`vŽå³lý(ÙêØ)²/oG"7–„8Ôz‘]Jˆ "›þŽRJ6ÌÉCNLnuˆ »wŠ,W]‘·È 4^ö²WàOë×azk+ð€Sð°‡=Óªöégœaì\.æ*ÁW®\‰7¾é-øþ÷¾'?õ©˜?^üâ—âÇ?ü>žùÌg£óØœ}ÎùøÆ7¾‚—¾ôå¨T‚:E@j×!˜H"k™#Cœ üOÝú@…Àq•!bˆ"@ YÃìr¼U²XW^Õ’[]ö(†ÿÄiºÅRÙ ýI$‹€Œg²£À¹JYˆ€³n²A•J¡X,â׿úÎ8ó,Ü}÷ð‰O}_úÒ=øêW¾Œç¿àxÊSž†o~ãëèíéE¡¡¿ûío„æÎ›_õžŒŽÎäó ø×?ÿ†jy¹\ŠZª[Äï?™D@Ö…Èzõ}Çz@ó°óÅG÷2]· .`báò;† -áDd,…ÂÆdð@P)ÂQÓú§à9·+–"@ʹD@ìƨD IC)BsK žöôg`Í7¿åíxÇÛވ׼æõÈò8t艪Ëo<öövÓ Ìëêêĺukñ÷¿ÿ ¡‘ÍeAÌÈåóâÍœ" •`BŠ€ûÙ¨CX(ë¨Ç'D´³C‘ú?JðD9»E€Dðkúü$\yüCT¿vö-ÙÓÛÛgZTW{,¿$;YI£÷wæ:E€ˆpçw`ù²åØ´i¶mÝZué€0düæ7¿2ßgË–ÍØ¼y#òù<®ºò3hÖŠ ÿýúûqÛ­7á̳ÎB.›EC¡ßÿîwJ§ño™L&ö+½(©Š "À'^ˆí¡°îýxˆ€åÁÄŒ‹ÙÕÜÒj\ÂÑ{<²ÈrNP­ˆ@ ¥˜H›ò˜02é˜ç@èèè)rH“0k¦(ð ªKDdúøûû_qäð¨”BWWÀÚ|Ÿ•+WUãÀºµk–¯X‰émmÆÞ¾m+Ò™Œñ¶oßnˆ?XÇüÇŽ!y&ˆUáþßE€¨^‚$e†o­Ýõø¤fF±8€9s¢R©tžp¨¾É7O9ý¡¼g×vRnà$`np»nBÈ_N‘’PÄÆ¶í!(æ!°ˆÜƒ¤0 ’¦[Œx8>±s¤ŽF!ŽøI¼nÝ" §ØrTWÆF[«Á«A6—3Þ½kWµÿÿ[¬­ B:©‰¯cÿý¿Ÿ*Ah4žcdнŸ-8Î" Q§Øú]ÇpæC=Ø8mkëÇ+^w6´Fk*¥ŽþiͯyÓ†Òœ¹‹+7Id`Ø2i%­jciÉ)È.ܱ {©è•¥â‹€ÄÜþ¸­ì(Äž={œË?Ÿ˜e9cXˆ£»ÛKqÂRf™Jا®þÅEIKZÿ·ÅCåâ!Qvï ЉYõ¾^<‚ÈÏãd€‡ß`Œ9´Ö8 àáÀã>ºÓà €‡Rd®±3aœááÀ£uZ ”R`Ð,OòuÚqwa"9ÇŽ}ÉÇ&wÞsÏüåËVìb0˜8ÈÎò N¶‚ ËG|evÿëùͯ~=kõåÄØÃÃ{--­s+AÖlÉÏĘƒ5‹–Ÿ…¿Äó¥8а»¢/[±|!/ã/étæô ÍQKM1 “† f R°hé†6L¹'šËå`<¼xŒËPÜœAÐQ+N °tû‡í0ؼp¤ RÙ”Ðd,ÀøÀà €3Ÿ^ ±(@[/€ÙdÊ>"µÍÙóù©ÆýgÀ>ƒÀI“ˆOÁøÀà €G„sX°†Ì &Ûº‹¢È}~+dêÙ›Y<‹@IÓçc|àáÀC³>KXAtýRRLšGœÀÜÙ`8XĬÇÚððÀßûÁOÎÌ*•KŸ$¥-6è`€Å0Ÿ2†¹ø8·!ê ±¹®iÈÍÍ-ïø÷Ï}ÖÓþÉ$ŸøôçϘ={ÎRétÁùƒÑ½û1ÙÉȹo˜¥Rê¥ZóˆÈ¬ÆÓ23H’¶¦;`þ#kæZ¡0†ø?#ÊgÂÈ`n((“É‚Yƒˆþ­Cýåž¾žZƒÜ5': Ëÿ}÷…笀Ë>üq\vÑûá‘,žðŸ¹ï{×ù¸åö».mniùPccc`ÛE*f’Á 'Šäq’WÊeaèèÿQ NVŽò0|9!"/rûŒzÍdÍa£q("€ÄPãX €Îb©ˆ¾ÞÞ+ßö¦×^péÅå—|‰àqómw^9kÎìóXëÚ=sè¸Å&—!g{/ÇB[‚$)ÈØ$HIDèï@ÆvA/‹Íî‹À¢ c1ña¶)QD¤R)d³9ççdf(¥ªW ¡A ñìC‘BGDZ¯¼ýͯ{)<†]²• <÷!yØžãÛlSŒôÖ"¶­ [m ÚûÈþÈ’øÆ`iÉÖ˜t*…cæ9I(ö!“É1B3âãþq÷›aõ€¤Å”!fG$ªõx*•S§¶ŒHÄ|.r¥äèÂXK±yãÆUo\}ÙEp €Çm_¸çÇÍS[žÌÄ$Îí·„&P,¸ÈTL¶®€µjZ݆\û‚fù/Ž5H%ììG®Š09vߨŽÌ‚¡5Çopv P*íï0†à¾¾Þ5ïxËë/q\tÙGN§O[u¿U%R 9Ò¯'Ižäsâ9>Õ6ÖêNÚ„­[wŒxÐH!I!Î%ñé…¡¾lrš2Y.fW"¢‘G fÍjGGgW䉯Œ½»w?ºR©ünõeB ¼xÜtÛkš2å”ÿÏgIk™–­»ìù“‹b8…`îœYøï†ÍÆU йlf$‚ŠƒŸO¦Yú‹p0P,"ÔŒ`º6K–,ÂŽ»ÆIÀýýÛÎ?ûÍË`àA€ÇÇ>õyAðÔÅ‹ÿˆö€ 0b$.-ôÉRÉŠ‘X~+èHv‰®MOi,`ÅòeøÙ/‹jK•´Ó)Ë粎†z(¥“F.’]|©…nôõ·cfãÑ<ïÙOÃÚõÆ‘£`=>û‡xñ%|Ï×ìoëÀ㺛ïØÓXhœÑñ§H ,qlÚÑ·Ž7š$ó£,\€ÌEQ¹£Gã‰O|<)lÚ²6m1-'‘›°ù\$…¨yC’¬wÑŸ¢[]Ò!¾7ÑðîEOo´f'ñ«ÂŠû­\Ç>úa(—+ÕáÕ;ÑÜ< šãÁ?fp¹\:ö®óÞÖxàñ‘O|öµsæÌ½ƒ#º‰í&: M™’“Œ8"]ˆZJ¶-›ñô§?=möîݽûö£³³k0NQÓ* yA~6¯’È$)b;©!.ô ‘Ëæ½íg`fØû”½Ùäwu÷€5"°™»ÐÜ<ímmXºl1¦Mk6žÍ-·Ü†Ö¶Y¦{£5@„q¡ãØÑ³/»è½×Á¯ð˜:µùÚ ˜ D‚ìL€+-½&@ ayTæRØ/`ä²y,Yº ÷|ñœrÊ©X¸h Z§OÇ¢E ÙöU…`ÿCUA8#NEÛE]óBr>ŒQ˜<¥iHóoªHQ‹ç$D‡CXÑÓšQ,–Ìg˜1£ ¹\ (U䪯ÅR ûË_±fÍœrêé(U íûŽ \hhø<€ë¼à[ÿ÷MŸÞþq PŒ".0Rß8ÖmàxÃ.0Š`ZÎbqÿùÏ¿qôÈѪ,Âi§†¶¶éhll@C!oûôvïÙ‹‡£··½=½èîíEJ¥@d÷ð³§øR͇T xƒ†~/¶}€™M$JS €yv ©t*FgW·éº€¥~9t‡î¯~îU1;©TÛvì4¢Á`Œ'„îž®ËW_üþ˼Üqá{?„Ï}ò#ô¹«oÒ™l†£˜š;`Æ(w¿Ÿƒg,NJ‚aËÌÑÜÓZš Ùúûp`ÿ¾jË¿…|K—,ÁƒNy fÏš…–ê=å ÀÁÃGqèÐQ¦R(—JÑAŸ Î1kh³n€#FË %,¸æ»G½ªA›²Ù zúP.•AŠRÓׯTPgÇêçâ1­\õ™{¸¯aõÇ>ýÙj@êB†èû ò&“ݕ爬‘ãO6` RfÒ ÌL?APœÒZ%Ù~Cêæ©MUhA¡± ©tåA (E)#¦Ååã Ù0¯&mmô#Ôqò›ºÚF‡ªÃièéêDOwúÁ:4ÓÛgÌDË´iÆÎçÍ…J©Œcv¤`¼@¢¿¯ÿú^þÁwxà>„·œ}Á {:õaxt× [ UÙ®xL #áÄîa!Ègó&Ø—Ëe¡R )R ‚!cW•€‡Æ‘ÃGÐÓÓ]Í;N.eD`p•^&;xåL+LѼ|½VÓf¡Q„â˜ðÀ¤+å*•2‚êņ¼ uSrùšš¦V¯& öÙш„ ÖŒR¥l-É>ãä‡Û¶niËòGo¾îJ/÷\ºú÷45My¹s*ì¾1 iБ”_l]v r,6€(à×Ph0ýïª w<B 1P,U_P y¡uX- Ì\s•ʨ³ G’›ÖxéG~^í_?^:ûLI„‹„9½}‚n‚ÇK]SÆCòl\n3I°¾5À€cË••Í“»14 Il,ÂVÄ B; ˆ ™ÍjÀPkx‹/í“\*•~ÿ¹O®~´÷&1ÞðÖsûªgU'ý¬-àIœð¿’—Ý%zŒá2Y$ÝeÏ#˜ aJ¥A>AXûjp`Az–Ïi­¿ø<&’˜~šYöñã¶ü|'-::Ž>²\*ÿáÎÛnð0Yñž^þï|>?(™ð£i&#Â%XòÛt&“¶ yÌ`Y=1m Ž{ƈ$ëD–év˜™}Rl$á¥}’ƒ+åòæk>÷ñ•Þ˜„xû¹ïB õ³ÚÛÚ¿;”Ï‹DÏÀMt·$k,ª·Õ·&‹vi¤Óʾ§8 @™"#&¶· ˆ-ØÏ¨µ µ$g>.Á&¿¡§»ó…Bá›×]ù)/“ ç¿ç¢Ù\vE=c¿€’Ø!’¬.W€êuâä&A|‘Y pM†ü*•ÈæA»&Ä‚xàš½‰DëÏV˜…ˆ›¤] #ìvý¥=Àa½ñêO·{`’áo¿àM-Í-7ËŽ $X-:ÊË Ä’ ç0¡.ô®£þ¶±â+ñ´ˆàËUІ”f™m$pŒÐŽt”#[{€Ä½µ À&°¸I5Ã?¬^šc±‡¨k€0@„þþÞ·}á–ënô‹&òùÜU•°Â²‹çtl+/ŽÒ¤#{¸¥²Q¾¤?Õûº@ˆãþdg ³{Ä@äƒã®=Õº ®þ|¬[Pó,ªm¹åñaÒFô†aÍŽÅ:æú&àt:s%€É"ÞxåëÞzÑ´i­«íYw°Ëþ`Ó0i×YAŠaöû£8A“ î%wŸ@¶ø$ß[¶êÑgWjÐ €¨Ž YÏ`ŒØ¹dcÄO ÷EÒ• d! ¦ŒA˜½½½—|å®[W{˜øÓ_þ¶÷÷kÖÏÙ¶}'zzzÌ,8ëJ+ÄÚprÇúÄD ÍH»ŽcGØ/ÖuPŠJ§Añgp,]“ÍÂŽ÷íã÷ ÜÓ¬a¦k=1ƒ~1˜õ…æÎž…'<öQOzÂc[}` “É–ßøÚW˜ÝsFØlÓÃÃÌkظyk“^r¹uv÷`ÇÎ è{õ¡v²‹è‘èH¬ñ7¶¨g’6ßäEu[Ï »'¿åòs¡æ½Å¶\5eîy Éó<f¸Aâ`‘„y qŸÉ:?@ÄäÔc{_|Z2‹{Àѳäýòä¨ öàÚÏ&b‘-ƒ£šÑÞÖŠsgm’€I°RDét D*ê?3%úú Jxû¦Ì6t“T-Ñ9+"ö~¤¶åæ•£2)$¸DC¦ísÝ›–ŠŒ¬‹A8‘$oàãä!01ÈÑ…`Ô’’ÔR,˜E¾ %)%i‚ìñ“j…š¡å„%û¾æ=*Ýä°Öö{šD ­9Ú] ê°ì`r wåç?÷¡'?å)Õ”žÓÐØ”«fù*ÊX¢)% K"XåK” ¤ŠH/ë‘HC8±QðPϰT¥Ò­ËV=hAûŒY³ Myé ƽ;,œð÷‡T_!â™'à¹fC¹Tèì8vxç¶M»z»;öØàGÖð0±‘0À*óLD! ŸË‰(eô˜•ð„i¸°6—bñ'©ƒØ9$à\>+ ê£:Çjpýuùè ‘†±#­^+ÑUŽ®"€nûlp@è`rˆ@.º²ùÓÑ•ƒÊ ÁDÿ}<Ø!ˆ @]•¸ ˆrÛötQwÃ@ßÔ4MŒ=ÏŸ¿àçÏ߈ x¯ËäïÁce¯_ßãtEΓ·ë¬.Ì9D6†ŒµD27ÓQ6Ž LX5Ý]ŽG`©¶è¯2zp?Sä.OOû/˜ çt¯ú@E#KªO:îß0üádÀf$Å’³s€²¹"[ª2Á -24i?Ï«‚ØYÕØ8 Ã@©óÿ_íJL‚WˆŒRç:ã!cŠžÐÕ#x@·?¨-fÎßß7ÐÞ÷]Ûp"¢¬Ü(`ýª€Eª# ­(Fà+dØ( ½6qGyÍçí,#L9àp90lƒ°ÁRàfeœ G—ÓÝà‘§Ü«7zúëïoGn Û:ø$èËŽ"a$eR?8Û%Í?VDõÕÁikΗ*§ß€¹ËÍåX"OœÕtHÀi  ïÁ,±‰KA«߀Ÿ_Á$̉aÌ{Š)¼ÄÙmà@èe[•3U8£Ô—RZQù9JÑP¾Ï/UŸÃ«'àî^-J$RjÓ‘(gvVÞj«ð RÇR½ºEUЉ³kÅÔÊ‚O²Àõœ 8ºç2Öï” 5P’†!¢+C.²žÄ§uŽ.R•}n«[ºåZۡÑ@ÎÐá™s"0”S«­äÇQ­ÏRÆùk=ŸPRÀ-X$„Û;@V§ìNxT &Ue×_*eÇq )Õ¹ÔÙ|½#1«\ó'+'â¸Ö4YjnVw‘µƒý7t‹*ÝÝá_ŸHô[o$˜vÁÖÎ(÷Ûòô*NglI9b²1%ê8Yg\{vÀÝÀñ¯÷j°« £çêqí-ÿ?¶ë4±“*hbÛN—n«Ø¶í*¶Q­mï»šÉ»ó½Ø«ïa¡ùô”‰ïUY†áˆÇ'±“¨•sÊ r¢=ª¦–Ïü ž®ÂIï·ºÙ¢u{صåbRƹäõzàózQSSƒÊÊJøIN9Cdd”°e.· e¥e(..Wø‰Úô,ä+dP BëòE#??[¸\p0u$ܟ̧ËåBEE…(SK(Ì' Û@rPÿ“s\’Pϸ|å ·lå:×5… 4p`½æRQϰl±EúIpv‡ŠfðèÑ3”äg{t0hš YQ¡ÊõðÛÛ¶cï$Æ'y<^÷PI–™#«–aÆôÀ˜Â¢ÂÞŠL¶ÍIcbbïÁœ öK·,K§e—³²²ëÌžQ‡Oœ9§©Ú0Ǻ=.– ¢¢’''ÆKªª@‘d(šŠ´Œ,î÷ù¤èè(”UT†‘™:aܨzÝ•ëÖ#<Ü×Öï{O§"¢¸˜($%%âÕÛP4 \Xr¦iÂçu£ºª ºaà¿ÔTWÿ_RR–¶}SÊ¿ßK׳AoÄ8œî1sö8¬Ø +Ü¥,ZÊFº{‰¿’ðx_&¿ÿ¡N^3³ õY€œ3i’!ùB¶¶:ßÂÂl¡w~Q–EQœìËi8«àˆºª®7[ 3ßÛ;À–´#êÚƒôÃõNá$IÂ$N! _Œ‘<ÏÙÜÞewkƒªª 1òÀö·‡G|þò “–÷¦÷/‡d<ö„º®•öåî󝡸ôáø²†mãr‹A‹ò;*"ª"*6·cäëLú×v)«"6‰Üy|ŸW/^&ê9Z~ºSêmù™ä›»X2ГŽ[‰ª(¸zë 4ÍXâóV6>ø„/\BÈ»%Çf¨iÚTðáê]ªÅeœÐXÙæGWÎw€3 ´²ø0¥ÃŠ–ÜÈq¨¶¹TÝÝ—Þ_îÛ&c·Hì¶¶9»\©¶ä±€©ÊQ ²84BÔêØÀ0Rb(­jÚ:Àƒ˜’ÏÞF-g È:Ë´ì ΠHžÄ ©:°T7…à±ÎUA ýl¿fWÛÎ^¢·Ää™à¹ýÐç/”ß}†¾Ìóž‡ä`&ëØ²Â€ü,rÀ ²p€K6…ÇKå%[ZvÛ€Ëun^VÀµ9:ÁÀþTh€ {mc}€CÔ÷‘Ö6jv–ü¾3ÿ Fu7ö±$½]€§+šï* Ÿz«@s»–ÙÔÒFÆX• «p2ð9yæÿuço»Ü`—[ÖÀk?IðXÛ;ê"±,€U¯’b" ÿ'—q¬˜–}’XuÝpÃîëÁU¶:»ü®×äâèªT¬Gıd …ØÒÏ1y.ÏÆLY„¿®Ž0ü¹H~¨ÙzÿÛ r<Å'›ÝvýþO°·iím<¡ï’½%ÌÈ.âP–sþ¨À-½ Žˆ¬‚õ g…<€é*Ƚ«Øí\?<žÄOàÚ;©Ì€iÍoÈD<Úµ‚ ¯É2ò~ÿÐ¥™ª“ç|î3”Ââ°ëàöŸÌjÄSõVë º#vµ~bõq¢º\uÐôÀ Òé}Vß'Óóòš;àQåw`\1>~.âp¯ï¨:„uc‘Ï9À}fšQx:qU@É‘|ùjõœ°!…­‚K˜Ú&Á üõç |øSíRÒÊ9&²(©zZ)+ÅyçûIl†´ ¼€W7¢]ý8`žäG‘ °¯¶°ínHòW›½…êÁp <:¢ü}ÙÂimtW{®ž®mf÷Œ=`£TY'Ã÷ˆq´Å<Æ5}Zu‚ “*Õ'¬gÀJ€é½zßÚ¨B¼¢*åS}V »ûžv;Ö¨Ðr»óš) d]¿±öˆ®v‘P7s¯\$p+;KÊ—ƒ,ÁR1ù?Ã&GÉ:œ”ú”êygÙ±a:[WË2ùzê¢:‘Ÿ-ÔêÙZk±‹Ôÿ>Ȉ¡ L lè ©OZ*µïêˆc7¯õÛu=ïÙÅJ\vµÚÛT˜²H ”òý"÷<'x|·ŠQ¾‡ìRoë|ªV Œ6ÛsbŸ@ÐÀ¼£R|ùÏ¢­;xØ"P–øZ+mr³ÝßxF5QÂÆ%«ã±¬vŸ¼OËî÷×À8÷­©ÞІì–ë··ÑšÄEªÈ2&â1aÕë·‹ -1°ïDDW¾¯“ñ¸|ß tÎN]Օ̺ù&\6kjGnQ÷0ß[NQÞ?Whi#I806K/Fà±W˜{š’çvª³©âò¿¾u—rj• Ï'ß2"Ômj"ÞÁÆP&mÁðp"ØÀË*ªªž›€ÄÙÙÞg•„¡iЫȅ-4¢ø•€IqX ½Xìãó„4݆žÝǘ“¼~#Õ'X×ßhch ¨~¢O}èíÛ]¨ß:ÃxüN ŒU† Ÿ?xÌçô69I—&H°` i®kêš”kmÈ××éF4|jl:Ìé°ûߺ"0²,a©|e%`pðÜ×+ó„HÊûÆ'£%øÖ ¦yS„ª"̇^›Ï¦~#ÀstÐpùo®‡9Þׄ6`3ÀàÛâÙÚ‚‹ãs¢4-;ôÿg=áZ¿Þõnv¾üúf/T€ÇvÃ_ÿÿøOyÖ$Í…¿iÌz+gÅ¶Ê ËÛ¶m›¥¤ŒØ¶­rl-~ãîÖ;èéÌtOæîùÛzc¼·ï›îxž õ`œ©º¦irÄq,_± ¶mA†ÊF³ãŸÛž@:™#l0ÆÀÃ`i(ü äuP#<>Ù±‘5gÃ÷Ž6@„µ+“ëŒÊI58ç0c¦¿6a ‚%@y2¸,ªPÍMu,–0ÑÝݣ“¶¶v 9tÄ2(U*úÕsF˜KL¥ðhƒä˜c„£¼®q¥ôž("Æ((&Q¢ËäŽëê,zÄøyK2cJK5ðÿ¢Ïp/¦g}®¼ð¢K¥}¸èâKeplzÓ€wÞyWMŒ|qÕ×Aµáz=;qΰçž{h1¦–ã©}½õz·ƒ×ßþ1y`€ðÔ(¦óbQ®1/(ôâ+onÚ´?BA)5ÑÙ]³V0€e¸Z‚‰·ßÿSá½?ÛÛóÄ%ÿ]׆mÙ°l M«éo[`j¡F¥Z½¡CF$¬fåjm‚2«V¯îÙvûWpÄÓ@¡[îzRº«€DÝ…L:ƒ”O ÛjbÅêA„±§ ú\ႨŒÊC,Æ‘L&1<<¬£Õ±BˆgïºåºƒZî+®¹i‡R¥ú$)!PV‡â&c:zÕ1¿â¹ò€’ŽîÐêêcô³7ÛxîºìÂ\KçŽ=¤k°ì€™œR0FAƒu(4ܸO5÷£ÂXØ Â…ŒBÅUÚ0¡¼ä:®2ΪW¶¼ ȵšB)_vô¥-4|ª)þþØ”ÝaÇ—’/_úRÇbÀœÜ\'»†2ïIEND®B`‚ddcui-0.3.0/icons/video-display-64px.png000066400000000000000000000065711427175135000200110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYsnºnºÖÞ±tIMEÜ 0S^Ѳ IDATxÚì”U–;Do4<~¦µx^‡iAãe˜éß›0337•§FY$Ÿ¡Ï˜éNPveF”$0Äp€¬Ú£Ÿ5XJ¾(Ê3þõ7yžÊ̺òžïñï~žŒÇ#F£eYÛ²ö»x<â¿þâ¯é”ÅbÉd2®kÖׯã1?}äÆõ›äy‰™Kú'þ¡âí›—Ìf?Îg7@ÿþwÕü'Rl 2zƒžõ0¶qQ‘pYRÖÖÉ5¶¬O™”EQ×.NÉt2åâå+Ìgs,d`7ŸgCXF1žÆÓ'÷lC>Æüë'N\¸Ë¨,‚— ä ;뤅 X:˜BŠnaãšÅ²âÖ©ãŒþü—Çî x¤°¸–)@Xb)a¬‡Žœ€ ü×~lä"x¾÷-¨Ý5–ù3ü³¨„™†ddÉ+KfñT8õê ÐUyתOºIbn›³b>–yŒçŒ,ÌY¡Î©i&pwVApAÆý¾þ‘›”´õêÕd·'€añÍTB&@ÉnWGÜaÊßÑÉ|ç[;Œ‚Å%ÑÞ(!¨.Ed˜D1_Ì¢h[£{ÖEø°fíD'‚UHÕ¬'DÖÓ;‹VŸQ[ ­Ç² ±âžUŒ&3«üùj„oecxP'F–£²ôù„Âjû4”ìdm#ùŒ°†:Rô¥¬; ‚ŒÜ×qq²öv–¢AbY9W³!Áà"8I/êbÓyå#‚ý¢Ä tÙmålò^ÛÿÿÔvo3±Xœ$Bªsã8›Ä”HJ²£ô¾ó>ôå‘}o Ïh׺ˡ+ÿ°$#­ƒ¦ÃÃ'$±ýýÉŠ]ÿ_û§Ù1@ãõ½è¯'ÙÕËîJ ÎéÁN}ð­å`Œ×{fV`+$ôÔxÆ’F—ÅŸ ì퀭Öîy≜åÏì땺’åCà‹Ýg@ÐôÕ0¤k»²fµþý\ã¬-•À;ËYúD0ÀóÄ­|Úë¯0·Ô7Ï©Þe¼vÞ—€JX3`MjÀh ˆ¬ &cÔg½‚Á¬$AS,["ûÎìÙÕHdÏ¿ât°ËR>2=éÏxðÏàÎês:[+õ®ö¸K}_°f‚ëÃ2r…ÄäÏxdr§×4¦õúG/}³BÎQ¢g0ú½£¤òV¼#µcD Óm6„[Kº—óG°½%1Z+‘zt|e|À»uØóï ;Q4¦>™ÜXÅb-·ƒ{+Pw` ‚ÀbeWR:—%#¤·”0W–¹­,©ÕUÆÚ$PÓ£è– ü¦úëï’ ›Ú:s²Ãºk£ï2Á Øí*«Îm‰ÿs|’$‹ZšÔ2ñÚ÷'µØ+ Pe´4,&p{<¿þ€HÆ{Fe¼Áå@:Ãx_2ñÝUÀ]ѽÉËöÔ£EU}_…~%*ëá’ÁÀ"û0Íþþˉ½[³YÒþ>–+½CÛ âìHûI÷oÚ£[ÿs›¦`Î~^"îFg×k~.`-X¸±ÚbÎ5~]†a_OðQ£¯‹¨TCU¶û LjÎý‰g3Âkß3˜·ªÀJpÎ…Eµ-ùÌFe³²Kb˜ S‹(np͸Â\öxD#Ch sž“h*›§£Këž`[&C›÷«ÀlnØàzÆ×÷,%€0K°~}bÔ™Þ ±÷óAtoÁ,Ÿ€\ìËÀu,Êt í7O‡gn0÷ÉvðvT(¤­Tº Tæ5øÈìöçÃdy Ƹ“|ã x,ÝíÍà$£~R=¥£p‘¬^½¨=×z±› lÖÿÙX3 \~®ÍDéÚ×~/ÂRe¤³Mºn Ù}Зº'µÌXFFûØÉ)®…ËZŽÆ$4¶fÙkp ÐÎ Ô-Nýi¾Ðd¶ÏXäAÇ‚À³Y{þ”óîP2û!ùiìõ ¼ÞÙùYŽÉF*hõÛ×N“þy’¾ªÝbXeò Xa”9çn½ÇëîH“)ªPèçÈ\Aÿ³;Aô,^m+ßß¡{©-)¿Ú¨¬×ëò£¬{°"p0í ˜?2Ù}¼Êiuê\±´&Ôa§ÍX¹¿ƒ·Ë Î&ÅbV÷÷w–»À%Ó³ÿ¥•åú½U›}¨j…WH÷ñ1ßC"£†ww§²Ö±œí¬€ð<ƒ*ÖîÝe€o‡GZà³ÜU‡·VS³Í1þö&¶{RÚRº”$?ú BY®ø Nw–ÝŠæ<¶ ¶ùÍ›÷¯ÄRA+éïü€×``ÊœˆcÍqáÙÎ忟Yi¢ãèdG«L‹¦+3ØC'&LÁka÷ªÑ+À‘…èæ…Ù¹ïožQ^ß}l2À2Éíº~jÓkò6xÒ;Tä‚JÀ­ÍN§)U Ö&~cß"H´?i„xãëùJK ×g.‘M޼"K"c}íy’3#Mï¹g<tõ×xþ­3Û'˜æx›_ýæöIâÝFè¿íZ°49þ’ÌšgÛe]™gųmÛ¶mÛ.ÛgÛ¾ÝÉîÎìNrI2¿ùæþ®ê÷%ýv7IGÝ®Ô!Ü @vz¦ÑÏIš‹§Â˜òh4Â/¿þ꜡•;Ø2$ÏŽÄéjHMgîüg”Íš§CþIÜE—gó=Î —ó·hÙ“š™½cj¡1ˆ’îy6žGeV.ãßúà•væªf£Tq„ñ“ûJ+¯Œn§‹^¿z­†(š…Vðþ{ïd¡1í6榵+Ç·V>¾ gqáÁâ±ÍLb¦ú A0ܸÙêÀ‚4Ç3(hv¸a3ã†s OfðÒ÷†!„àñvIΆɩ”X¿üú³í'%Eýøã”EQ¼½Ò$47ìV@Z&ä®ìä<é7¡erÊzýfÛ¸À‹‹-O1F¸¬Î*+>O°`:é¤S´Åõ6Øî¿7µû÷èO>þ–.»ì’BûT¸^{ý mmŒ?{¾þ«'©ýN»¡»í&³[n‹Í7+´O & N6·ÓfË,ÕbûÅ· §úZ¾ çd6ù|Œý÷P­–¹àtËf09ñ…‘M‹Üâ]÷>ˆù¥;ï}pE_JÈÁRö°õ¾a‹½¾ÇŸxjyÌ'ÝrÇ=ÿŒCðù—^¿ÅØçïb¢Ô©1!FÁƒÁP ÎÙîóiPEdœ‹ì‰|N4ïÚs×öŸV\uÝ-hušk,Ý]êËìÁnP:ñ奔‚dÆlÎ,4Bž¼6[Çp4Š=Q¡Þh`2™`NÔëõ×öýþ§xLñ pËú¡ç…ð¶e1Ø%2Ò`Z äpŒo¿ûB£‘7m“rüj<2Šj¶šØp½µðîŸÌ­‹Z+õòч°í´¬€SϺ­Vk­v»ý9ò³ÏgMT.yž™É®¿.~øé|÷ÃO±™šD“'QDY%J)ÚcóÙn«_i©Ì‰(ÁRÖéKÿó«/=¿øpÁ¥W¿(„Ø:™z8W-çÿÇq¹j¥B>Æp ‡v“ýϹõ.=ƒ¡‘Y9mŸywP¥½rÉy§oSè Øïà£Ñl4×n´Ÿ¹Ù'tAUPq&wZÓ•g ,(¢Uìù Û-`j$Ÿw÷¨M{¸®+}ùÙƒwßRÜ 8ê„Óó}¹c<7ýI;ån÷Ä•º¬´%”JdH ãÙã4—Y{È2à3­‚Z­öäÝ·^»{¡[àƒ>{õO)·¨–Ë´„…à) B’{$7ì Ú÷ÄÌâŒÉSšbŠ0RÊpe1RtFD•Ô'ˆ#â c…eºo­¹úª›¦€8zìI·‚áºa1—ßÒótœ(™ðÀð¯Zëˆ-¨)½„–ÐúÁ$ÃÏ(0Ô"IEND®B`‚ddcui-0.3.0/man/000077500000000000000000000000001427175135000133625ustar00rootroot00000000000000ddcui-0.3.0/man/ddcui.1000066400000000000000000000105431427175135000145370ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH ddcui 1 "13 June 2020" .\" Please adjust this date whenever revising the manpage. .\" .SH NAME ddcui \- GUI for ddcutil .SH SYNOPSIS \fBddcui\fP [\fIoptions\fP] .\" ALT USING .SY .OP .\" .SY .\" .OP \-abcde .\" .OP \-b busno .\" .OP \-d|--display dispno .\" command command-arguments .\" .YS .SH DESCRIPTION \fBddcui\fP provides a graphical user interface to a monitor's Virtual Control Panel (VCP). It uses the DDC/CI protocol on an I2C bus connected to the monitor. Normally, the video driver for the monitor exposes one or more I2C buses as devices named /dev/i2c-n. Virtual Control Panel features are defined in the Monitor Control Command Set (MCCS). Monitors implement some subset of these features. Each feature is identified using a single byte. For example, feature x10 is the brightness control. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. .\" .B ddcutil .\" .I command .\" .R [ .\" .I command-arguments .\" .R ] [ .\" .I options .\" .R ] .SH OPTIONS .PP .SS Options that change initial settings for the \fIFeature Selection\fP dialog: .PP .TQ .BI "--feature-set " "name" Initial feature set to show. The most important are \fIMCCS\fP - all features defined in MCCS, \fIMANUFACTURER\fP - features in the manufacturer reserved range xe0..xff, \fICOLOR\fP - color related features. For a complete list, use the \fB--help\fP option. Unless \fB--custom-feature-set\fP is specified, the default is \fIMCCS\fP. .TQ .BI "--custom-feature-set " "(feature code..)" Explicitly specify the features to be shown. Features in the feature code list are specified as 2 byte hex numbers, with or without leading "x" or trailing "h". To specify more than one feature, separate the feature codes by commas or blanks, and enclose the entire list in quotation marks. For example: .EX --custom-feature-set "10 x12 14h" .EE .TQ .B "--only-capabilities" Restrict features to those in the capabilities string. Applies when the feature set is \fIMCCS\fP, \fICOLOR\fP, or \fIMANUFACTURER\fP. .TQ .B "--all-capabilities" Always include features found in the capabilities string. Applies when the feature set is \fIMCCS\fP. .TQ .B "--show-unsupported" Display unsupported features in the feature set. Normally unsupported features are not shown. .PP .SS Option that changes initial settings for the \fINC Values Source\fP dialog. .TQ .BI "--nc-values-source " "MCCS|CAPABILITIES|BOTH" Source of values shown in the drop down menu for simple Non-Continuous features. .TQ .B "--use-latest-nc-values" Always use values from latest MCCS version .SS Option for initial display selection: .PP .TQ .BI "--model " "model-name" Model name as specified in the monitor's EDID and shown on the toolbar. .SS Miscellaneous options: .TQ .B "--styles" List available Qt styles .TQ .BI "--style " "style-name" Select the Qt style to use .TQ .B "--version, -v" Report version information .TQ .B "--help" Get command line help. .PP .SS Options that are passed to the \fBddcutil\fP shared library. These correspond to \fBddcutil\fP command line options of the same name. .TQ .B "--ddc" Report DDC protocol and data errors to the terminal. .TQ .BI "--trace " "trace-group-name" Trace all functions in a trace group. May be specified more than once. .TQ .BI "--trcfile " "simple-file-name" Trace all traceable functions in a file. May be specified more than once. .TQ .BI "--trcfunc " "function name" Trace a single function. May be specified more than once. .TQ .B "--timestamp | --ts" Prefix trace messages with timestamp .TQ .B "--thread-id | --tid" Prefix trace messages with thread id .SH STATUS CODES Normally returns 0, returns 1 if failure. Using the \fB--help\fP option is regarded as success. .SH SEE_ALSO ddcutil(1) .PP The project homepage: .UR http://www.ddcutil.com .UE .TQ General \fBddcui\fP documentation: .UR http://www.ddcutil.com/ddcui_main .UE .TQ For detailed documentation of the command line options: .UR http:\\www.ddcutil.com/ddcui_options .UE .SH AUTHOR Sanford Rockowitz (rockowitz at minsoft dot com) .br Copyright 2019\-2020 Sanford Rockowitz ddcui-0.3.0/qconfig.h.in000066400000000000000000000005601427175135000150140ustar00rootroot00000000000000#ifndef DDCUI_QCONFIG_H #define DDCUI_QCONFIG_H // config.h template file, QMake version #define APPLY_CANCEL_FLAG "$$APPLY_CANCEL_FLAG" #if defined(APPLY_CANCEL_FLAG) && (APPLY_CANCEL_FLAG == 1) #define APPLY_CANCEL #endif #ifdef VERBOSE #ifdef APPLY_CANCEL #warning "APPLY_CANCEL IS defined" #else #warning "APPLY_CANCEL is NOT defined" #endif #endif #endifddcui-0.3.0/screenshots/000077500000000000000000000000001427175135000151475ustar00rootroot00000000000000ddcui-0.3.0/screenshots/ddcui_capabilities.png000066400000000000000000003120611427175135000214610ustar00rootroot00000000000000‰PNG  IHDRjÁ¦åÅÅsBITÛáOàtEXtSoftwareShutterc‚Ð IDATxÚìw\ÇÛÀgïîh'xô& * *U‚ˆ‚ш{×Ä‚!ÆäUc‰=FÍ/DQÑD%vcE,* "ˆ ‚ôÞ¹^wß?V7çGQ“˜<ß?ø,³;³óh û”YóqW¹ž((ª(*­­mà×6êš„µ ¢ÚQ=OTÛ ¬iàW×ñ«ky5Mb‘ÈÈ@! zt¼*+örJæóz¦½%G«cgÛU~Ýó¸K2žÕ0l­ºhÿ[”ö÷ õAëó_Ùàƒ3ü‹œš2ë3¦ŽN›Óèt“ëW.:õrfê°þöìÚÚL#N—ôä{Œ×£ŠëW»ø ­P©g £«Ï¢këÈäM›AÓ¢áJr£ ¡Äq¥s6äÿß4cDׂÞzœWgÝxn8!L—¨M¿œür°g7]¬gÛi.ÜÌ`ú}¦G4d^½—ëçÓ]¯o{„´¾4/§¤¢†/’ ]}S[Çn66@”)¤•á +Ÿa¬h°4 Eóï^}V‡#„tìüÜÌÈiNZ’t;­LN D·pîgÙ‰y«…[ëV¾,-"o(yþ¤ ¼N(Ub m&ËÀÐØÞÑÕ¶­–k®Õ7SÞQgà-Á0BH—ÅngÐ ×ÌâU.‚øÛ³S¼2UÓp‚Ë ¡D1ä4]œFS(’‰¤ ¥W!¥’ p£Ó¤zJŽÓéР“¨ŽG¢Y‰æ³½êT Êú'Òª ì{öòö0`3i ±ˆ_[Y”Côt´í„©¬H¹Pi=6Ì›®,IŒKECZ²º‚À0¬3B‚ĻÒ>ãÂŒi’‚;·¢ú›á%wkƒÂýµBʲGW‰ NYoÜZYžr¡ª-Y4¶~31å•OŸbv.î&zL¡JD¼¦Ú’¼'ÈA“Ù\«æUj)ºoßxæ# kaŠoG.¢¥ì—þ8ÑZ–ÐO>m3;YNïë>ÐÂʦ¼´8ãQŠÇØkÐ`¬¥»«›ª2àJ¥P„Ëd„H d,}zS O*SâJœ¦MÇ „+q: WHM<‚ p{n CFƒ¤*7#½¨Z„t uq-CÕ‡:Ah>‹paMÞÓ—%•MB9bè°»» p2B™±‰%2ZW·Ð¶L„¿ú×Ô}¤Ç ›û×OfˆÎõÒ‹up´âüçËzø™³h!D(q-¶¾ [-{p»€oÅ1&ø•/²^–VóÅ L[ÏÈÌÁ±—‡‰!¼.ûæ­—ŒãØß\’WPÑ(£˜:õwµC58fýª|E齫¦}†: o½`§þf¢Ü‚Š&-‡Á~=94\ÐBáZ„º‰ý†•­jfc:VÝMžgW‰ÙÒ<‘E?s-µŒŠVÞ¾‹“ª>{*3ršÉ2ÌßšÑV±jbþiAJÊÒÒñ^CÝ,™B„RA0tØFºl=IÙ•³ !\Põ"ëeIO¬À˜ÆV={ö´Ö£55Óª± g½Y7×Á6¥7T:ƒ²¶19 „iUÞãÇ…ÕBÄêjÝËZþ$µXL3îû±§½.†ü’'ÏsK„Rœ¦¥­£ghÞÛµ—9œ™Ðh­¹ç®]¹¢Åì#TÌDŠËœ Ú‘ýò'0,)áF}}myY‰ÿá:ººîÞò4¸yöæÞÇ?SJE“@*($˜‚mn o6Ô „ôŒÙ ‚ ¤H©THÅ"¾Èg*”Jº˜ÐnÛQ\˜ö ”ãâèÅÆDÕ…O‹Tž¹..xÔúYBY—“øP`æÜÓÇÝ­)Ä‚º¼œ”‡x£Ô"d‚›6Qv!…èÃÌ.1 ™à¦MT¥ž»ý\ß.hü =¢!ójòK¶W‡Ö+ ~á£bc·`s )y¥™ÉÏ ëdˆ¡­Çµ°ã[1”ÕO“Ë,]]ý= t„ŒßP‘—“˜háÕKøà‰¹Nš\nØßÏ£­hªÌN½{]ií?ÖɈ†¢[û…Z#„Wd\Ídôi˜Ñð<¹Üb ¿‡¡âåÍÄg6]j^Ê[*œ@j65ñ¦UHiGZæ¶–³r³å4{Oc:Žã4íÕeŠê§ÉªüÔg¶FÅæ¯õ™pƒÖ‚,±7Ê´p¦•ÆbUÅ|Þׯ7çU£(kªê9–žL Ék2âæ p„,ã®æ\#'KFÊÚì»ébKgÿºZ„´©¶øYzB™!Æ7P¯IM%ߨÌPMÏYTå“óäœâ¼–Å|Þg€=ÿñ½Ž‹_ —&ª.zZ¬8¡DQà×SžöLdÓÓË…£Ç¤ár©XÀ«ÈÍzN8ƒ íò#¾6à:æ}¤‘s]û³«^ÐZvƒ0ŒÅbùú¥ÜOðõb±X"‘¨©±¾Åìͽ&)xS£¤©^¤ÃÖ©oK„R…LnЕ-W*y2‰@® åb¡B)kÒ—+8,@ ²”\½~Cºj!B.F¶ýûÓiØ«ˆ 5%$)©âmXÂeBžéêqŸ‰1&51 3 jau'¨ms4íÍB^i9aݯ !Bø2%‹gãûq€.¦ðk*Ê$ÆN¦¼‰Š^C<,u0B&â hz†]í=ºpžÞO~©K „¢9yê 륎DzO^m²”ß duakc„LÀÊ\¨x]CÇF„\,“ã4š²"W餱pÔ|úRYã'dU¥ü®6ÆööØíl=×ázHZUÞÀµ2#ãÒÒñŽUÞƒwó^Î|½L`ÚLy3Yp$Óí=ÌMc±*bÒiªõ'h4 Ç „©g¤§#âɵuuµ‘BÛ¸§•>!.OI“:ö·f!¯®ª^‹cjæäÃÑ{p÷1CK½&‰„&ÔmQÏèÍ5³æbÞ\‰±Ý^õC fhÛ߃FõCqÁÓjnŸ@G#Lʯ)L]}£®\öó´&yOs&ŒqhÓØ©Åk #‡`‹Ù/¿¹„ýÊ©rAkÙ]ûõOJ¸AZþÁ4 ‰DI 7\ûõo1»ºù(“I©$‘XÜP[/jÒè&UyN0´i¸L¢TbbTÒÈ'äbC‰c ¾žP(jsã7¯FkÓËbÌÎÓD ²ªôØ´ ;ÀßË^—t– K4Íϓ٠°faHÑð,þA®D‹¡ÀulÝ-ªÒë(W®Tà­˜V„B&“I1BQ“yÿqùéXšAÝõé*[wšÅl[6 !$¯¯i2¶HWHeÑtºX: ¢>û¥Ân …FH+Ób•Ë1g?ÿ^úFŽF—žVë‘ËîDCVbb®³pîmÆ02æH§ÇËÜÃû[ÑñªÇ‰éul¶¡Îë€ALR”zûa=ÒÒ5ábZf=Ú*¼%¡dJ‚rôU˜[ÙÛš‰´-YHœ[XÁìjEžV+¼;\yEiÅŸÃÌNšÿ¼¯Š,:Z2fÛÅþ)¦åw]ùŸÓ¯¡¹9¯àeƒyOŽƒÏ — kÊKóòžåöëRš'³`ÅÂð† qÙJL¯—ß°~‹Þ6ÙwÊÇKÜTµÊÑWÖökYÏ!B!ÿSQêbÊ š]^÷Ç%R-nÿAT?”òĺ6l"x7*i¢iuqpécM—Ke0È M?âëåc©TÜþë1ŒFšj­eJÄÇ^R½@sö.&&¦¦æ)÷HÛ'ˆ”û ¦¦æ]LLZÌ®n>ªº(%2¯®^“2Žã‘9®T*eRDàt¦EÃ1$ÖgÈärøÞ8´…€§Ð·`aáu•Ìî¾½ëï—Ô)ì­´Bˆ ú6­žó†6l !¼¦(Ÿè6(ÐJ› J]qí¾7¢5ÇœÚHÇk3”Y í«!„Þ™’×Û³;k–—xY%»œ×¤4´`cáµ,G?'þýœjQO}=†¾¡ž¢êÕMøe„uoóòr‘Œ@ ÄÐbÐuþô‚ÑŒ{yôÑÉOÊ!o ,Íkäzùõ2’•¦>¤sÚ*¼¡ÞüG^_(¶r²rëGÓÂùyy Jç×—É‘!§•SŸºCZ½Š,}LJòÛ,öO1 Ñ0Õ*Ó <Í'&$YX[[˜°õ»X:u1·(Hº•-a)H…cÇ ñŽVCÏ@_QNÐÞÐj_níã꺖õ¬Ö¾ÍŤÓõ Y¤å:޾½ëï×Êí­É}RLŽ^]M½ÌÞÔ §ßÈî2¿©®²¼  ”gÕ[Ð?âëÇJ¥!t;îjkW Žb0h!ŒFÊæÙ)Ôþ¥R4g¯®¬¨ª¬ðý(ˆ´i6ÐÛ?éÎ }C®™yóìÍÌG•ï>ŠEGû.&F2†–F£a4W⸜À :ƒŽa4œÀq‚P(•]8,‘XB¼ñÍHZ÷>þ9Vp§ÓDG8¹ZIš>šÎ¢7œÀÉÍ4½Œa¡TÈqúŸKÞoÞ^u´8ÑÒR6NP®<¶Ž€'Ä‘!M« ×ðia±ˆc£‹)¤‚úªJ©>‹xÓ¸Äjá#°¸RI§c{e#aê&-Aà”ùDÈ¥2¦Ž.“h,¼¹Pˆx3œ¦éeqcž-¤¨*,FÍŒ§ŽV^íÖj²í©¶ª˜ˆÀÕv $§‹®¼±8«$³AÊìÖÏßÃŒ©gf¡—[,Eúdµxy¥B•|Rº•>½ø #oV7üÍ7}•ѶÄ|³†t³^=r2’êílL8zú†]m8]-8Oâ3Êôû[ê@ð#´e>¾Þ-‡¿6øZÛûòꆙKã-f'in†¶'û‹çYƒCÈxÇ”û ½ýY,–ïGAwoÆštå6Ï®n>ªÄ?!¦Ö¤1.Z N§3Lm­¼—…啈 ºv5éÝËQ"•) ¥R)“Ëtu´T󠌭G/o–z§ §1'ý©’åà¤ýÚÔÓfÓy­ŸeêÑë…„…>kc%'Þ.e(”L+'=‚¦P(bbºzº/ž1Lúw¡·liáþçãÝØÅeÅŸM–“1=útÐE*ö*Ë´+Ê(­ïehÂ`wèÂON¿ýTJ0˜z\+;^ I„„…>ÍÄÌL˜~ï!¦çÜ]CHÎo00½V<‚èÕv„0«yþ艻Y%il}zy; S¨7Í1/-¨êÎ1Ã+ò*i,Õ©ãu®òo¾ `HU–'26FtªÚ¯ŠŸÖ³l¸âÒ¢Ú¦F± §1ø«—ÓfÑš„„…>F“V=Ïidhc ¹‚¦oaa ¥§Ã@bU­fŠM߬[s=­ºp‘’ß$$,õ1c3SQÚ½t-î€>¯c”¥PBÓgÊ_<«,$” ÌÒ=ÄÏRËȀͯ(Í™4æÐƃàõæ•æþÂ݇T.ÒÜj1{‹h{²+ ¥R!‰’îÄ›p“îÄù~4TGWÇШK‹Ù›{ÿœ:ºp8þ~>ªÉdH_ß„ž˹w¯æoàР]°-Ì™EuŽÎ&,›C˜UfW }ê,ÓÔ\‘ÓêYm zVNI7Vç¡CìxB‡­[›q9‡ÎÔÕÉìÙLýþ~&bm#NË> ‚@oú¤0޳O s‹î3Ò~´ìÅMOÔÅ·¿9ËÀÊ}¨•Ž“!ÔâÜ/´»êä–;¸Yê˜÷ÿØ'¦éêвñÅËzŽ>]ÞšûЦÍ 2¢™¹ûð%‚â§é|µJ"¶µ5ö¨½…« õ¦»{oƳ›ïcFÝûØHÓ©º]Pg*¯fëèê¨Éòìq~gªýê=^.ª ðp¶vt&…È(wBPU!êbå®_”ž[ÖÍÍJÏÎg¸aM½”¦«gh¤§UõøÊS¥©ZMJržÒešõܪ‹ÓÖöpíÊ4ë?"P(gèjÓˆ×nIiùó:¯àQ¯Q ’:Æ&Ú)y|¡.[Ðýw¹•o7ªp4ŒFޝw›ÝË/ !>–N§wëîdÜ•«§§ŸÕˆcÜÇ­¿X,jž½™ùø¦Q)‘H„B‘\.C56ñêj Œ0„›ž={Æá!„ -K—ÅbAW€v£kábù4-ñE_w;®¡‰‰²<;SØ«ŸÕ«Ä:Ï2º:÷<¾•ÂwîncfÄ6`+Ä‚ê:¹¡¡y7ÓÒgÉùºî¶ÆººÌÆÒôtf_7Kí¼eDG× Xö}»çeܹQÕ­§×€üZ¿¦¢°LËÖÆ’«,~|3ïê`cj¨¯Ëx5Ź/rêM\íÅ™oxéT§N[ݲŒÉÂÍÍôt˜LºB*jª*Ëͪ`»ºéÐô{ ÝLå¹t·13äZ ¹D,¬,¬,–›YZY`’goÔDjiÒ3¡îIUAÛÌ´1-1§¯‡=—Í@¼â‡%Ì~ý­˜Ç•4-Ã.Ú \ŽGß„ä→Òì¬FKggBá ÞÇ7–zjíJü ÿF¼r¾Ëìª%àJ%§‹±Ç@„PÀW«³Ú”…mßüÝ’ekêk«ß¸%Ž+Jr&ÆqœN§¿~ñ$”J%FÃ0 !ŒFà tè„´®øÅ‹Ê1¡m`bÃÅ‹r«¥˜Q_Kf›g!i(~YZU'(©khåàl«!BZS˜ý¢ªI†éqmey¹5r¬KOÿÞ¦ÂÂÔ‡¥"ÌÀÁ»µn'+,oª.)®ªmIä]›É2ìbnkefÀ@á¢Ú¢—eÕõB©c°ô-mºYhaˆhzã¾DcAJZ™øõ¿²ºÂ윪F±Gˆm××äöaK•lgáêˆËÒï4Ún»¨úañš'ÉϪ•4Gï¾\F§*o%S¿µš,ýôˆÎU›DƯ,«®­kŠe29ŽL=މµƒµ ë•Ç׿,­ªJˆ®ÍÔÕ74¶°°éª‹µT¹F=·.¦3—V¿xQT/UôL< êÁFü—·o6ÚzÙ3k óŠB©L¡Dt&›ÓÕ¦‡‰.„=@{àwý%úSf}ÖP_Ûžëå2Ùõ+ç,ü²¡®æoÏNšˆ‡öǼ2ëjª E„aaj±¿—-ÑÔ(cl#ŽV¤Ü{ªíØ×B4o¾!CKû×]?yù26éªùâºÚšIwg/ˆTÈe|^Óßž!DÄ¡ý1-ì¼þËæ#mDãU6H¬ M,´hJ™°¦¬4'·XiÓdž‰Cx#¼¼Æ¶¾ÁÌÏ"ÄìhÏõ3?‹JÄB>WŸs|å}¬®,‡ø 0áš½þ Õ6Àq¼¶ºòŸ“F£ýé}Ô70„¶ø JÄí¿¸¹‘ö7f'wÕ¼2ù¼FhK@4!Ä(¯¨ºxæ™4hÈpÐ  ÆÝøW?lS^QÅ@ Ÿ( BR™´¨4< !TVRx'á.üÀÐÀ|À|þÉæ£B¡àp8¹¹¹„Ì!!!ø ›íÃáÃê¼óQ.—;99}Nœ8ÑÑjoÞ¼ÙÐÐðèÑ£½zõb³Ù¾¾¾§NJII9}ú4y_WW×uëÖ…„„x{{/]º”tLŽ5ŠüëîîþÓO?©‰pîÜ9___kkk??¿ .‰ïOÍO:ÕÑѱgÏžK—.‰Dj´&#ÿBóÑÖÖvðàÁ¤Ù‡zþüyZZÚ´iÓÔ.Û¿TTÔ¾}û —/_>yòä’’##£¾}ûÞ¾}!tûömò8==Çq77·ŽÖûĉL&sôèÑãǧ–Ô…BaXX˜……EjjêË—/×­[Ç`0Ö¯_ïêêºjÕªG9rDµÆÆÆÑ£GûûûçääœÿÉ“'2™ŒËå:99u´Úuuuj‰555ä±¶¶ö‚ ȃ… =zTsG=ztPPƒÁ6lXhhèáÇ߫¡Ã‡;¨––F¦_½z!´zõj]]]‡³råÊ“'O6ÏÞQø€ÍÇáÇëêêž={V"‘œ}ú”\‰vrrêß¿?¹’[\\loo¯êÛÓLYY™­­-†aä¿öööåååäq—.]¨t@€ Ÿ7oÞªU«ìíí'L˜““ÓÑšWTT¨%VTT˜˜˜ÇFFFÚÚÚ䱩©imm­T*Õ,‚½½=õ¯½½}YYÙ{,ä® }úô¡š¾¦¦†jú9sæhkkóx<µì•€sû1Œ)S¦üöÛo4MKKkĈͯ±¶¶^±bŘ1cÔÒ½¼¼x<^LLÌÀµµµ|õêÕÔÔÔíÛ·w´Ò¤±8~üxò_Ò¶eË›ÂÂBÇi´7ÌbÊŠRÃÒÒ²¸¸˜ ò‚ÂÂÂæ®Á7lmmÑ¢E‹-jjjZ³fÍ‚ âãã;Tó   S§NEFFR6nIIIbbâ?þHþ[WWÇçóõõõBùùù&&&L&S&“µV ¥¥eQQõoaa¡¥¥å{!Äb±T¥¥¥E5½••µzN¡¶1¨Ea(À‡B‡¿û8}úô´´´-[¶›fš_ðÙgŸmܸ‘ j”H$III!&“éååµcÇÒݰgχãèèØ¡ 455;wîûï¿§¼_©©©zzzÇŽ>|8†a«V­âóù …"55U("„ÌÌÌòòòš"¢¢¢d2YnnnTTÔÔ©S5Ü:)))33S©T²ÙlCCÃö»9)–/_ÞÐÐ0}úôììl¡PxïÞ½qãÆyxxP¦0BhåÊ•‰¤¢¢bëÖ­'NDikks8œE˜4iÒüqëÖ-¥RyãÆK—.‘NÙ÷'‚†.•J7lØÀçó ‚(++‹mñÊæ2ð¯5mll\\\Ü|Ó Éœ9s¾øâ‹E‹ÙÙÙ¹ººFEEQΧ€€>ŸOš¾¾¾‰¤+×'NœÐÓÓ›>}:÷5–––³fÍ:xð ›Í¾páBAA›››ƒƒÃš5kÈ[/^¼øÚµkvvv#GŽT-ÊÈÈèìÙ³7nÜptt ?~|DD„†[WUUÍ›7ÏÎÎÎÉÉ)33sçέ¼¥¥e||¼¾¾~XX˜½½ý‚ >þøã3gÎPÑŸÝ»wwssóóó0`ÀŠ+Èô5kÖDFFÚÙÙmܸQµ@Ÿèèè+«j³” IDATVØÙÙ­^½z÷îÝžžžïU °Ùì‹/ 0ÀÖÖv̘1ÙÙÙÍ/kMF>°¯ÏßµK,"„¤29häoäÚµk_ýµê§‘@Fþ 0µµBe%…{vE·7ö‘Ãá´vª£_íÞ7­5´oO{ÍG°<>  ±xÐ@ÿ‚ƒƒÿõ«ºÿÌGóè8oÄ>6ÿA°³µiÙ|ìÞ½;hPC!—µl>â8Ú4±˜ÀûáÅk‚ þÝÒ¾|ùR Ô××CÃw”.]ºèëëwëÖ T`>þWxùò%AžžžÐê#+++??,Hóñ¿‚@ 8pà¿ÞÃúþpvvNII=˜òï6­`Íúèìoø£ië̃ètºêæc«øúúªÿq4-^+ µ€Åkø‚©kò>&''3 ÕƒvôË/¿t´Z·nݲ··ߦð6Àà “‹×ááál6›Íf÷îÝ{æÌ™>¤ÎFDD|ëÝ#GޤÓét:Íf;88L™2Eug1u–âÚµkdzDD„ZQÛ·oïÓ§†{•––ÒéôÇS)yyyt:=;;!tåÊ•p8CCC__߸¸8ê²Gùøø°X¬îÝ»ïß¿ŸJ_¹r¥»»»ŽŽN`` êNœ8áïïohháªüÕæ£B¡ —­©UæÍ›×ÔÔTRRröìY33³ÀÀÀ?þøƒ<5jÔ¨^½z}òÏŸ?_*•ÖÔÔ\¼xÑÜÜÜÏÏïÌ™3ÔÙÏ>ûL¨ÂСCßS5ºwï¾wïÞ/^äææN›6mÔ¨Q!7bĈ€€€ÊÊʨ¨¨ˆˆˆøøx*Ëúõë§OŸ®V‡ÃY¸pá–-[ sð>Ðû˜’’âãã£P(¨µÌt:]WW×ÉÉiÓ¦M|>ÿ«¯¾ £ÑhAAA&L˜3gNIIÉâÅ‹ÓÒÒ”J¥……ÅÁƒW¬X‘ŸŸ¯££STT$ çÎ;wî\êîäß½{÷ÆÄÄ”––3fíÚµÚÚÚصkWjj*y÷ââbWW×Çß¾}›Íf?¾òcÆ`0 FïÞ½·nÝÊãñ/^üÉ'ŸÐh4R@¿ ©c'''©TZXXhnnþÇ(•ÊuëÖ1Œ#F|òÉ'111C† A͘1!”˜˜¨VÔ°aÃB¤£´=ÔÖÖ&%%5O÷õõ511ižKØðS ~Ôä}ôññQ;ÐÀ„ ªªªÈ¥XŠuëÖ™™™ååå•––þþûï”9råÊ•Ï?ÿüÖ­[çÏŸß²eËõë×ÕJãr¹§Nª¬¬¼téÒÕ«W÷ìÙƒ?~|IIIrr2yÍ¡C‡ dooùòeÊ'÷–Lž<¹²²òÙ³g}«TTTXXXp8œ!C†„††’¿Ž“‘‘Ñ·o_*ð´ÿþ™™™ïö¾d£œ{*@Î/^«aii‰š}š›Éd–——¿xñ!Ô£GSSSÊõòòB™››Oš4éðáÃj¥=º[·n†õèÑãóÏ?¿}û6BˆÍfú駇Bá8~äÈ‘™3g"„NŸ>Ói[Ü¢šbee…ª««#Ïîß¿Ÿ«BUUU‹¹:´ïD-…:ær¹iiiIII«V­ Â0Œ ghhH]chhÈãñZ+¡ùíÚY±°°°Q£FQZ5jTXXl E:¹x­ºÐLRZZŠâp8ªvÒºuë¾ÿþû &ðùüQ£F­[·ÎÐÐ!dffF]fjjš˜˜¨jñ „®_¿UXXH„H$²µµ%ÓgΜ¼eË–¤¤$±XúnmR cccòßO?ýtíÚµÔÙ·qÈiii!„är9•"“ɨt„F333333[³fƒƒƒ½½ýˆ# ŠŠŠ¨,ï£æãùóçG¥jJ¶h‚ð€ÿ*«×ïlñúĉ¦¦¦={öTMäp8[¶lyòäÉ;w222¶nÝJ¦çççS×äç瓞KІ†† &,\¸ðÉ“'Ïž=[¾|9e²ôíÛ·gÏžgΜ9tèФI“´µµß­f~ÿýw333jߛͶR ˆì\.—ÍfçææR)/_¾d0666Í/ÆqûŒ Eééé999=}ú!täȲ’d:B¨´´ÔÌÌì]õX¼€ÿ$.^c_-ž¿-j—X$D)”¸êUT¸^󸽷áÛo¿­««#7SwŽ~ýúýßÿýßĉ;”+11ñý}¸ñ?B\\œŸŸèþk0è4„PYIáž]Ñš~вÕ GÍ»7x<Þ{­ýéÓ§Aç|ÀÛš’ε¶xý¾ D ôèÑÇñèèh&“ ð7›jamÞÞÞdH"uðNn¹aÃÔÙ:ò’"ðþ>@óæc«´¶x €ùøïGõ“æ@§uJ0ÿäßm]±ÙìçÏŸ“ŸÇT÷h ²c_&À|ü¯`ccS\\œ––ÖÐÐ ßQ8Žžžžµµ5¨À|üÑâ/4a]è€ùøàÁРÆGþƒZ6ýýýA;@3ˆ–ÍÇ“'O‚nUf̘! [6B£G­A`>`>`>`>`>`>‚ 0€÷£ý—&''ƒ¾þ•xzz¾{ó! Êø ˆ Äq!DAäŽãä1y !”˜˜Øþb Y€ÿ”ù¨jJA£u,šb0ÿdeemÞ¼ùﺻB¡øwÜôý©‘òÛÿ›Úèoi÷¿«Vr¹œÇã5OçóùR©ô¥–vV 5‰€8Yû‹{2¹¾ùŸmV‚ êêêÞ¾œšš0ßàôéÓ†¹ººæååݹs§[·n&&&ÿäí5¿üò‹‰‰IFFF'ò^¿~ýÉ“'ÊÒÐÐpýúõ¿EÒË—/ÿòË/ï¶Ì;wj~°½›¶¦Æ6+Ó®\¹²oß¾NHúN(((˜9s&õïW_}åäääããÓÑrfÍš…ai-Íž=ûN÷ª…k°ï]]]MMM[ë픤B¡ÐÏÏÏÔÔô»ï¾ÃqüÓO?522š6miÊ?~<$$ÄËËkçÎr¹œÊž››;eÊ”   sçÎQ‰/_¾Ü°aƒ‹‹KRR’ê½###­­­«««UÓׯ_Ÿ’’ò®ÔR[[;`À€¹sçvn o“ÿû¿ÿ;wîœZ}¼½½;QùÌ 'Ožœ˜˜øë©Z¸æríÚµ6%½víÚŽ;¨SóçÏÏÎÎ&¢ªªêÀB¡P,oÛ¶íÈ‘#ä¤ÅYTT$‘HæÍ›—’’B¦¿xñ"+++**JmT¦¤¤7N­SRRÂÃÃIó;!;;{Μ9•¨5Ž?þÃ?(ŠL™2…­ªªÊßß¿¸¸X,ÇÄÄüøãš yöìÙøñãAUU•ŸŸ_}}=™žššzíÚ5¹\^__ÿé§Ÿfffj.ç‹/¾ˆ‹‹S*•{÷! Èã?þøcÏž=H(ß¿_.—WUU-Y²$""BC! ßÿ=yL¾„tN¢#FTTTÇOŸ>?>AJ¥2::º¢¢B¡PÄÆÆ.X°€º>&&æçŸþ+'öÖ:Ò?þ¸ÿ~‰DRXXèççGIÑ¡¶#ÉÏÏ1bD›óakéàÁƒgΜi¿Œ­U¦¤¤ÄÏÏ/))I"‘ÈåòNt$¹\îëëûäÉ™LvùòåÅ‹k.¤¶¶öþýûñññk×®m¤-"—Ëïܹ“ŸŸïî~ûöíÅ‹755Õ××/\¸ðöíÛïûqsãÆ Ç …B¡Ëå§Nš:uê”)SNœ8! …B!ŸÏçñx 66VƒHÙŠ¹ÙY_-žÿî¯oݺ5mÚ´¨¨¨¡C‡>úèĉí×ÿ7úõëçàà€:s挩©ittôçŸîáá±xñâüü|Íê­¨¨øöÛo===§L™òàÁ„T*>|øµk×=<<ŠŠŠ4ÜtÿþýáááÓ¦M =qâÄàÁƒ×­[G:BD"Ñ®]»‚‚‚†~âÄ ¥RÙZ‡iM*ƒãøÅ‹ÇŒãçç·mÛ6J½­Ijdd4wîܳg϶Y8AcÇŽ511‰G?~ÜÈÈhݺuÔ[^^¾jÕ*OOϰ°°ãÇ«-9ÉdÚÚÚ~ôÑGš‡­µ9émܸqÍš5l6»=«s-v¤¡¡2Ë—/ß³g“Éd0èHä›°žžƒÁ000 =066öòòb±Xo#)ƒÁð÷÷766VK·±±Ù¸q£‡Ã ÎÉÉù+ýŽçÏŸ§üŽ/^¼xñâ?Èû(“ÉFŽI>¤ëëë===kkk ‚¸uëBèþýûJ¥²ªªjúôéÉÉÉA(м¼<‘H$“ÉV¯^­z—#GŽ:tH,?|øP(1wîÜK—.)•ÊÚÚÚàààêêj‚ ²²²ÂÃË‹‹•Jeeeå¢E‹’’’‚ˆ_ºtiSS“\.'=üš½¿ýöÛ† d2™D"Y±bõZ Áû8þ|—»wïJ$ò¦­9“nÞ¼innž••…ãøo¿ýE¾S†……=~üX©T¾xñ‚Åb;vŒÊòèÑ#sssU‡M›¬Y³æÀÔ¿Û¶msqq),,Äq<;;;((ˆò·5WoSSÓÈ‘#333É6R}©Õì“S½icc#‹ÅÊÈȈ‹‹ ª¯¯ß°aÃÍ›7qŒŒ<þ¼L& …?ÿüóÞ½{5t >¹+süøñM›6 ¹\?kÖ,…B¡¡#qýúõ &´§pÒ¯#‹ ‚hjj "[ToSSÓ°aÃ=z$“É÷íÛ·sçNÕÒ._¾¾û÷hiiéêêΞ=[GGGGGÇÅÅ¥¶¶–4À¿ùæ///ÒÙ°páÂóçÏ8Ïç_¸p!>>žÁ`…BÕÒ6mÚ4uêTÒ@¦„‡‡ÿïÿKIIéÖ­[TTT×®]IVrròèÑ£ÉkžžžÏ¡C‡V¯^m``€5jTXX˜æÊûøø,Z´ˆÇãÙÙÙ…††¶óû™û÷ï0`™]ÃeºººŸ}ö™³³3B¨OŸ>‡¢BÇúöíKz ¶nݪšÅÍÍ-??_GG§ýúOOOW«ÆºuëlmmBNNNãÇ¿ÿþÈ‘#[Tollìˆ#\]]É6ŠŒŒŒ‰‰!EkÿMuttLMMûô铚šêííÍápºté"‘HÊÊÊ*++É&ÐÒÒš?~ß¾}g̘¡¡Ãt(Æùÿû_\\ù®xþüù/^ôêÕ«µŽ„233#×Jètz›î±ñãÇ_ºtiìØ±§NZ¸p!Õ(ÍÕkllœœœ=f̵ìG-% àüùó³fͲ³³›4iRnn.BÈÒÒ2222í5999Ôv]Õ èëëk–ÈÚÚúÊ•+‘‘‘ŒŽŽngl)ižv¨Ã©Îª-×|®ì觘ÌÌÌjŠZùºººÔ«ª®öæ7íôxëô˜TÛF­¦·æ’’ZGGÇ6mG’I“&EEE•––ž:ujøðáÔËårýüüRSSÉÞ˜‘‘‘““£Z‡ÓžÅ_™L¦šËÞÞ¾yÿÑÖÖVÍB.¨vtúkñ˜*ÜÀÀ wïÞ±±±Ôklll]¨&©¾¾>µšF:rÈI€j2GGÇ ìÚµ‹êWÔªzEEE÷îÝ;=Yñx<.—ÛNõ¶©.&“©yFjmh¼‰0  ÌŽœœJ´ÚÚÚY³f >|âĉm–ckk[QQA=Ì,,,TÏ2™LiÓ¦Q £-Òµk×'Ož£ÇãÑh4Õ6E]½zµÍ•ëÖ$êÛ·¯Ú…6HN:Åd2×®]«Ú픈â£>?~|‹¾ &<}úTu»Lmm­Ú$cggggg÷èÑ£[·nMš4‰|³U{YÕÖÖ¶²²¢fjÃqÜÈÈHµËµ¿#;wn÷îÝ¿þú«Z‡oÛeff–––4ÈÙÙùÒ¥KÛ·oï\G222rrrb2™\.×ßß_mh´³2]»v%§==½ÀÀÀ¨Å‡´§#•””`æíí­¯¯ö믿vn»æ!Ó~²²²æÌ™³uëÖ~ýú¡–·2ÇŽ{úôi¹\. ;¤ùúí۷ߺuK*•–––îØ±côèÑärCÏž=õõõŸ?~æÌÍ%466úûûWVVÚØØ¸¹¹uïÞÀAAAW¯^%½Ê"‘ˆZÑŸ2eÊž={ø|>Žã7nÜаkdòäÉ÷îÝãr¹ÎÎÎîî¥ÔS°  ÇñºººÄÄDµ}oƒ³³sNN΃HdC‘‘‘áàà°{÷îöH¾«¦|ýõ×9992™,##ãÊ•+\ª>>>—.]zúô)Aõõõ;wîœ0a5[ã8^RROE§µvÓæXZZššš^ºtI¡PH¥Ò}ûö-Z´¨ýÁ^jdµÊ`¶dÉ’èèh‘H„ãø;wÚ|Ó%#²Û,œê3fÌ;vì¢E‹T­‡æêuppèÕÓhv IDAT«×éÓ§ÉP凒‘XíÙ9nܸ½{÷’+Ñeee«V­zöì‹Åšpà€ª¯]¤‰& ɨëI¤j‹¨¾`ž;wN$Éårò#”½¨T*ïß¿ooo¯VÂÔ©S9ò믿~òÉ'dJÏž=_¼xñðáC‚ ¤R)¹FLž*((ˆ‰‰¤³ÿ‹/¾èhGÂq|×®]wîÜÙ»w¯‘‘Qzzzvvv'ÚÎÇÇçékBCCÛÜ4ÝbG‰DÑÑÑåååAäååýñÇšM¥Ö*£­­½xñâ .H¥Òû÷ﻹ¹ivµØ‘LMM?~,—ËãââÂÂÂÚŒ¡ìÐéwîÜY±bů¿þêääTSS÷¡Úoû¨P(<8xðà#FPg÷ïßohhøÉ'ŸÈåò¤¤$cccr‹â­[·–/_¾uëÖaÆÍ;7==Ú6pàÀ¥K—._¾ÜÞÞ>%%E.—‡‡‡ÛÚÚÚÛÛ»»»‡……‘1<oÈ!ÁÁÁ½{÷þøãÏœ9CE±TUU­\¹Ò××wâĉ»wﮫ«£ªF=wîÜþýû“ºE,X0jÔ¨>}úx{{ÿôÓOTŸÏÿöÛoûõë7nܸü‘,¼¨¨ˆ\çêÝ»·»»;$‘’’âîîÞ§O‹åîîîëë[RRR[[ëíímnnOî¹ár¹ä$R[[ûÝwß 2äÛo¿ýá‡Tc³³³ýüüŽ?Þþ(‡üüü>}úP!/Û¶m‹‰‰YºtéàÁƒ¿ýö[RöÖÔKDyyùòå˽½½'L˜ Ê™ŸŸ?}úô~ýúÍ™3çСCjÛßToúóÏ?#„Ž9’’’bnnž‘‘±k×.@  wîÜI†Âüþûïd!­u˜Õ¨¡28Ž_¸p!,,ÌßßË–-MMMš%Åq|̘1ª2¶)iAAA@@€L&S oj®^2¤uÏž=Æ 1bÄæÍ›_¼x¡z ©Têëëûüùs †ê½cÆŒéß¿ÿìÙ³ÉøQ‚ $ILLÌàÁƒÃÃÃI?ÊĉI×ÅÏ?ÿ¬gY^^îââBÆ(Ož<9""¢©©‰Åb>}š ˆÇÏœ9sàÀ_|ñE~~>™¥µÂq¿|ùrxxx@@ÀòåËïܹCEþ¹»»[YYuïÞÝÝÝ]m·¯š¤A¼|ùrÞ¼yžžž+V¬ ‚\+**6oÞìëë°{÷nÕ½ÞÙÙÙ'N RÝÂyäÈÕ›&$$éîî†...~~~TsÔÖÖÚÛÛ«ÆÔ¶¨^…B1nÜ8ssóôôô½{÷z{{755?~éÒ¥AÔÔÔ¬ZµÊÛÛ{Μ9G566&¿ñÔÚŒÔâxì¨D6uîÚµËÏÏoÑ¢EUUUToär¹îîîîîîýúõãr¹mNä²`xx¸jPxfffdd$9^Ú‹ÙÐÐðõ×_ûúúnݺUmŸþÓ§O<Øž‰«E‰È¡´{÷îàààaÆíÝ»—š“›“——×»wo2ö‘ÄØØ˜ô)tH¢uëÖ‘]ˆôcQé"‘èÀ!!!\¹r¥j%Ç×<¤R©T6lÑ¢Ejo«W¯öõõ úßÿþG–S]]pìØ±ðððqãÆ?¾‰ôkÏ#www[[Û67>kh;±XÜÝÝ{öìùõ×_ÿÅ;¯¥R©T*•H$"‘èmv^¿•ùØ!nݺµmÛ6Ðøi†¥K—¾ý6þeË–]ºt‰z¢ïsïÕ›~´¡t‚ ÂÃý½½;]‚H$š:ujbb¢‡‡Ç¯¿þÚÚ"/t$ sˆÅâ{÷îQ‘µ:öÕâùÛ¢v‰EB„Љ“§¨ÍËÍINNîÐV>ào$))ÉÇLJÚpM‹-î¼NLLÔ°;ÂÈȈ´ËJ ÷ìŠf€fþ P棪)IDG?óBU`>`>ÿóQ.—óx¼OQ™Íiç7ß5tN¥ïC½jŸJî|>_*•~¸ú×ÐÛÿÉ’’Ô¢Â[ë½R/ùð÷7Äàô¨w2ÇvhšzßOŸNåÿ}˜À||ùòå† \\\’’’šŸ½wïNm~êòåË¿üò õonnî”)S‚‚‚Î;×ÎÂ[ì¾{öìñóó[¼x±ê¯ÂÌ;·GÎÎÎÎÎÎ'Nœh³œ¸¸¸±cǪþZŸÏß´i“‡‡Çœ9s4ÿòIccã²e˼¼¼¶oßN>ÉòòòœœœLMMÉšDDDP?iÓQ‰ª««×¬Yãéé9f̘£GR?¥³~ýú”””·o;¥RyéÒ¥ & 4Híg‚›_yòäɉ'†„„4oýÑ£GûùùýòË/mþjmbbbdd¤µµµª˜ÙÙÙ}ûö555Å0Œú( H¥R ÃHõºººfee‘é‰äçŸöóó›4iR{~ë!$bbbBBBBCC)Û¢y›ª±víZUý·Ø‘Z”T- Ç?âååµsçN¹\Þ¹ŽDM§Ó©ßìhe$ÉÞ½{‡½uëVÍ\›CÃÙÙÙÈÈèÉ“'è½Rocccttt@@@tt´jzk¦¨¨höìÙí4µ[ë½A\½zuüøñžžžß~ûmtt´æª®X±ÂÉÉ Ã°ï¿ÿžJüî»ïØl¶““©. ‹ÿgïÞ¡ÌþÇŸ4š)Qºß"©f™Še í`r‰è²!QªU±Ê–ú”T*}ºíR‰*·$E¥¤Ð’(k–’rIR˜a3¿?žïw~óchw«Ý÷믙3Ïœó\Î9óžó\NjjêP9éyFÔ4 533ЗÚd%¤ÂˆÞó „ ƺuë ¼¼¼âããùMoD=ÏP})Ç‹711Yµj•ðgå<þ›œP__Á‚)))jHYYÙ† ŒŒŒ>žèåË—žžžÂÛ©>vD?aÃþ(ÛN…ô±¢7 6›=þ|¬6š˜˜:tHpÊ¡ŽéˆúXá݈[Êãñ®^½jgggiiyåÊ•Q‡………nnnd2yÛ¶müžGÚÇòÿ?¨©©}úTݦOylø³gÏ***BCC?~Žww7N÷óóô###£çÏŸco™L&•J}õêUOOÏÚµk‹‹‹‡Í|PÉÉɇâp8¿ýö›››ÿqÐ^^^æüâ?þXºtiWWWKK •Jå?›>00055µ··÷Ù³g³fÍb±XÂóùé§ŸnݺÕßßúôéÈÈH,ñÞ½{Ä{}Úßßÿñž ¸|ù²ðv:T;ÒŸ0á?Ê"¶Ó¡úØ5ÜÜ\¬6ö÷÷çää¬Y³ÛÒ¡ŽéHûX!Ýè[z÷î]__ß>¼{÷nÆ ÃÎå1h¡ýýý'Ožljjâp8ÙÙÙëׯ]‹Ù±cG@@À€ÎJDùùùŬ3Ÿ4úˆê :mqRR’›››ŽŽÎÇåää|ûí·ZZZØÛGÑétUUUàééÉŸÌ^Hæƒ:w‹‹˜˜˜‘‘›Í®««ÅݼysÕªU$INNÎÅÅ¥°°ÿpüøñbbb$IpÂûAµµµ=zôèûï¿ÇãñË–-;~üøÇçËDêt‹nß¾íèèhll,...''·}ûvþ¿R …Âd2KJJ>娕””444ìÚµKQQqÀ”¯Ÿ7oÞÇÏ©æñx$‰@ HHHHII ;0{öl•ŸàÝØØøâÅ‹­[·b?À£«¥4måÊ•AMMÍÌÌlØa¶óçÏ;88üðÃ&LàÏ‹:ì1÷ññ3fŒðŠ4Ô–j¨¦!''çááA$%%%ÕÕÕÌ?.zÓàñxû÷ï "‘H£[™—/_¾zõjÅŠ’’’ãÇwwwRg†Ý¡¡¡gÆ Âç+ªöŽh÷Nš4ÉØØ˜H$Š^aV¯^=`¨Rˆk/—ËÝ»wïŽ;dddÆŒcbb’œœŒÍú-Ä7ÜÜܬ­­±y–UTTÜ¿ÿûï¿777ñL½`Ï3Ò¦!˜6Ѽ&3(!fD=O||üŽ;455ÅÄÄ444Nœ81}úô‘ö¹¹¹K–,ÑÓÓkooöì™('W­Ze``øþý{,qÆŒØOÑãÇÿøã3f {&}ܸqkÖ¬YµjƒÁö˜b222ôõõ‡­H#"¼iܸqcùòåçξ{…4Û·o«««»C„¬ÌË—/ ùa÷ððø”¦áççÇf³uuu?ãD5B*Œ®®nRRRggçèjokkë¤I“¤¤¤øËØÛÛËÈÈ?Õ=kÖ,kkë«W¯ ~dii¹p᪪*…É“' _™A{ž‘6 ¬P))©††þä(ƒ6™¡ÂÇ¡*̈zžÂÂB þ[2™Œ…#êy„ô¥ åúõëïß¿///÷öö®­­±òŒ3†B¡`xMM¹¹yLLÌÂ… ÃÃÃüÍc0ü/ÂÂD7TÏ#üGYôv:h;Ò¦!ˆL&×ÔÔ9¦#êcGº‡ÚR qãÆa DGG[YY:üxþüùêÕ«-Z´k×®Ñuø}}}{öìÙ¶m›ˆŒ¿îðñðáÃaÐOËÊÊøG}€?kïæ³k×®C‡=xð`Ë–-îîî¢_S/˜I\\Ü–-[ FiiiPPаã=Cùé§Ÿ=zôâÅ‹/^üòË/Ã^þøñÊàñx!©UUU+++?e×555íÚµËÝÝ=22òòåË"ŽeÐÜÜœžžþüùóòòr}}ý¬¬¬Ñý%HJJš;w.ÿá‡rrr†ýë_RRòßÿþ·¸¸ØÐÐ0$$DðÓ‚‚‚àààˆˆˆaã’‚‚‚ôôôìØ±cýúõíííîj{{ûãÇùÝÇ_Q«?ÎÄÒÒrÏž=³gÏvÏ šOWW×áÇׯ_ÿ)+ƒÃá†ZQÓX´h‘ðá«¿Í ‹ÒDi¶ƒÖ^7ì…ªcƒOFFF111‚µñÖ­[gΜÁæÏìééuÏ#zÓÀ -++c±XK—.=zôèH›Œ 3¢žGLLlÐ+íFÔóéKi4šÁ?üœœ|êÔ©¡šöPÛˆ 6·¶¶îÞ½[__?!!¡¿¿ÀµÏŸ?矂û: á?Ê"ÒÇŠÞ4†Ú]CÓOéc?q7Ö×ׯ^½zÏž=ü¨n}µ¶¶vppp```TTÔè2¹té’ªª*úÂüùác{{û­[·<<<ôõõwïÞ<à‰‚‚‚àÈ‚‚«W¯ø=ˆ¶¶öèÚ‰¹¹9?äúô©œœöZEEEEEE\\\OOOJJJø555þuîõõõü07..ÎÁÁAJJÊÀÀ`Ê”)‡H'Ožüûï¿cM¢££Çcÿc»- eË– é"‡Ú"2™<à‚hÁK;::ø>:êêêGŽÑÓÓ›uêTLLŒ(;ÇÊÊjË–-“'OÖÒÒúî»ï°c-ü˜‰D"‘(x †ªH#"¼iàñxõëׇ‡‡¢i”——744Ì;W__?33“ Œhetuu ƒwÂ(šFjjê'þÂý)†ª0Øé§ &Œ®öNž<™Ëå ÞBÛÝÝ-ü†ƒÌÌÌ{÷îéëëÏ;—H$Þ¿_ðS33³¥K—ÖÔÔŠÔÝÔóŒ¨ið;ÖÅÅ»Èo¨&3(!fD=Ïüù󫪪øo¹\.vhFÔóéKq8œ‹‹KvvvppðǧM›&âžéíí---UQQA)))ùúúZZZŽ?ÞÆÆæöíÛ‚KÊÈÈŽÞ ù ‘A{ža”Eo§Cõ±¢7~ÿýw,Œ꘎¨én²¥^^^‡j rÑ¢¢â?üÀ`0„ß>?T‡åÊ•ÐÐP}}ý~ø!""‚ÇÒ?0|”‘‘aü¯Ý»wbÿùfΜ)x/…BÉÊÊjhhèíí‹‹³³³]¹îîîIII\.·¤¤DBB Õkjj:;;ûúúîÞ½K „_idmm}æÌ‹ÕÚÚšœœljjŠ¥ÛÛÛ߸qƒÍf?{öìÉ“'ÂÿLš4ÉÐÐ077—Ç㥦¦nܸñãe:::rssÇêEÜ" ‹ÊÊÊììì¾¾¾îîîØØØ;wò¿R]]=uêÔO9|t:===½¹¹¹³³3''‡L&"“©S§^¿~½±±‘Édfee ™CSˆ;w¶¶öòåË,«¯¯»pYø•*Cuø‰‰‰Ø±KNNþñÇœÓÿœ>åÎëóçÏ*++kkkÞ»wOðÓ   eee*•ÚÑÑ1à¶Ü™3g ÞEXUUµ|ùr–––&bæƒÞN¥R7nÜØÒÒ‚%r8œË—//Z´hÖ¬YÍÍÍÃÞ£”M§Ó?~ÌOìèèØ¿ÿ¬Y³<==«ªª†Í¤½½}Ë–-¦¦¦‡îééÁî›6mÚ7ß|chhhhhhjjššš:Š-Ân ;uꔵµµ••ÕéÓ§™L&ÿNR ·oߊr+–Ýûûï¿ÿðÃóæÍ~;'¶™4mæÌ™D"ÑÐÐpùòåüû% LMM###‡½ÓÇÇÇÐÐp„ Ó§O§R©·oßž4iÒ´iÓ°»ÏâââÔÔÔttt„ìüŽŽŽS§NYXXP©Ô'N` ûG8mÚ4l·«©© Ö±¡\½zÕÚÚÚÁÁáÑ£GBŽé€¯øùù [‘>ÞRák2hÓhjj 155577?uêÔÇ+#bEÂê’­­í„ 6mÚ4ìnte¸\îµk×–,Ybjj4ìݻ›FTTÔ§ÔÞíÞ²²2CCC¬èãÇ[aÂÂÂNœ81ìê ¯½åååëÖ­›5k–···Ìûúú&Mš´fÍìá”Øý1;wîÜ»w/¶ØJN:ÕÛÛ{¨|†êyFÚ4 9s¦···à±´É JH…½çÁž?hjjºdÉ’ëׯ®çª/½s玩©éòå˳³³…ßþüùs ¬ÒéôóçÏ .ßÚÚºiÓ¦Y³f–ÅbÅÆÆÒéô9sæìܹS”•´åo¾ŽŽŽ²²rEEÅrç5Îß×ûHhx7‹‰J¹êèè8T YTTdmmý§Ä¬Û·o§R©¶¶¶üybccY,Ö† `WüýØl6ö0<555ØÿHÆÆÆ÷îÝý6X„_#QVV¶gÏhÐÇþ¥ LLL°ëdøóD`/ø…àñxx<>??_Ș½´´4+¾®¯?ùy®R÷÷÷þ,V0 ššš†††°> #üi#à«Æáp¢¢¢ v;;»Ïø„¯®i@û¥ù<ᣬ¬¬¬¬,ìý?—™™ì„ÏHð¡àŸGFFÆÄÄöøÓ~}ÅÅEŸKšô±_ä„ÂGá#€ðqÃÎò%ø*VrtøwéÚÇÍÿºv×ÇkÛÙÙ9`Ë¡¶è\1€¿5|¼uëN_¼x±àôãããUTTôõõõõõg³...%ÛŒŒ ‰¤«««¯¯ïââòÛo¿aé»wïæ§ëëëkjj ™´—Íf[[[“H$ýÿ¥¨¨˜ðüùsuuuuuu}}ý ¤¤¤ðç {õêÕêÕ«…O#öõÚ³gÿ÷ôô„……Q©T—“|¬¿¿ÿÂ… Ë—/ÿø>AÑéˆ`ÇnØùT‚óçÏWWW?pàÀ  ôôôØÚÚvtt`oóóóýüüTTTÌc9ÔýE[ ü»ÂÇÊÊÊèèè´´´ððð7¶··ó? ŦÙœK×ÎÎîСC¢ €ÙÛÛS©Ô¼¼<ƒqâĉèèhlºݻw[XX`é #33SH&!11qΜ9üùšŽ;†ÒÖÖöññ‰‰‰a0—/_nnnæOf¯¦¦ÖßßÿàÁƒÞ‘®©©ÉÎÎ600ÀÞž:ujüøñ·oß *ç/u IDAT Ù¸qcss³ïòx<…AÃ2Ñéˆ`ÇnD_?~ü;w„|+;;›B¡HIIñ‹ð÷÷·²²q‹þ¢-þ]áãÍ›7W­ZE"‘äää\\\ …/O¡P˜LfIIɈJ™8qâ–-[Nž<)˜XQQqÿþ}---___Q2¹zõjCCÃüùó¿ÿþûaŠ··÷ñãÇù³³¯^½Z°¬ÆÆF///##£ÐÐÐ;vØÙÙñGCÛÛÛCBB¨Tª¥¥åΟ?¥?þÜ×××ÀÀ`Ù²eØðÇKKKsss#“É .Œjm¹\îâÅ‹q8œ‹‹ ÇKHH——×ÕÕ­©©A=~üxíÚµd2ÙÝݽ  ûÊëׯgÏžÃ᪫«×­[·pá‡#>>ÞÇÇg̘1Ø[¶råJ ¦¦fffV__/d‹Ï›7oЧÂ~|LÏœ9ãìììîîngg—’’baa±wïÞžž„“ÉfÌ …Ÿtuu“’’:;;±·ŠŠŠ†††²²²wïÞÍÌÌüöÛo#""B}}}>>>÷îÝKKKãp8Øhnnð÷÷/-- ­¬¬|ûö-B¨¼¼üôéÓ§OŸ~ôèÑÊ•+ÛÚÚ†<*xü… lll8€‘sçÎÍÊÊÒÒÒb0ûöí ,++;|øprr2&*))aƒ¦Û¶mÛºuëÙ³gÇ/˜gFF†à3Wg̘=¾ÿñãÇüñÇŒ3FY>:¦ÎÎÎÙÙÙ?ÿü³ŸŸ_ttô¥K—ÄÄİuKKK{ÿþ}FFF^^Þ¬Y³:::ðxüŽ;6lØ0{öìS§NuttìÛ·Ï××W[[!ôòåË™3glܸ1 ËÿÆwïÞ={ölnnî´iÓbccÏž=˯‡Cill,**š2eÊ(¶èk/ðó§Í:#8Šãàà`ll¬®®þáǵk×*++ó¶UUU>|ø)™#„nݺUUU%ü|+ßœ9srss=J"‘„äÏ?)9yòd„PCCƒžž–B"‘æÎ;vìXyyù9sæHII½{÷!ôôéSEEEccc„””Ô¶mÛ°«ènß¾íêêŠÍË©  ƒÍL¥¥¥¥  °eËmmíéÓ§¯Y³Fxóã?¦§§oÚ´‰Á`ÈÈÈhjj"„rss‹ŠŠøS“wuu7Nð‰ÿñññãÆCIKKóÛÛÛ?~,//? ”‚‚‚cÇŽEDD|ÊÜYŽ©¤¤¤¼¼üÌ™3>|øÝwßÉÈÈLœ8}411Ù¸qcGG‡ººº6·¦¶¶ö®]»jjjÖ¯_?nÜ8&“ÉsçÍ›‡\ÖÕÕ½{÷.–˜˜˜¸gÏìô‚ –.]*ÊJÖÕÕ}÷Ýw"næPµttµ€ðñÿSSSkjj®êëëUTT°tiii,v‘““›7o^uu5?|ìèè““iAµµµ ,œìÒÌÌlDW¡ùùù‰‰‰ úQoooii)å±³Ø&L6Ïþþ~Á<ÇŒ£¬¬Œâp8‚«ŠÅ£ØqqqïÞ½knnNOO¿}ûöÁƒ…äÿý÷ßïÛ·oõêÕ©©©+W®Ä•””üüüoH‹ ‰D"‘Éd &^¾|ùâÅ‹111‚&†Ãላ‹Z7D?¦***ׯ_oiiillüå—_ZZZ'NœØÛÛ{ñâÅ   ÔÔTyyyÆ¡?þÿ ...xoS¿(EKIIÕ××óx¼ÏV‹¾E£«½À?Ì'¼¶¶¶>sæ ‹ÅjmmMNN655E±X¬“'O666òx¼çÏŸ§§§ûí·ü¯TWW{ºy€öööÿþ÷¿î°Æáp#š:]HìxêÔ©ü‘H$b)MMMŸãþØÔ©SŸ={VRRÂãñØlö­[·‚ƒƒBqqq XÀ“––†ŠŠŠŠŒŒ7nÜÔ©SŸ={&<"‘èéé{ïÞ=lŒ!D£Ñ²²²ÊËËy<‹ÅÊÈÈÈÈÈvU Nç_]ÀårÃÃÃóòòNŸ>---]VVVUUÅ_¸¼¼\OOïôéÓ"î[Ñ©««kaa¡œœœ¾¾¾¡¡!¶‹BæææÛ·o÷òò3fLtt46p;”+V?~¼µµµ§§'==Û·ÃRUUmhhÀ®"õ¢öÿ@þ¾Þ<Åìb1»bccÛ‡–ÍûHvv6Nwvv~üø1?ñáÇk×®ýöÛoÝÝݱ@óöí[ ·oßò†“™™I$§OŸnhh¸lÙ²‚‚,}ïÞ½&L˜>}º¹¹ù›7o„gÒÓÓcccC$ W­Z…=õ j544´µµ étúùóçûûûùß ;qâÿmccãôéÓ¿ûî»öövWWWŸ>‰Ä‹/òx¼7oÞìÚµËÔÔ”F£aÃiØ·***Ö®];kÖ,''§ÄÄÄîînçàà0kÖ,CCÃ-[¶444 »šššB‰‰‰‚‰---;wî455]¾|ù©S§ÚÚÚx<Þ­[·°0ÝÐÐÐÐÐ0##c@VW¯^õóóÃ^c'Ù§M›†-¬¦¦–––Æ_²ªªŠJ¥&%%ñSÚÛÛi4ÚÌ™3±¹|ùrþûø˜†……!„Ο?_\\üÍ7ßš™™}á»CFFFð.濚ššÚ£Gþ¶âÜó8¦***ùùù#úŠ(ÓØ µE_~íþxØÂGá#€ð@øøuÈÈȸtéÒ¾’l6j*¾îð‘ÃáØÙÙIKK¯^½!Äb±h4‡Û¶mBèÍ›7AAAFFFNNN l6ÛÚÚšD"éëëϘ1cÆ µµµŸ}ã_¼xQ]]ý·‡=»ÛÎÎÎÒÒòÊ•+Ã.ŸŸŸïçç§¢¢‚=åà+ÅÅŧL™"‰IIIt:=$$„Åb¹»»/X°    ""¢´´´¨¨ˆ@ $&&Ι3‡Á`|DIIIYYY•””`osrr<<"„ìíí¯^½ŠEoñññ4 !TYY©««Ë_FVVÖÆÆFð[===7nÜ B¦ ùé§Ÿöîݤ  @&“7oÞcggÇ`0öíÛXVVvøðáäääÂÂB,$MIIqqqñööž?þÍ›7§L™‚b³Ùvvv¾¾¾ååålhhÀòŸ0aB^^^bb¢`¡Ø´ÈÊÊÊYYYiiioÞ¼9sæ BˆJ¥¾ÿ¾½½=###11qëÖ­mmm‚guuukkë°»KCCcܸq¡ÖÖÖèèhVÀ×è“f¡P(>>>uuu3gÎÄæúÃãñØ ÝÇŠ‹‹õõõedd,--cbbÄÅ…•îìì¼qãF[[ÛîîîsçÎݹs!”››[TTÄŸ˜»««kܸq‚óÄœ9sföìÙ!,‘@ lݺ5 ÀÀÀ@GG;Õ>”ׯ_777/\¸!$!!áííM&“=<<$$$ÆŽ»zõjIIIIIÉéÓ§¿}û–?±¡Á‹/$%%EÜiõõõ6lØ»w¯ºº:Ô?ü»ÂG ‰•+WÞ¿¿¼¼ÜÉÉ K$“ÉOž<ÁF"1L&›¾yΜ9¹¹¹"f®®®®®®^ZZÚÜÜìââ‚å ¤¤äçççïï?Ô·¤¤¤ßòx&&fÑ¢EX FËÊÊ*//çñx,+#####CH<ذaÇÓÖÖž3gNKKKww÷P +))ÉËËgffr86›µqãF á+ùäÉ--­S§N »9yyyÿùÏbbbtuu[[[oݺÅÿèÇßÿ½§§çP·ÿðqÊ”)®®®ü3Ñâââ'Nœ¨­­µ··wttäp8û÷ïg³ÙîîîÅÅÅ eõêÕ<O”ÌgÏžýÇ())©ªªb)ãÇOLLLMM;w®——×ëׯMMMBuuu&&&.\prr¢P({÷îÅ–;vl]]ÍÌ™3wïÞœœ,##ƒŠ¥P(žžž'Nœ P(Ë–-ãp88nÿþý¯^½²²²rtt”––^³f ¶ð7~úé'‡SXX˜žž~äÈþJJJJª««Oœ8qØÍ9pà@EE…ƒƒ…B™7ož`ø(..>yòdYYYÁL___ …rãÆ ›¹sç655A}Àg‡ó÷õ>ÞÍb"„R.¤ò/+üXQQ‘µµ5ì2€¯BAA‰‰ —ËEñx<ÁØXöÇççç •´´4+¾®¯? “€€ð@ø |>„|RøØÓÓsúôiKKËùóçŸü/U\\¬¢¢ÿÕeðwïÞ-))™‘‘qåʉ´uëÖ/!|œ3gαcǾÆÌ¾|â£þæË—/_½z‚Ãá$%%ÝÝÝBØœ{MMM'NœÈÉÉ™2eÊÆ ###¹\nMM͆ 233ÇtóæÍk×®‘H¤wïÞ­X±"""ÂÂÂbëÖ­’’’Ïž= ÏËË“••Ý´i“ B(77›o033S\\|ûöíóæÍÃÖ§ªªêرcååå4mòäÉÒÒÒÂ×?///""¢ªªŠJ¥²Ùì_~ù…D"±X¬¸¸¸K—.IHHxxx,^¼XLLLHæ?/**"“ÉëÖ­ÃfPDýöÛo)))999ªªª'Nœà—òàÁƒ¸¸8Qæ9øâøûzóx<³‹ÅìŠmZvv6OÀíÛ·:ÄûȇìííËËËûûû[ZZÖ®][\\Ü××çêêšðúõë &0ŒìììÇ¿ÿžH$>yòäÖ­[4íÝ»wûöí»sçÇëè訫«ëëëëìì´°°hhhàñx½½½öööAAAÝÝÝïÞ½322zûö-Ç«¯¯wpp¨««ëïïÿý÷ßBqqq¼¡Ý¿óæÍííí§¼¼\YY¹©©‰Ëåúùù]¹r¥··—Éd†……>}ZHæÎÎÎXzssóÆ x<^OOϤI“^¼xÁårËËËøår¹Üõë×OŸ>½©©‰ðWÊÏÏçr¹‡Ãáôõõ±Ùl6›ÝÓÓÃb±˜L&“ÉììììèèèêêÊÎÎòcÅêª _ïÑ>âp¸þþþÓ mmmg̘’““óó󋌌œ={öرc'L˜ ¤¤4mÚ´ŽŽ‹%)))//?sæÌ‡~÷Ýw222'NìééA½yó&::úáÇ ­­­]]]! ‰±cÇ®^½ZRRRRRrúôéoß¾4iÒÍ›7===UTTBÓ§O ¾òIII~~~Ø âŒ3îÝ»'//ÿúõëæææ… by{{“Éd¡2ÏÍÍ-**âÏÞÕÕ5nÜ8°uëÖ€€ˆˆÁvâĉÞÞ^]ð5}ø¨««ûË/¿ô÷÷c§wBL&“D"aA’`À4ŠÌ;;;7lØpôèÑ]»váñx//¯¡BØA_;Vxþ½½½ØyvŒ†††ðµ4s%%%???ÿ óx}º££ƒÇã½~ý:00ð?þPRR’——ÏÌÌäp8l6;**jãÆCeN£Ñ²²²ÊËËy<‹ÅÊÈÈÈÈÈ@=xð`Æ <O[[{Μ9---ÝÝÝü¢}}}çÌ™ÓÜÜ •_#ñOùòÚµk³²²V­ZÕØØH£ÑRSS‰D"B(22òøñãwïÞUSSóññ166¾ÿ~zzú˜1cþûßÿþñÇIIIQQQ½½½/_¾LHHÐÑÑ‰ŽŽ^¼x1BèàÁƒ×¯__±b…¥¥¥¸¸¸½½ý·ß~ëé陑‘qõêÕ7nôõõ]¸p¡¸¸8==!¥¬¬¼ÿþÝ»wWUU™™™íÛ·/((HKK‹J¥nòxÞÍb"„R.¤ò¯äûXQQ‘µµ5ì2€¯BAA‰‰ —ËEa·ðò_`[Ä^àñøüü|##£¡ò‘––ÆbÅ×õµá'á"<0>„ÂGá#€ðñ«ÐÙÙÉf³Gôþ½ëö¾Žð±ººÚÍÍF£]¾|yØ…9NDD•Jõõõ}óæ ?=??ßÏÏOEEE0Q{öì)..æp8vvvÒÒÒ«W¯F±X,†Ãá¶mÛ†zóæMPP‘‘‘““SBBBBBBh÷îÝ$IWWWOOÏÉÉ©°°PH)ÏŸ?×ÕÕ•——×××'“ÉûöíëììüŒû¼¦¦æÒ¥K§_¿~=** ¾Üð‘Åb­ZµêÀ×®]ËÊÊzøð¡ðåÓÒÒ:;;óòò\]]ýýýùCeÁßßßÊÊj¤QTvv¶¸¸xbbâ”)S"""BD"1))‰N§‡„„°X,ww÷ DDD”––aᣅ…E^^^eeeXXXPPЋ/†*H[[;::zóæÍ £¸¸XII騱cŸq··´´TTT|œN¥R=úöí[høBÃÇGÑétUUUàéé™™™‰z÷î™LÖÔÔ¬¯¯/))!‘HvvvØ£ÒÏ;çââ"&&fddÄf³ëêê°|fÏž­¢¢‚ÃáFTz||¼6… ”””••UII öQNNއ‡‡»}û¶£££±±±¸¸¸œœÜöíÛétú€|”••étzUU•(…„… Þ¹s{ÛØØhdd´páÂääd‡ƒ¥WTT¬^½zöìÙ›7o>xð ¢¢b^^^PP‰Djnnîïï_¼x±´´ôÓ§OB</##ÃÉɉB¡üüóÏü@–Ç㥥¥¹¹¹‘Éä… ÆÇÇ#„222\\\ÂÂÂôõõõõõ<È_7iié5kÖ :0 ðE„MMMêêêØk…êêj„ÐĉÓÓÓ•””ÚÛÛÛÚÚh4ÚÙ³gñx<ÇËÍÍ•——Ç–×ÕÕé©ê222ôõõùoííí¯^½Šâr¹ñññ4 !TYY©««Ë_FVVÖÆÆF0.—Ë`0ÒÓÓÉd²(…666&%%-[¶ !ÔÑÑáéééä䔟Ÿîܹ®®®ÈÈH„ЫW¯vìØ±{÷îâââ5kÖlß¾=$$ÄÌÌlÏž=!11±‹/º¸¸`y¦¤¤}úÑ£G+W®lkkÃ6311Ñ××—Á`0 ì=™LÎÍÍ…¶€A‰Qk#8v¨©©¿dÉYYÙÄÄĉ' _~ÚÛÛ?~ÌFB ÅÇÇ'  ®®næÌ™“&MBáñøþþþ¡2133#‰&&&‘‘‘JJJÂKyòdÆ ü¯+))Õ××÷õõ`‰žžž¿þúkSSB¨­­-""â?þ@EEEEFFŽ7nêÔ©ÆÆÆÏž=Ö?~ü³gÏz{{»ººÊÊÊ ?ÿúúz*• m_høH"‘¢££·nÝjkkkee5g΄Paa¡½½}mmmOO“ɬ­­µµµ­­­E9;;‰D33³øøøcÇŽñÏ_ûúúR(”7nØØØÌ; ¤†åááqåÊÁ”)S¦HHH¸ººŠ‹ÿÏЬ¸¸ø‰'jkkííí9ÎþýûBÁÁÁùùù–––­­­Â ª©©ùñÇCCC·nÝŠÒÑѱ±±Y´hQoooppp{{»­­­££cNNva¥²²òÑ£GOžÊÊÊt:½ªªJ”B ÂÂ… ïܹƒ½mll 422Z¸parr2ÿ4ñ«W¯öíÛgll<þ|kkëÎÎN‹5þü¹sçÆÅÅY[[[[[Ÿ?ž¿ü“'OV¯^M¡P6oÞüêÕ+„P__ŸÏ®]»6mÚ4{öì;wò‡<™L&6#¢±±±µµuYY–þøñãµk×’Édwwwþ„Ú! …Âd2ù;>~6MMMêêêØk…êêj„ÐĉÓÓÓ•””ÚÛÛÛÚÚh4ÚÙ³gñx<ÇËÍÍ•——Ç–×ÕÕÅÎ_‹‰‰ñŸþ˜˜¸dÉ’ñãÇ‹RzFF†àcÃííí¯^½Šâr¹ñññ4 !TYY©««Ë_FVV›–šËå2Œôôt2™,J¡IIIË–-Cuttxzz:99åççŸ;w®««+22[lÿþý………©©©8®§§‡H$¦¤¤äççs¹ÜŒŒŒôôô–––˜˜„ƒÁ8räȾ}ûJJJÖ­[çããÓÚÚ*!!áääíååU\\¬££‹ež––öþýûŒŒŒ¼¼¼Y³futt`™ìÛ·/00°¬¬ìðáÃÉÉÉü3òx<~Þ¼y¥¥¥Ðf€¹/kÖÁ¹ò455ããã—,Y"++›˜˜8qâDáË#„x<^TTÔ‹/öîÝ+Jqííí?æ£! …âããPWW7sæÌI“&a‘SÿP™˜™™‰D“ÈÈH%%%á%;vììÙ³µµµ~~~{öìAUTTyyya p8œžžooo<ïììüË/¿kjj†††Nž<[F[[ÛÃÃÇ3æÇ466^»ví¥K—|||¾ùæ,ªvuu½sçβeËÆŽ»nÝ:,Dž9sæÙ³g±LLLL6nÜØÑÑ¡®®ngg‡Ms™››[TTÄŸ÷¼««kܸq&&&Ø[UUÕa/-„9…üü|ìuSS“¶¶6ÿ£—/_*((|øð¡¥¥‹äp8œ¹¹ù›7oBOŸ>ÅîtAõõõ8p€@ ìÛ·O\\¤í"‰D"‘ÉdòS$$$V®\yÿþýòòr''',‘L&?yò‰Ä0™L‰„½ÎËËSPPqc7oÞPUUåççW]]­§§'''G¥R¯^½úñ¼ÛææææææÍÍ͵µµ...ÉÉÉS¦LAõ÷÷ó¯Aär¹ÒÒÒX-Lãp8þ2ütÁTTT®_¿ÞÒÒÒØØøË/¿´´´8::*))ùùùùûûºòrrrÐf€¹ÏòšB¡dee544ôööÆÅÅÙÙÙaéwîÜ ;{öì™3gÖ­[WYY‰¥»»»'%%q¹Ü’’ UUU„Pgg§²²r@@€¸¸xFFv6V8@§Ó_¿~-˜heeuèСœœœY³fa)•••ÙÙÙ}}}ÝÝݱ±±;wîü”Mž:ujXXØæÍ›{zz´´´ôôô.^¼Èáp8NIIIhh(Bèýû÷óæÍknnVUU500ÐÖÖnmmåGÕ‘‘‘]]]ïß¿?~üøO?ý„rrr:~üxKK B¨¦¦&!!ÁÂÂBÈ:¸ººÊÉÉéëë644 „h4ZVVVyy9Çc±Xü¯TWWÃŒØøüá#‰DŠŽŽÞºu«­­­••Õœ9sB………öööµµµ===L&³¶¶ÖÖÖ¶¶¶!äììL$ÍÌÌâãã;†¨=zô(222<<|Ö¬Y ÅÓÓ ¤†åááqåÊÁ”)S¦HHH¸ººò‡0ÅÅÅOœ8Q[[kooïèèÈápöïß ÎÏÏ·´´´°°àÇvC©©©ùñÇCCC·nÝŠÒÑѱ±±Y´hQoooppp{{»­­­££cNNva¥˜˜Øøñã×­[7}úôåË—/[¶ì»ï¾Ã²277Ÿ8q¢‡‡ÇÚµk§OŸîììŒÒ××÷÷÷ß¾}»‘‘ÑñãÇýõW99¹¶¶¶Í›7GDDܹs‡Çã…„„$$$zôh÷îÝnnn,K”Òkjj²³³ ÄÅŧL™"‰IIIt:=$$„Åb¹»»/X°    ""¢´´´¨¨ -,,òòò*++‚‚^¼x!¤,ƒñ믿ÆÇÇçååM˜0!77Wøº={ö ›Kp*•zôèÑ·oßBõÀ¿1||ôèNWUU%žžž™™™¡wïÞ‘ÉdMMÍúúú’’‰dgg‡=*ýܹs...bbbFFFl6»®®ËÇÙÙyúôéx<^AAAFF[xXñññ>>>cÆŒAIIIYYY•””`åääxxxàp¸Û·o;::‹‹‹ËÉÉmß¾N§ÈGYY™N§WUU )«¥¥eêÔ©rrrÁÕÕuݺuXzccc`` ‘‘ÑÂ… “““9›¯]»V______pšiié5kÖ\ºt ª/þácSS“ºº:öZAA¡ºº!4qâÄôôt%%¥ööö¶¶6vöìY<Ïãñrssååå±åuuuÏ_wwwûúúZXXlÙ²eܸq¢”ž‘‘!øØp{{û«W¯"„¸\n||Ŧ“îèèðôôtrrÊÏÏ?wî\WWWdd$>ž>}šÁ`0ŒÓE’Éäa/þ _Ö¬38ŽÿZSS3>>~É’%²²²‰‰‰'N¾=w¬ì¶mÛ***ŠŠŠ¼¼¼°e8NOO···ðynݺÕßß/&&•ÿ®ðQAA!??{ÝÔÔ¤­­ÍÿèåË— >|hiiÁ"9gnnþæÍEEE„ÐÓ§O±;]ø&L˜`aaQQQñðáCsssáE‰D"‘Èd2ù)+W®¼ÿ~yy¹““–H&“Ÿ’H¤èèè­[·ÚÚÚZYYÍ™3!TXXhoo_[[ÛÓÓÃd2kkkmmmkkkBÎÎÎD"ÑÌÌ,>>þرcØùë±cÇÊÉÉmÚ´ÉÐÐðàÁƒ{÷îUVV¥t+W®¦L™2EBBÂÕÕU\ü†fÅÅÅOœ8Q[[kooïèèÈápöïß ÎÏÏ·´´´°°hmm¶,--­ŽŽ{{{*•úðáÃððp„‡ noo·µµuttÌÉÉá_XéààÐØØH¡P¼½½>|È_—œœìèèÕ?œ¿¯÷‘Ððn!”r!UHPRTT4àŽ6›mff–’’¢¦¦öµ¬sYYYHHHJJÊ€K?˜˜˜`£áñx‚/°Gb/ðx|~~¾‘‘ÑPùHKKc±âëúÚˆð“ÿöYgBLL̈®;üìÆŽ{ðàAˆðYˆÃ.|pÏWaêÔ©pÔð¹Àœ×ÂGá#€ð@øøUáß».\GGÇÖ­[ÛÛÛE̶¢¢"$$ä_»W9T-ÂÇ¿Juuµ››F»|ù²(qIDD•JõõõåOÄÒÖÖF"‘ôÿ—´´tuuµˆ¥ïÙ³§¸¸!ôäÉYYY}}}yyy}}}‰ÔÖÖ†-Ö××wøða6›-b¶ííí7oÞüÓ÷ÕîÝ»I$’®®®žžÞÂ… ?ï±;qâDGGÇǹ(R„#Æb±V­ZuàÀk×®eee=|øPøòiiiyyy®®®þþþØÀ¡””ÔéÓ§ ƒÁxò䉖––¼¼¼(¥×ÔÔdgg „ðxüÚµk ÆîÝ»±Ü¨T*^éI“&ñx<§·FÍ;777÷¯-,,òòò*++Ož<¹cÇŽW¯^}ÆÃwçÎ> ¬Ux¼““Srr240ÂÇ?ߣGètºªª*@ðôôÌÌÌD½{÷ŽL&kjjÖ××—””H$;;;ìQéçÎsqq322b³Ùuuu!lšA,Cƒ1wî\)))QJ÷ññ3f BHOOÏÏÏOðÓØØXiii„PBB6ÙØØˆ}ÔØØèåååááaddºcÇ;;»ß~û ûÔÇÇGWW×ÄÄ„ŸU__ŸÏ®]»6mÚ4{öì;wvvvb577oÙ²eöìÙ~~~PTT,((eåUTT°qV—‘‘áääD¡P~þùç/^`ËôôôDDDXXX,\¸0-- ‡Ã-]ºôÊ•+òòò·oßFýòË/ŠŠŠ©©©Øò?^»v-™Lvww\ß~ûmÓ¦M3f̰µµÝ¸q#BˆÍf/X°àÆóçÏ×××§P(‚¬££cHHÈû÷ï¡>þÉšššÔÕÕ±× X04qâÄôôt%%¥ööö¶¶6vöìY<Ïãñrssù#‹ºººüó×|wïÞ¥Óé"–ž‘‘Ál¸¸¸¸œœœà§ŠŠŠØ WWWƒ!8g£¢¢¢¡¡¡¬¬ìÝ»w333¿ýöÛˆˆˆÀÀ@ìÓãÇ f%!!áääíååU\\¬££‹…wëÖ­sss+**Ú°aÃþýû;fjj:ìš÷ôôL"‘nÞ¼™œœŒÅ”çÎsppøÏþƒå³iӦÇó#ï}ûö–••>|899;9Îf³íìì|}}ËËË<ØðÿØ»÷x¨òÿqàïÑedº$IbËNS¨Y¡\]>JS(ê#·llm}T.»[¶R’M’D¤›¦ …¶Ö¥ÑÅä~¹ÍŒfæüþx?óð«È¶íÖn¯ç_ç¼Ïû¼ßç¼Ï½zŸ÷9™LNMM577ÏÊÊ*///,,<ñ£¼¼¼ššZEEüÆ€˜OkÖ™Áñ©©©ÅÆÆ®]»VNN.!!aòäÉÃçÇD"Ñ¥K—RSSGR]gggqqñs¿‰B¡,Y²dܸq zzz'N|õêÕ0ùÇçææ†£Õ¹sç^¸p!TVV¦¥¥¥­­ÒÐÐGrÃ322âóù]]]L&·ÌåË—ËË˯_¿Ž3´µµååå-_¾üòåË¥¥¥$i̘1nnn~~~Ã{ïÞ=&“)ž÷œÍf?~Ñ¢Ed2ÙÏÏÏßß_GGç‹/¾ˆŒŒÉAÎ;·ººZOO~f„’¢¢bvv6^nnnVWWoª®®VTTìîînmm•••Åñ¢±±q[[î|þü¹‹‹ËàÒž>}ª««+##3’ª¥¤¤¤¤¤8Î_‹$$$ðCyL(ޤœû÷ïËÊÊFDDœ?>$$„D"ihhxzzÎÆårñ{帺w¾`>uêTooo__ß×Ò ‚ðööîïïonn.**Z³fMFF†¤¤ä𥵷·ðBàoäã?¼¦Ñh©©© ýýýçÏŸ·²²ÂéYYY'Nœ¸pá¹sçÜÜÜž>}ŠÓétú¥K—D"QAAÁ˜1cTTT—öàÁƒ•+Wްj2™laaÑØØøOŸJ¥>þüáÇ|>¿¬¬ÌÓÓs„;Ž3ÆÓÓS$á®V''§ãÇ777#„:::"##Ÿ33³¿¿_çåå͘1~c„…B9{ö¬ŸŸŸ¥¥¥™™~Ö™››kmm]SSÃãñ8NMM¥¥eMM BÈÞÞ^JJÊÈÈ(66öèÑ£¯=¿nkkÉÀA±-[¶¤¤¤ˆW_¾|¹lÙ²OOO;;»™˜˜Ðh´¬¬,sssvïÞ½æææÐÐÐ~ø¿òã?"„ž={võêÕGÑh4##£’’fhhØÐÐÐÑѱk×®ÈÈȬ¬,‚ ¾ûî»øøøÂÂB2™|æÌ™ôôtKKËÄÄÄÇÀÙÙÙ+V¬(//'‘H¾¾¾>>>·oßž={vPPP@@€A@@€œœîÇõöö;v¬ƒƒÃÎ;ñ æØªU«JKKÕÕÕ7oÞ|¸páÂÁ}Éøg ùzî ‹èãrBI—“ÅãÞÞÄd2¿;òÏÀç󌌒’’¿öñ±ðx¼ýû÷[YYýY×›Dâñxd2ùÏ>ggç­[·~÷±œœœE‹áarA ^ÀCÚð‚„„Dvv¶¾¾þPåHKKãX±±¾&2âÔç>ë ™LŽŽŽ÷™},{öì¡Ñh&&&ÚÚÚK—.ý3ª¸wïFC999 mùg ÂÞÞ~áÂ…ð»þyFCˆ?Üó}÷Ýwö ‡Ë–-+,,ükN‡D"YZZ­ü#Áœ×ÂGá#€ð@øø·"~wýŒÁ`\»víÏ(Y À-@øøWc±XŽŽŽ¦¦¦7nÜI¼ihhèééÙÖÖöÇk?xð`~~>^8}ú´ÁòåËÃÃÃïß¿ÿœþï­ôÎ;?~3=<<¼§§ç­»TUU±X¬?ãàÅ­ÿ \.×ÙÙ9$$äçŸNMM}ôèÑðù¯^½ÚÛÛ{ÿþý7úúúþÁŽÃÊÊÊ´´4ñt,ÉÉÉmmmW¯^}þüyEEÅ_п·ÒŠŠŠ†††7Ó³²²º»»ßº‹———¿¿ÿŸqðVVV‡þÇwßà  -,,TTTÈd²““Ó­[·B¯^½ÒÖÖVSS«¯¯/(( P(VVVøc×qqq6l5j”¾¾>ŸÏ¯««Ãåtvv~÷Ýw†††Ë—/ ¹xñâHjõðð;v,^mhhÐÔÔ?~üĉýýýÅ_ðÎÌ̤ÓéT*uÓ¦Mååå!‘H´f͉´a âããfÍšUYYIƒÁ°³³£Ñh_ýuUUÕðÇ0T¥ÅÅÅ®®®ÚÚÚt:='''8p 00ÐÕÕ•J¥R©Ôôôt„ŸÏ_±bEzzº‰‰ •J¥Ñhµµµ8ww·‘‘‘ªªjHHˆ¸ÆÚÚZ—ÐÐÐõë×FGG‹ã¿’’GGGCCÃÐÐP:N£ÑZZZB>ôññÑÒÒ²´´Ü¹s§¸(Æáp à·|.|=wÁå°¹vLLLçÐÒÒÒˆ?ARRÒÅ‹ñruuµƒƒ^®¬¬444,))IKK³±±éèèÀsìHII à<ûöíËÏÏ'¢¿¿ãÆyyyB¡°»»ûàÁƒßÿýHjŸ7o^QQ‘xµ®®ÎÒÒ2 àúõë555âôæææÖÖV¡PÈb±ôõõq¢P(\¹reuu5>0{{{;^ºt)00°½½}`` ¢¢ÂÚÚº¥¥e˜cxk¥eeeöööuuuB¡°¥¥eçÎ999xÓÉ“'oß¾ýf9«W¯®««{k999ÁÁÁâU‘HtäÈkkë¶¶¶þþ~OOÏ_ý·ÿêÕ«›šš„BáÝ»wBåååAðxŸÏçñx\.—Ãáp8œÞÞÞžž6›––6L(ŽYÏÊ|=w|Z³ÎH$ñ²ššZllìÚµkåää&Ož>>ÿùÏLMMB/^¼ˆ‹‹c±XªªªL&óÿzn%$¶oß~ýúuŸòòr555„ÐåË—ËË˯_¿Ž³µµµååå 3™ø[+½wï“ÉïÅf³Çÿ¡¦&‘H eûöíÿú׿BºººÍÍÍ¡ŒŒ ''§)S¦ „LMMíííq~2™ìçççïﯣ£óÅ_DFF.MEEåCðññÃGEEÅììl¼ÜÜܬ®®.ÞT]]­¨¨ØÝÝÝÚÚ*++‹ãccã¶¶6%%%5º¸¸ „„Bá¨Q£Ä;Ž;VYYùUKIIIIIq8¼JĹsçœÕÕÕÕÕÕ§M›vüøqSSÓ’’’¸¸¸½{÷*))±Ù옘q _}õUPP‹‹KrròæÍ›q¢†††§§§±±ñHN¨J§Nêíííëëû×ëâ€xðtØâe‚ ¼½½ûûû›››‹ŠŠÖ¬Y“‘‘!))‰·öôôÈËËÃo øL|ü±4-55µ¡¡¡¿¿ÿüùóVVV8=++ëĉ.\8w›ÛÓ§Oq:N¿té’H$*((3fŒŠŠ BhöìÙAðùü»wï¾³j2™laaÑØØˆWûûû·nÝzíÚ5×ÓÓsëÖ-]]]„PMMÍŒ3”••y$_Ï¡a}\B(érò0Cô˜L¦¹¹ù?ìüù|¾‘‘QRRÒôéÓán¬³³ÓÆÆæêÕ«Ã?˜Ž‰‰ár¹îîîÐbÀ§&''gÑ¢Ex4~wV¼€?º‚$$$²³³õõõ‡*GZZÇŠõ5‘§FæÍJ&“£££qG@q8œ5kÖ´´´())9räƒÕÔÔðÓv|&FCP©Th1 …’šš:òüðØøÜ@¯€ð@ø |>þ­ˆß]ÿ¸BCC‹‹‹G˜¹§§ÇÏϯ³³s„ù Ƶk×þ1—L À} |Öá#‹Årtt455½qãÆ{R]]íëë«££C§ÓËËËG¾ãÁƒóóóñ2Ç;sæÌòåËMLLN:uäÈ‘Y^»vMAAá—_~*Ã/¿üÒÑÑ18%))‰J¥R(”¦¦¦×2 9r„ÏçN ïééykáUUU,ëÃ^5>ŸonnN¡P¨Tª¦¦¦››[mmíû5Ì™¾U`` ø’à³ ¹\®³³sHHÈÏ?ÿœššúèÑ£÷+§¨¨ÈÉÉ©°°ðÀŽŽŽ\.w${UVV¦¥¥éèèàÕHJJ2Œ”” …âçç÷¡ÂG;;;??¿a2ܺu뫯¾œ²~ýúòòò·~ª]VV– EEÅÁ‰YYYÝÝÝo-ÜËËËßßÿÃ^82™œ §§W^^þäÉggç-[¶ ¼GQÜé[YYY>|øSè3 |ü -,,TTTÈd²““Ó­[·B¯^½ÒÖÖVSS«¯¯/(( P(VVVøSéÅÅÅ®®®ÚÚÚt:=''G\޽½ýœ9s$$$eddpæwŠõðð;v,B¨ººº¶¶vÓ¦M’’’&L Óé111ø‹â™™™t:J¥nÚ´ wmr¹\“%K–œ?ÞÜÜÜÜÜüâÅ‹ø¡*AQQQVVVZZZ~~~ƒû+++wíÚ¥¯¯ïããS__KJJ¨Tª‚‚Â;wFrÌñññ¯õÕñùü+V¤§§›˜˜P©T&îìîî622RUU \HSSÓþýûõõõmllŃkkkƒ‚‚ LLLÌÍÍ{{{GrH$I___JJ Ÿ,‡Ã9}ú´©©é’%K~üñÇ®®.„Ð7ß|C¡Pâãã×­[·hÑ¢ï¿ÿ§¿AkÖ¬‘““ËÌÌD%&&JKK:to¥Ñh§  ~ÀÀç>677«ªªâeEEEüŒuòäÉׯ_Ÿ:ujgggGG‡©©é… $$$ÊË˃‚‚öïßÿÛo¿9r$11177W\T__Ÿ§§ç²eËvïÞ=~üø‘ÔÎ`0ÄŸ ¯®®ÖÕÕÅ“h#„$$$¶lÙ‚—©TjhhèãÇ\\\BRRRIIIÙÙÙ"‘ˆÁ`\¿~½µµ5::ÇRË—/¿xñbIIÉâÅ‹###ÅÕ>|ØÓÓóáÇ®®®®®®8~ÒÖÖ.//ß¿ÿ[lãÆ¯õÕ‘ÉäÔÔTss󬬬òòòÂÂBñŒ“&Mºÿ~BBÂàzzzœœœììì²³³ãââØlöO?ý„7ëèèäææ&''“H$7’CêêêJMM0aîݳg‚‚BJJÊÝ»w,Xàáá! ¿ÿþûùóççääDEE=xð@GGÇËËk¨(ŸD"EDDP©T<Ó÷Ê•+,X XºtiQQü€€¿Þ§5ëŒ8tC©©©ÅÆÆ®]»VNN.!!aòäÉ¡{÷î1™LñÄÜl6{üøñ‹-Â«ãÆ ,**ŠŠŠZºt)…B¾ºÎÎÎââbqíB¡ð­9_¼xÇb±TUU™L¦8]]]}Ë–-cǎݾ}»«««P(ÌËËKIIéèè‘‘QVVç Á±²¦¦¦­­m^^ÞŠ+þúv.++c2™[·nÅ«€ÇãíØ±CBBÂÞÞþرcùùùjjjaaaÿú׿†/*??ŸJ¥¶··Ï›7ïòåË8”l ^WW'‰êëë333ûûû‡Ê9sæLMMÍ+W®@PPP†êêêZºtiKK‹ŠŠŠŽŽŽººúË—/GRµ¬¬ìÑ£G#""ª««%$$:Îáp‚¨®®f³Ù!ÜÖÖÆãñRRR”••_{ûç5222[¶lY³fÍÎ;ÉdòàM,köìÙð>Çð‘B¡œ={ÖÏÏÏÒÒÒÌÌLOO!”››kmm]SSÃãñ8NMM¥¥eMMÍ„ ’““—,Y²uëÖÆÆF<6nܸqòòò>>>ºººßÿý¡C‡?2Æ–-[wk¹ººÎš5ËÙÙÙØØ8###99YJJÊÜÜ\(êéé988Lœ8gÃù'Ož¼eËWW×9sæØÛÛ#„ÜÝݯ_¿®««»gÏžÙ³gÇÇÇŸ;wîÆ?þø£™™YPPÐÂ… OŸ>}êÔ)ü×ÕÕ•F£ýðÃîîî4íØ±c¡ŽŽ–••ennN£ÑîÝ»7L:Bh÷îÝQQQ4íСCMMM¸g1&&†F£999…‡‡Óh´õë× ‰ØÙÙiiiikk›‘‘±råJ„ШQ£&L˜àææ6g·õë×/\¸p¨¦ãóùt:=??ߢ··wüøñ°°°¨¬¬´³³[¸páæÍ›MLL¢¢¢–,Y‚‡¢JJJÚØØ|ûí·¶¶¶ ‡"‘HÜB諯¾7nÜk/ewttܸqÃÈÈ~ÀÀ_äë¹#4,¢ËA%]N+|“Éù§Uþ.ø|¾‘‘QRR’ø]“‘{ùò¥££czz:ÜF#„ßOçxÊÁÂÂÂfÏžýÚÃårÝÝÝ¡I€aäää,Z´#bð}‡$$$²³³õõõ‡*GZZÇŠõ5‘§>÷YgÈdrttô{ŒAär¹›6mÊÎΦÑh#Ÿ-æs¶oß¾ììl“×èÅÇLJF£íÝ»744ôµï©©©ÑéthR࣠M þpÏï"%%•––­7rAAAAAA#Ïâ¿<¶>"˜ó@ø |>ÿVÄï®\¡¡¡#ƒ»§§ÇÏϯ³³s„ù Ƶk×>ÛK,à>þQá#‹Årtt455½qãÆHòóùüÐÐÐ Ðh4œX]]íëë«££C§ÓËËËG^ûÁƒóóóñ2Ç;sæÌòåËMLLN:uäÈ‘Y^»vMAAá—_~*Ã/¿üÒÑÑ18%))‰J¥R(”¦¦¦×2 9r„ÏçN ïééykáUUU,ëÃ^5>ŸonnN¡P¨Tª¦¦¦››[mmíG¼‹ø|þ?üðfzmm­‹‹ËàÉð÷¹\®³³sHHÈÏ?ÿœššúèÑ£wî’™™)‰˜Lfaaapp0N,**rrr*,,}út¡P˜——¿và>ZXX¨¨¨Éd''§[·n!„^½z¥­­­¦¦V___PP@¡P¬¬¬p’››Ûñãǵ´´ôõõÛÚÚp9ööösæÌ‘PTT”‘‘aoSll¬‡‡ÇرcBÕÕÕµµµ›6m’””œ0aN‰‰Á_ÏÌ̤ÓéT*uÓ¦M¸k“Ë嚘˜,Y²äüùóæææx>ü” ˆ¨¨(+++---??¿Á}Š•••»víÒ××÷ññ©¯¯Ç‰%%%T*UAAáÎ;#9æøøø×z%ù|þŠ+ÒÓÓMLL¨T*Fwvww©ªª†„„ .¤©©iÿþýúúú666‰‰‰âÇ»µµµAAA&&&æææ¯}¯{($I___JJ Ÿ,‡Ã9}ú´©©é’%K~üñÇ®®.œ­­­mß¾}úúút:ýܹsÒÒÒaaa ¥¥¥E(®Y³FZZúùóç¸ †Fûú믫ªªÄÕ=|øÐÇÇGKKËÒÒrçΡ/^Q©T*•ºjÕªÁ¬‹‹Ë©S§à×|¾ž;‚àrØ\;&&¦shiiiÄŸ ))éâÅ‹x¹ººÚÁÁ/WVV–””¤¥¥ÙØØtttˆw¹|ù²x—Á¸\®‡‡‡žžÞíÛ·GXû¼yóŠŠŠðrffæáÇߚ­¹¹¹µµU(²X,}}}œˆ#×èèh>ŸÏápBCC###Å'ÒÙÙ) oܸ„CCC¿øâ‹êêj‘HôäÉ ‹ÎÎNq'OžLOO³êÕ«W766Ž$}õêÕuuuo=þœœœàà`ñjww·™™YQQQWWWTTTxx8Þ´mÛ¶[·n …Âöövssó¶¶¶aZ¯½½ÝØØ˜ ˆÎÎÎÛ·o¯_¿§{xx\½z•Íf÷õõÝ¿ßÑÑQ ôõõ­Zµ*??_(¶¶¶ÚØØ¸¸¸àü–––ÍÍÍxyÇŽÏž=#âÒ¥KíííÖÖÖ---AðxoÞ<ü츫«ëäÉ“¿þú«x\AeeeMMMWWל9s,X€’——ß³gOttô0%_¾|¹¼¼üúõëâžË¼¼<[[[2™ìçççïﯣ£óÅ_DFF¾ó|ñY444hjjÂÿ€?èã‡ŠŠŠÙÙÙx¹¹¹Y]]]¼©ººZQQ±»»»µµUVVv$¥Mš4iÙ²eeee=266>³”””””‡ÃÁ«³fÍ:vì˜P(5jNáp8 ¥¤¤$..nïÞ½JJJl6;&&F\‚P(މDÒÒÒ$)>>žÍf‡……ÉÉÉ1™Ì+W®ˆóž\[BBâ=æÚþ äåå oÞ¼ùæ·´´ÔÔÔlذ!11QCCc˜¢ôôôîÝ»×ÑѱgÏž¬¬¬Õ«WOœ8ñË/¿LKKÇåØo¿ý68:ç R OOÏ7/"AÞÞÞýýýÍÍÍEEEkÖ¬ÉÈÈ””¦¨¾¾>|oÀøã>þØG–ššÚÐÐÐßßþüy+++œž••uâĉ .œ;wÎÍÍíéÓ§ÃÂårãââ^¾|‰ŸzÿòË/ƒÃСÉd üd!¤¤¤diiyâÄ 6›-²³³-,,¸\nMMÍŒ3”••y<^||üફ«úé'6›»Ü¼¼¼BÏŸ?WWW———omm}-ÿñãÇëëë ‚¨¨¨`06¯««‰Dõõõ™™™ýýýCåœ9s¦¦¦æ•+WpovAAAXXB¨««kéÒ¥---***:::êêê/_¾IÕ²²²Gˆˆ¨®®–8tèPxx8‡ÃÁÏñƒƒƒÙlö—_~YYY™Íçóëëë8 Ž §NZ__?00›››““ƒœœŽ?ÞÜÜŒêè舌Œ|òä B(//ÏÝÝ uuu==½ÖÖVŽ7®³³Sü°[üüß’3f¼ö¦ÞÏÇï}¤P(gÏžõóó{ùòåŽ;ôôôB¹¹¹ÖÖÖêêê<ÃáÔÔÔXZZfee)++oܸñÑ£G"‘èèÑ£S¦L¹|ù²””Ô¸qãäåå}||ÊËËçÏŸèСÁŒ‡±eË–””q—««kjjª³³sSS“©©irr²”””¹¹yYY™žžÞ”)SÖ­[‡³9s!dll.!”t9ÙÖÖv¨¬L&ó­‘ù[ãóùFFFIIIÓ§Oÿ½û¾|ùÒÑÑ1==n£÷ðüùóÐÐШ¨¨?»¢ÞÞ^ƒŒpüð‘““³hÑ"ü9‚ /àg€xABB";;[__¨r¤¥¥q¬ØX_qêsï!“ÉÑÑÑïÑ/Åår7mÚ”M£ÑF>[ ÀŽ;fggwýúõ¿à{: ** bGàC M@¥Rßc/))©´´4h½÷ããããããó×Ô%##³hÑ"hsàCÑ`ÂGá#€ð@ø |L XYYIKK»¸¸ „¸\®©©)‰Dúæ›oBmmmúúúvvvññññññ|>ßÜÜœB¡P©T---ww÷šššaÊg0 ªªªT*•J¥jjj’H$@ð‡ÞÓÓó·¸ííí ,ضmÜ—ø§…£GNHHÐÐЈŒŒDIII]ºtÉÂÂâ»ï¾ãr¹t:}ÅŠ999‘‘‘EEEL&“L&'$$èéé•———””8;;;::3«žµµõÞ½{£££Ëÿç½Ï0++«»»ûoq1äää.^¼7%þá#Bhâĉfffx5##cË–-$)33ÓÖÖÖÀÀ`ôèÑòòò{öì±°°øÿª” Ñh ¥µµõµtwwÇÆÆJHHüöÛo£GF»ººjkkÓétñüÈ¡ÌÌL:N¥R7mÚ„ÃM>Ÿ¿bÅŠôôt*•J£ÑjkkB,kÖ¬Y?üðBèÞ½{jjj»víÂ…„……)))ÅÅÅÅÄĘ˜˜àù”‡ªt(/^¼ðôôÔÑÑY¿~½¿¿II BH$1 ;;;CCÃÐÐÐÞÞ^œ¹££wÖºººþöÛoâB†ª´¶¶6((ÈÀÀÀÄÄÄÜÜ\\BèöíÛ†††ðs|Šá#BÈÚÚúæÍ›80Š555E=}útÖ¬YâjhhŒ3fãÆâ'Ñ£G¯©©±¶¶¶µµÁÁÁ|>ŸN§çççÓh4—×úáÞôóÏ?‡††nß¾F£=|øPœ>a„„„„äää%K–lݺµ±±qñâÅ!sss¡P¨§§çàà0qâD„««+Þe÷îÝQQQ4íСCMMM¸sNKKKKKK[[[__ÿÕ«W.\ÈÏÏkÖ¬ùöÛoýýýi4ÚªU«ð°Â¡*ŠŠŠJppp``à‚ œœœ¤¤¤,--BëÖ­£R©Ë–-c2™'Nœ=z4™LŽˆˆHIIY¼xïüÅ IDATñ7ß|³fÍš7nœ:uj¨JG5aÂ77·9sæ888¬_¿~á…⪥¥¥gΜ)%%w6þ$$_Ï¡a}\B(ér²x°Ý›˜L¦¹¹94ÀßBNN΢E‹D"Bˆ ˆÁ ¸//HHHdggëëëUŽ´´4Žëk"#NÁ89ð;@ø |>„ÂGðw'~K|j4GäÅ‹³fÍRPP þ´´ôãÇߣ¨;wî¼ßŽ%‹åèèhjjzãÆ‘„‘‘‘†††žžžmmmâô¶¶6???öõ×_·´´Œ¼öƒæçç#„¾ùæ …‚§±ÉÉÉÑÐЖ–þçª ïééùƒ…”••iii)((ܹsçƒaoo¯‰‰‰ªªjHHÈ)'00_ÂÇwPWW?{öì®]»Êÿ‡N§¿_QxžÀO—Ëuvv ùùçŸSSS=z4|þ«W¯öööÞ¿ãÆ¾¾¾âÏ{nß¾ÝÎÎîáǶ¶¶®®®#ìP¬¬¬LKKÓÑÑA}ÿý÷ÚÚÚ666===‹/¾uëÖ† †ŸJç£ÈÊÊêîîþƒ…Ì™3çñãÇû÷ïÿ3Žp„ YYY °++«Ã‡Cß0Ÿ°°0@àî¡jjjÚ¿¿¾¾¾Mbb¢øé^ff&N§R©›6m*//lj tuuÅ]˜ééé!>Ÿonn¾lÙ2„PCC H$Îÿþ}555Ÿ¬¬,;;»mÛ¶ÕÖÖS)BèùóçFFFIIIï}‚………***d2ÙÉÉéÖ­[¡W¯^ikk«©©Õ××P(+++üQø¸¸¸ 6Œ5J__ŸÏç×ÕÕ!„‚ 4003fÌâÅ‹kkkÙlöHjõðð;v¬8î9räHLLÌkÙŠ‹‹]]]µµµét:îljjÒÐÐX°`A{{;B¨¼¼\UUuÙ²e|>˜êîß¿ïàà ££ãáááêêÊáppajjºbÅŠ¤¤$¡PˆºwïN [¾|ùŠ+AQQQVVVZZZ~~~ÔÃ`0233BÇŽSRRJNNªy1Æáp àO€¿_ÏAp9l.‡Ó9´´´4âOðàÁƒ)S¦èêê"„Øl6Nìîî633+**êïïïêêŠŠŠ Ç›š››[[[…B!‹ÅÒ××—sòäÉÛ·o¿Vx{{»±±1^ÀáVZZ:iÒ$ÿW¯^UUUÕ××S)AEEES¦L9yòä{ŸiRRÒÅ‹ñruuµƒƒ^®¬¬444,))IKK³±±éèèÀ³ III à<ûöíËÏÏ­À‹/ްöyóæ‰WÍÌÌêëë---«««Ÿ={¶cÇ‚ ÊÊÊìííëêê„BaKKËÎ;srr‚ˆŒŒLKKkkk 8zôhVVÖ0uýú믻víêì쥥¥ÊÊÊÍÍÍ"‘ÈÛÛ;%%¥¿¿ŸÃáœ8qâÌ™3Aô÷÷[[[ôõõ½zõJ__¿½½—³zõ꺺º7ËÇ—ÒÎÎîÅ‹¥¥¥A$&&†„„°ÙìÌÌLggg@0øöHOOg+µ¶¶ö÷÷ÑÑѱxñb¼Œ/Ygg§P(¼qãFPPÐà½rrr‚ƒƒ§?~<##C|™._¾ŸÏçñx\.—Ãáp8œÞÞÞžž6›––6L(ŽYÏÊ|=wŒþBX///;;»Ñ£ÿïxÊÊʘLæÖ­[ñª@ àñx;vìxñâE\\‹ÅRUUe2™¤^› „PnnîP•"„tttªªª$%%?È)‹ûABjjj±±±k×®•““KHH˜—Ëõòò266f2™kÖ¬¦ºK—.y{{KKK#„´´´{ý]äää—?T¥bC¥¢¢bvv6^nnnVWWoª®®VTTìîînmmÅ‘‰D266nkkSRRB=þÜÅÅg !“ÉAAAâ€{xRRRRRRø ò`úúú‰‰‰xuêÔ©ÞÞÞ¾¾¾¯eÓÐÐ8qâDYYY@@À­[·JJJ¦N:LuýýýƒÛjÆŒo ‚ßXÇŽƒCêr±þýï>|xñâÅgΜ¹zõ*NŒg³ÙaaarrrL&óÊ•+ïQòPÍ‹õôôÈËËß$Ÿ¾Ohì£8vDÍœ9SSSóÊ•+¸»µ   ,, !TSS3cÆ eee?xw™êêj‘HÔÑÑ‘_U¦P( ]]]çÿäU©8r9sæéÓ§ßûi4ZjjjCCCÿùóç­¬¬pzVVÖ‰'.\¸pîÜ977·§OŸât:~éÒ%‘HTPP0fÌ„Poo¯‡‡‡²²²¿¿ÿèÑ£ ÆHÞM&“ÉonÚµk—‡‡mijjšššŠŸs¹\ƒßΖ——ONNÎËËóòòúöÛo¿úê«áƒ³µkמ9s¦§§‡ ˆÆÆÆýû÷?yòdêÔ© ·nÝ|>?**jçθoo˜€»®®N$Õ××gffö÷÷tîÚµëÔ©S\.W$Ý¿¿³³¢ý½¨TjÿéÓ§—-[&''‡Ÿ?®®®.//ßÚÚúÚ÷V“'OÆw#‹ÅÂm8Lób,köìÙð' „ïPYY¹}ûö°°0vöìÙÁÑ@```gg§¥¥¥­­mFFÆÊ•+BæææB¡POOÏÁÁaâĉ!WWW¼ËªU«šššh4ÚŽ;=z„»å$%%#""¬¬¬444ð“n\Ë‘#GÖ­[O£Ñôõõ_¼x1L¥˜¤¤¤ªªê[Ÿ,…B9{ö¬ŸŸŸ¥¥¥™™™žžB(77×ÚÚº¦¦†Çãq8œššKKËšš„½½½”””‘‘QllìÑ£Gq·\aaáO?ý1þ|æääÔÚÚ:’Ú·lÙ’’’‚—oÞ¼™mfföôéÓiÓ¦>}‡ƒ&LHHHHNN^²dÉÖ­[ñëØ$iÏž=222>>>x ê0ÌÌÌLLLœœœôôôLLL455I$Rpppmm­™™™­­­´´ô¶mÛB111ééé^^^ 77÷úõë¡¡¡¸œÝ»wGEEÑh´C‡555áƒÌÈÈX°`Çi4~ !´nÝ:*•êàà°lÙ2&“yâÄ |¸ººÒh´~øÁÝÝF£;vìmµuëVOOϵk׊SÜÝݯ_¿®««»gÏžÙ³gÇÇÇŸ;w<¾ ááá4mýúõøu«U«V•––ª««oÞ¼yìØ±AAAíííC5/B¨££ãÆFFFð' À§äë¹#4,¢ËA%]NÌz“É477‡&û›âóùøÍñéÓ§Ck|jbbb¸\®»»;4€(''gÑ¢Eø#~1W¼ þ AÙÙÙúúúC•#--cÅÆúšÈˆS£¡e?d29::úß55µwöéŸ?#T*áÓ­ü@_€ð@ø |>‚¿„ø­û?)?ƒáOZ9||ñâŬY³¨ÿ#--ýøñã÷(êÎ;ï·ã_‰Åb9::šššÞ¸qc$ÿZGFFzzzâItËÍÍ5jTZZÚÈk?xð`~~>BˆÁ`(((¨ªªR©TCCà .¼wX>’io>¸ÖÖV///mmmƒ¤¤¤¿Ý “ŸŸ?mÚ´ØØØwæ,..^·n¶¶¶‰‰IIIÉ{Ô•””D¥R)JSSÓ{_;‘HdeeõòåKø£ à#‡êêêgϞݵkWùÿÐéô÷+ª¢¢¢¡¡áSnk.—ëììòóÏ?§¦¦>zôhøüW¯^ííí½ÿþÆ}}}Gx</00ÐÛÛ{äµWVV¦¥¥éèè „¬­­÷îÝ]^^~ëÖ­âââÔÔÔ÷;©¬¬¬îî1OŸ>meeU\\œ——7xz˜¿Ë £§§wôèÑ‘äܼyóñãÇKJJîÞ½;wîÜ÷¨kýúõåååo~óÿw]; ;;»ÄÄDø£ àzx&ÜÝÝñTÅMMMû÷ï×××·±±ILL?8ËÌ̤ÓéT*uÓ¦Mååå8ñÀ®®®¸ 3==!ÄçóÍÍÍ—-[†jhhX°`ž÷!tÿþ}555Ÿ¬¬,;;»mÛ¶ÕÖÖS)BèùóçxÖ–÷>ÁÂÂB 2™ìää„gÛ{õê•¶¶¶ššZ}}}AA…B±²²Â…‹‹Û°aèQ£ôõõù|~]]¸¨K—.9::~ñÅ#¯=66ÖÃÃcìØ±¯¥KKKÛÚÚ–––âÕââbWWWmmm:ž““#ÎöðáC---KKË;wâæ]±bEzzº‰‰ •J¥Ñh¸ B"‘ˆÁ`ØÙÙ†††öööŠ/±’’R\\\LLŒ‰‰I@@@__ß0•¾Uoo¯‰‰Ixx¸››Ûœ9sþýïãôîîîC‡-Y²D__?<<\|íâââV¬Xa``üõ×_uÃ`%%%...4m×®]â3jllÄ÷‹Årss³±±ÉÍÍmiiÑÔÔÔÔÔ¬¯¯Gy{{“H¤áñgÏž¹ººìÛ·OÜHn.öõ×_WUUáôÇkii•––~õÕWT*5<<ßÀo=SÜ£œ™™‰:v옒’RrròP‡1̵#âêÕ«ŽŽŽÚÚÚ666ƒûGmmm¿ûî»®®.ø» Ÿ;_ÏAp9l.‡Ó9´´´4âOðàÁƒ)S¦à)7Øl6Nìîî633+**êïïïêêŠŠŠ Ç›š››[[[…B!‹ÅÒ××—sòäÉÛ·o¿Vx{{»±±1^Àÿ:b¥¥¥“&Mò÷÷õêUUUU}}ý0•QTT4eÊ”“'O¾÷™&%%]¼x/WWW;88àåÊÊJCCÃ’’’´´4›ŽŽ<›””ÔÀÀγoß¾üü|¼ÜÐÐ`mmÍãñ"""Þ<å¡Ì›7¯¨¨H¼züøñŒŒ ¡PXQQñŸÿü'77— ˆ²²2{{ûºº:¡PØÒÒ²sçΜœ‚ x<ž¬¬lUU•H$*--]µj•¸œÕ«W×ÕÕ½VWbbbHH›ÍÈÌÌtvvxÓÅ‹eee/\¸Ð××WPPÀáp†ªtx>>>¥¥¥ƒSÁ‹/¸\nÿÿû_ñízüøñ˜˜Çãñ®_¿.¾ÞzÔ••9::655‰D¢gÏžY[[·µµ ¾ììì^¼xÑÙÙ‰kðàÁîÝ»q†ÂÂBñò[Õ×ׯZµ Ÿ)~n~þüy‚ .]ºØÞÞ>00PQQammÝÒÒ"Þ GÀ#<ÓŒŒ q;_¾|yð^«W¯nll|-åÍkW\\lffÆáp®\¹òã?Þºxñb&“Iø›ÈÎΉD@  ðù|>ŸÏãñ¸\.‡Ãáp8½½½===l6;--m˜ P+²ž•ùzîø$fñòòò÷÷·³³=úÿާ¬¬ŒÉdnݺ¯ ·cÇ ‰/^ÄÅűX,UUU&“ùGêµ±± ‘‘‘AåææU)BHGG§ªªJRRòƒœ²¸!¤¦¦»víZ99¹„„„É“'ŸÿÈ‘#û÷ï'“É#¯®³³³¸¸XAAap¢‹‹ ™L®¨¨¸råÊÂ… B÷îÝc2™âyÏÙlöøñã-ZD&“ýüüüýýutt¾øâ‹ÈÈÈaê"âØ±cwïÞ¥P(!“”””ŠŠ MMMœ!$$dÓ¦M!6L¥¿·I{{{oÞ¼™™™9zôh‡3g΄Pÿ™3g?~Œ/¢­­íðϯ]»æáá1eÊ„ЬY³6nܘ••µ~ýúÁ¸ãÇǽ¶¡Å‹‡‡‡?þü‹/¾ ûïÿ;LáwîÜqrrš6mBhΜ9aaa8ýòåËåååׯ_Ç«mmmyyyÃÌ>ÿÖ3ýPfΜ©¨¨¸{÷nuuõ9sælÛ¶mðÖ¹sçVWWëééÁ¼àsö MZ˜œœCŸÐØGq숻@455¯\¹‚»[ pWMMMÍŒ3”••y<^||ükAIuuµH$êèèÈÎÎÆ¯*S(”†††®®.‡såÊ•wö»¼µRqä:sæÌÓ§O¿÷ Òh´ÔÔÔ†††þþþóçÏ[YYáô¬¬¬'N\¸páܹsnnnOŸ>Åét:ýÒ¥K"‘¨  `̘1***ø4ů8p`ÿþýïŒBd2Ù¢±±ñÍMæææt:¿ÆajjšššŠËr¹\ƒÁ`0ByyyîîîA¨««ëééµ¶¶â1‹8&®««‰Dõõõ™™™ýýý$i×®]§Nâr¹"‘èþýûx<ë[ Ué#Ïž={„ OŸ>½zõ*N—””ܸqc||üÀÀ~dìîîÎår‡ºaìììNž<ÙÚÚŠª¬¬ŒÇcg‡±`Á‚îîn///q¿õPÌÌÌΟ?ß×a±Xâ7ŸœœœŽ?ÞÜÜŒêè舌Œ|òäÉï=S„ÐäÉ“ñ±X¬‘´á›×!õÓO??~öìÙâüB¡0//oÆŒðw>wwìã‹/¾üòK<ö1**j𦾾¾ÈÈH333KKËï¾û®¢¢'éêêZZZâAýÛ¶mÃù{{{¿ýöÛyóæ­]»öèÑ£x!AwîÜY¼xñ”)Sð¿Ö¸–ÇÏž=[^^^WWWOOÅb S)öìÙ3CCÃÄÄÄ?r¾Ïž=spp055½zõ*NÉÉÉ‘’’š;wnCCCQQ‘²²òŒ3ª««ñ`»ˆˆCCÃ;w¶¶¶¾VT@@€²²²¡¡aOOÏHª¾yó¦··7^¾uë–²²²ºº:'Ö­[HDkkë¾}û/^ìààpúôiÜŒEEEfff†††sæÌ¡Óéâb«ªª6oÞ.!”t9y˜WL&óÍo€¿ >ŸßŸ>}:´Æ$‰þýïÿøãxPã?˜³³óÖ­[ßcX*€%''gÑ¢Ex(îß/àÑYxABB";;[__¨r¤¥¥q¬ØX_qj4´ìg‚L&GGGÿÁá›`°žž{{û–––ªªªéÓ§9rä|²AØÛÛãW¬|æ |üŒP©Th„hâĉø¦Ï‰D²´´„‹Áœ×ÂGá#€ð@ø>Qâ·ôÁ߃Á¸víÚßúΜ9SWW—ò$ ¿ðñÅ‹³fÍRPP þ´´ôãÇߣ¨;wî¼ßŽ%‹åèèhjjzãÆ‘üeŒŒ444ôôôÄs¢`±±±Ó¦MÃÍõ»æú;xð`~~>ŽHTUU©Tª¡¡á… Þ;¬ ïééùë[²µµÕËËK[[ÛÀÀ ))éÓ¿a¸\®©©é{|9µªªŠÅb$ÊTPPÈÌÌüÔ~ W¯^Åso~(•••^HýÞ…çççO›6 Og0¼âââuëÖikk›˜˜”””¼G]IIIT*•B¡455½÷ï±¶¶ÖÅÅþN᣺ºúÙ³gwíÚ%žˆþÿØ;÷x¨òÿñ¿éÂÒE±n«r«…™u)³% -¦vl‘]„µ.‘ÊgÛîÊÖîVnaBŠ¢ …–\R²ˆ.31#w3Œ13ç÷Çûû9?1I}vÛÝ÷ó¯÷yŸ÷y½Îë}ÞgÎkÞï×9/'§É‰¢R©0ÜGËÀÀ€‹‹Kppð­[·²³³=z$º}zzzaa¡ƒƒC@@ÀH/44vשS§&þPÌÉÉÑ×רÚÚîÛ·/66¶®®.++«ªª*;;{rFôööþùeccSUUUVV¶iÓ¦ÀHII]¾|yîܹ300ð­Íà5ýo‹/úùùMú!¿Æb±jkkÿwÿL&'ÜÐÐ&ÿ|+ß|óMHHHuuõÝ»w—/_> ][¶l©««{óßÈ;Ý ,€‰(у@üÍÜÇ‘„††òù|///˜¹µµõÀFFFd29%%_dÉÏÏwrrÒÖÖÞ¾}{]]¬<|øpPP»»;œ“ËÍÍ YZZœŠÃÀÀ@LL ¶/,,TWW÷÷÷/(( P(nnn/_¾¡ðâÅ ˜µeÒ>~üØÊÊjþüùÎÎÎYYY€®®.]]]uuõ–––ŠŠ iii8””´mÛ¶)S¦ ½çò_BB‚ÏôéÓGÕËÈÈlܸ±¦¦Ÿqww×ÕÕurr*))Á›=xðÀßßÙ²eÖÖÖÞÞÞ°{ׯ_Ÿ››kff¦­­M$a„Baff&…B!‘H¿þúk?~‰•••“’’âããÍÌÌ:sg§tLúûûÍÌÌ"""<<Ÿ___?00Àãñ<ˆ×øøx.—Ëår¯_¿Ž‡1Lmm­££ckk«P(|þü¹­­m{{ûÈñC¡Pêëë»»»¡ö¢¢¢={öÀ?ÆËc#Ο??44ÄápNž<™””$B8žýøñã#å>|8%%exx¸££ã«¯¾òööÆ-µ··ïîîæñx^^^eee",e±X€›7oòùüªª*2™ ë}||ÒÓÓÙlöàà`aa¡££#¼vUUUgxx8--íÔ©S°}BB±cÇx<—ËÝ·oßï¿ÿ>RKHHȵk×ðM&“I¡Pššš„B!“É´µµÍËË1` ”””jkk…BaBBBhh(Þ'G޳“===uttîß¿ÏårñD§Ó»»»Á7Ž;†'7Ó"ÂÇÌÀ¾aÃ8za„À… 0 »|ùrPPPGGÇðð0•JµµµmkkÂÎñH9}}}ÍÍÍÃÃÃýýýkÖ¬ÁSÃû¿w`’ú‘wß«W¯FÕ¼y?Žg)†a¯^½ôõõ¡¼ÀÊyýN9¯?Ь3pyŽB¡à+\µµµååå;v쀛|>ŸËåzzzŠ‹‹×××'%%Ñh4UUÕòòò÷ÑK&“ƒƒƒÅÅÅçÌ™(--O)@__¿±±QRRòƒ˜ŒÏƒÔÕÕ6mÚ$''wéÒ¥¹sçŠn¿aÃcccUUÕÞÞ^www8_+‚îî*…‘•®®®T*5-- &£»wï^yy9ž÷œÍfϘ1cåÊ•{÷î Ô××_´hQtt´]†9sæîÝ»ÒÒÒ33³›7oR©Ô%K–ÀÁÁÁÛ·o‰DJßµKûûû322òóó§NÊápttt<ïܹsOž<qãÆ¢× ¯]»æã㣤¤X¼x±ƒƒCAAÁ–-[FNâΘ1ÎÚLLL"""^¼x±hÑ¢ÐÐЃŠ>I555gggqqñéÓ§{zzš™™988àw”ð1áp8iii555bbb²²²{öì¹&îââÕ××7 III===2™ ÐÒÒÊÈÈôôô„‡‡ß¿ÿøñã°YCCCSS“††††††¢¢âž={455uttÜÜÜ`ƒ•+Wz{{÷õõ©ªªÚØØŒÌ—ÚÕÕ•šš:23??ßÁÁf]WTTŒ•””1`>ùä˜-iùò剉‰ qqqðÜà\VVvóæÍÎÎÎ9s樨¨ÀfãYôNܹsÇÙÙ¦;×ÑÑ …õW®\©««»~ý:> [VV†ò7ioo?þü£G_¿~Íf³?à¬K?ýôS¸8ƒßž1>¢¤…W¯^2e ,ËËË“H¤ŒŒŒQ9š«««“’’öíÛ§¬¬Ìf³ãããßG£œœÜHùã)ýÿ+ýï—0ZQQ±¸¸–™L¦¦¦&¾‹N§+**ööö²X,YYYè/ššš¶··Ãw^¼xáêêŠ/7CA^^~ÕªU4í­î£”””””‡ÃY»víÚÜÜÜÈÈÈuëÖÍš5ë³Ï>óóó{óu Ãüüüx<“ɬ¬¬üúë¯óòòDxÒ£^ÄÕoÐYÇO黲gÏž-[¶¸¸¸HKKÇÄÄà šo:ë÷ìÅÄÄFÙÝ»‘¦DFF:::Λ7OCCC´p|„Cá#7ß>ÞéÁ7èáyŽzï?ù‘VŒÇ›ãyÖ¬YK—.ÍÉÉõO0}úô .tuuµµµ]¿~=??.ìΛ7ïöíÛ,«µµõÌ™3, w’ÒÒÒ|||>ùä\ŸÏ©ú.ø„ܘ'öNáVŒÜLNNf³Ù¡¡¡rrråååiii¢-zŸ¿‚¸± .ôõõ555à?//¯S§N{ö,==ŸcsppHNN†Ë‹^^^ã  …v’““aì¬ z{{wîÜ9‘§>œ;ær¹çÎóññ™¸W„ÿؾ};\ýg2™ÁÁÁo}k~LKÇs(=ÁápàšïñãÇáLXLLÌo¿ý6cÆ ---ccc*• qpp(--•——×ÖÖ&ø;:}}}qqqø ‡¬Y³æÂ… °M___lllzzú»ÀÌ™3©T*Çc³Ùüñ=&/^¼ÐÔÔ”——g±X#4Ƴè„[XXàÑh4???XïììÂd2ÑÑÑOŸ>OÈëׯ§L™¢¡¡!..þûï¿ß¿ß5wî\xíh4ÚDî‹7ïG–Âÿ±jjjŠŠŠèYˆ@ Þ¿6ö±¾¾~éÒ¥0ö1&&fä®ÁÁÁèèh kkëŸ~ú‰J¥ÂÊcÇŽkkkîææÛ÷÷÷ÿøãzzz›6m:}ú4Œ Ä0ìÎ;&&&JJJð—jùù矵´´äåå ‚¡¡!F¡òüùs‰”’’ò>ö>þÜÞÞÞÜÜ<==´’’’Z¾|9ƒÁ¨¬¬TQQQSS£Óé0.22’D"y{{³X,\È£GÜÝÝõôôœœœFÅÿ‰ ##ÃÏÏ–³²²TTT455a(ŸÏß¼ysPP ‰Û¿¿‰‰‰½½}TTìÆÊÊJ ‰¤££ãääTQQ‹mllüæ›oôôôvìØ‘˜˜#º„BaFF™L^µjÕÉ“'{{{¡9vvv ,PSS#d2yppÃ{S©ˆh3yyy---°ÿ~XÿðáC2™lhh¸{÷î~øAMM F‹ž;wÎÜÜÜÄÄä?ÿùÏÓ§OE˜ªª*gggCCÃ;w666ÂÊ»wïB7@ „ÌÌÌQ}{øðaÑýÏáp,--—.]eiiiii™šš*D‹‹#‹-‚7ÈæÍ›a÷r¹Ü˜˜+++ÄÄD8TTTôôô Æ“'OÔÔÔ´´´êëëdztÇŽRRR0 ¾yƒö„Bá­[·ìììLMMøá‡ÂÂB<âvÆ Ÿþ9@سgœ÷ý÷ßoذaùòå+V¬ ~'Œ‰Œ}³jkkÝÝÝ?ÿüs …réÒ%8Æ0+V¬PRRÊÏχ¯ÅÈËËñ' cccW¬XaaaqðàÁçÏŸcöòåË+VÈÊÊ.]º”@ àñ‹ ÃÃÃÞ/aaaòòòðÄÆ³hLá"xúô©«««‰‰É¾}ûNŸ>½`Á‚û÷ïcöäÉ777###//¯«W¯ ÁhNç­§§G ®_¿…\¾|™D"™ššž:ujÆ +V¬èèè€Qà>>>jjj+V¬Ø¾}ûòåË_¿~ÝÑѱfÍ0{öl€Ç@y?Žg)†aaaa##¼Š}œ`ì£X€¯ç¯¡‘ƒ@ê•«"¢sÊËË'ñÕ:ÄGÂÐÐ|sFž!>B¡pëÖ­§N‚p²êÔÔT&“¹k×®­[\\\NŸ>-"ˆñ—Óßßoll\TTfÄ?’’’’•+WÂH'ø/ÀÅ+X/..¿> è+¾jiŠŽ<‹²Îü[ˆ}ÏðMÄHúúúÖ­[§««{ëÖ­°°°?Suzz:‘H400€ßúù;'..ùŽ9|>?&&ùŽbLE]ðï¾ÁŠøPÌš5ëîÝ»‰j;;;;;;t ïÜ9s&ñ‰(ç5@ ¹@ ä>"@ ûˆ@ @î#â#K@ø|>êøû¹õõõ‹/VPPÐþ/222Ož<™„¨;wîLîÀ?æèèhnn~ãÆ‰<Û¢££I$’¯¯ï¨L! ++këÖ­_|ñÅ£G&¨ýÈ‘#>dff*((¨ªªjkk“H¤ÄÄÄI»•}}}~O²X¬;wêêꧦ¦þSÌáϱ´££ÃÀÀ`"™£ßÿÚÕÖÖ.[¶LAAáÎ;“¶T(ÚØØ¼~ý=âoæ>jjjž?~×®]uÿÅÉÉir¢¨T*ž0íãd``ÀÅÅ%88øÖ­[ÙÙÙouûÒÓÓûûû FzxgΜ©¨¨8}útQQ‘Hœˆö†††œœ}}}€­­í¾}ûbccëêê²²²ªªª²³³'gTAAAooïŸß™QQQ666UUUeee›6múG˜ÅŸc©œœÜÅ‹ÿœk§££óäÉ“¼¥âââ %%%=âoæ>Ž$44”Ïç{yyÁt·­­­022"“É)))ø2S~~¾“““¶¶ööíÛñt´‡ rww‡S˜¹¹¹€¡¡!KKK˜³˜Á`àù… ÕÕÕýýý (Š››ÛË—/E(¼xñfm™´?¶²²š?¾„„„³³sVV ««KWWW]]½¥¥¥¢¢BZZÚÆÆ~>))iÛ¶mS¦L122jnn†r*** ÆÁƒ•••ÅÄÄ&ø%ð„„ŸéÓ§ª—‘‘Ù¸qcMM ܬªªrww×ÕÕurr*))Á›=xðÀßßÙ²eÖÖÖÞÞÞ°{ׯ_Ÿ››kff¦­­M$aÂyÌÌL …B"‘~ýõ×þþ~ü+++'%%ÅÇÇ›™™:tæÎOé˜ô÷÷›™™EDDxxxèèèlݺÖ÷öö=zô‹/¾022ŠˆˆÀ¯ÝððpRRÒúõë?¾{÷îñ ¤ººÚÕÕ•H$îÚµ ·èÕ«WpüÀÏt“ÉäÒÒÒ¶¶¶%K–,Y²¤¥¥àçç'&&&Ú¯®®vtt„ÝâääD$ÛÚÚ0 ƒÝE$wïÞÝØØ(¢ãââìì윜œlllRSS׬YsôèQ.—;ÞèÏÒeQggç¡C‡ŒŒŒÜÝÝÿøã¼~ÌkúN׎F£-^¼øäÉ“€{÷î©««‹N®#âš¾9z!7nüé§ŸzzzГ@ Þ¿6ç5†aEEE0¥/€ÍfÃÊÞÞ^ ‹ÊÊJ×ÓÓƒ'fe2™,K Ðh4###\NxxøíÛ·G ïèè055…åááa¾«¦¦föìÙ]]]---"”¼ÏJJJááá“¶455õâÅ‹°L§Óííía¹¡¡D"UWWçääÉd˜’X(JIIÁ”µ†íß¿fpÆ0,666..î?ÿùÏW_}•••5Aízzz•••øfHHH^^ž@  R©ßÿ}ii)ÌGlgg×ÜÜ,ÚÚÚ¼½½KJJ`’eYYÙÆÆF¡PXSS³aÃ\ÎW_}ÕÜÜþÜÖÖ¶½½}äø¡P(õõõÝÝÝP{QQÑž={`ƒÇãå1¡Óé_}õUkk«@ €ß¯««ƒùŽƒ‚‚:::†‡‡©Tª­­-ô)ÇìÆžž))©êêê»wïš››wuu;v Î7zÇ´ôƒX444´yóæ‡ &“innîêê*b ½ëµ+**:qâ~Ãúûû<*<<<77wTÍ›–톙˜˜”——£¬¸å¼~§œ×EÖ™;wR(”©Sÿï|jkkËËËwìØ7ù|>—Ëõôô¯¯¯OJJ¢ÑhªªªåååL&‹‹‹Ï™3PZZ:žR€¾¾~cc£¤¤ä1Ÿ¨««'$$lÚ´INNîÒ¥KsçÎÝžÉdFGGß¹sGNNnß¾} Ÿþ¹huÝÝÝUUU #+]]]%$$¨TjZZÚŠ+àOyy9ž÷œÍfϘ1cåÊ•{÷î Ô××_´hQtt´]†9sæîÝ»ÒÒÒ33³›7oR©Ô%K–ÀÁÁÁÛ·oÀe÷ñ”¾k—ö÷÷gddäççO:•Ãáèèèx<Þ¹s瞢¤…W¯^2e ,ËËË“H¤ŒŒŒQ¿êêꤤ¤}ûö)++³Ùìøøø÷Ñ(''7RþxJÿÿJÿû%ŒVTT,..Æ]@MMM|NWTTìííe±X0­˜˜˜©©i{{»²²2\:wuu…UUUýõWèY[[?~üø­î£”””””‡ÃY»víÚÜÜÜÈÈÈuëÖÍš5ë³Ï>óóó xÓ#ôóóãñxL&³²²ò믿ÎËËáIzgT¿Agg<¥ïÊž={¶lÙâââ"--ƒ¯ÿ¾é¬Oܳe ô´Fšéèè8oÞ< ’ÅÅÅáùŒ<7ÀÂ… }}}MMMGõ¡ènÅ[Gïx¼E£ºKBBbr×tÌk÷¡=z;::F H@¼•(ö÷K–,IKKƒÓ­¡¡¡€¦¦&555.—›œœ<Ê)¡ÓéB¡°³³³¸¸¾ª,--Í`0zzz8NZZšèO)î¹jhhDEEMÚ@"‘˜Í`0x<Þ… lll`}AAAXXXbbb\\œ‡‡Ç³gÏ`½““ÓåË—…BaEEÅ´iÓæÏŸë­¬¬®_¿ÞÖÖÖßߟ——§««;‘ ++«W¯^½¹ËÒÒÒÉÉéôéÓpJ,;;., dfffffÊÊʼ¼¼0 ÓÔÔ444d±X0fúÄÍÍÍB¡°¥¥%??ŸÇ㉉‰íÚµëìÙ³B¡°°°°»»ƳŽÉxJßÕE(**ÒÒÒš9sæ³gÏÒÓÓa½¤¤¤ƒƒCrròðð°@ xò䉗—×ÀÀÀx†B¡„‡‡³X,@CCCrr2ŒAooïÎ;ñ™¿ñ°°°ˆ¥Óé\.733Ÿntvv a2™€ÎÎÎèèè§OŸ¾k7нcZúA,ÒÖÖ¦Ñh?Æ0¬³³ó§Ÿ~‚.ï;]Óñ®`öìÙ4Ïç¿~ýú­÷ïx–н ¬¬LMM = âÝøkcëëë—.] ccbbFîŒŽŽ¶°°°¶¶þé§Ÿ¨T*¬TRRª®®ŽŒŒ\µj›ÍoôŽi釲èõë×X±bÅŽ;’““eeeaÌå˜×ô]¯P( Yºt©ššš···¬¬,ŒStss#p „Ó§O‹°TÄè-..Þ´iü*@ ØÇ‰Ç>Šøzþ98À¤^¹Š‡+½Iyy¹¥¥%r¸ÿ¦ Á7Ç,X€zã" ·nÝzêÔ©yóæMü¨îîn2™œžž.//ÿϰè‹ËŽ;&h‹@ JJJV®\ Ã¥àßr¼×‹`A\\¼¸¸ØÈÈh<9222ÐW|ÕÒyv*êÙ ±±±ï¾‰I__Ÿ][[[ccã‚ ~ùå—·Âáp¾þúë¶¶6eeå_~ùåcó'aÑß ÃìììàKcx'ûø/B[[uÂdÖ¬Yðû;GZZzÒ_hÿ8-úû"&&fmm†1@L4…@ @î#@ ¹@ ä>"@ ûˆø(ÁßÒG |>u@ þ~îc}}ýâÅ‹´ÿ‹ŒŒÌ“'O&!êÎ;“;ðÏ„F£9::š››ß¸qc"O÷èèh‰äëë;2SHpp0‘HܱcF›¸ö#GŽ<|ø™™©   ªªª­­M"‘'íVFDDôõõ}Ì}^[[»lÙ2…;wîüO¹¸¸ˆ‰‰ ‰n644ô믿‰ÄÀÀÀI(êïï733SUU YßÐÐpíÚµ‰Ë ‚ã@ ˆ¿“û¨©©yþüù]»vÕý''§É‰¢R© ãcîë—ààà[·negg?zôHtûôôôþþþÂÂB‡€€ÜÃûå—_-ZôàÁƒÀÀÀmÛ¶áØDÓÐГ“£¯¯°µµÝ·o_lll]]]VVVUUÕ¤¿&SPPÐÛÛû1w»ŽŽÎ“'O8ð¿V7‘fùùùB¡°¼¼üñãÇÇŸ„¢™3g\ºtiT=‹Åª­­¸›ŸþMH#âoæ>Ž$44”Ïç{yyÁľ­­­022"“É)))øB[~~¾“““¶¶ööíÛëêê`åáǃ‚‚ÜÝÝáfnn.`hhÈÒÒæ,f0bbb°}aa¡ººº¿¿AA…Bqss{ùò¥¥€/^À¬-“6ðñãÇVVVóçÏ—pvvÎÊÊtuuéêꪫ«·´´TTTHKKÛØØÀÂ'%%mÛ¶mÊ”)FFFCCCÍÍÍPŽ@ ˜9sæ”)S¤¥¥G& MBB‚ÏôéÓGÕËÈÈlܸ±¦¦nVUU¹»»ëêê:99•””àͪ!555³gÏ ìêêjlllii¡fÎURR F®–Y IDATŸ´¥©©©/^„e:nooË $©ºº:''‡L&ÃD½B¡PJJ ¦Æ0lÿþý0 0†a]]]K—.UQQMP»žž^ee%¾’——'¨Tê÷ß_ZZŠaXmm­]ss³@ hkkóöö.))Á0ŒËåÊÊÊ666 …ššš 6àr¾úê«æææQºRRR‚ƒƒÙlöððp~~¾‹‹ ŸÏ‡».^¼(++›˜˜888XQQÁápÆS:L&“B¡455 …B&“ikk›——'Z)¹¹¹øfoo¯­­mMM@ `±Xîîîx÷ÂqB¡Pêëë»»»kjjDœÌÉ“'/\¸ÀãñØlö±cÇ\.Wô@ºrå > pètzww·@ ¸qãÆ±cÇð[ãĉøpõ÷÷yHIIÉñãÇGÕ9räÍ“tssËÊÊ–––íííø®àààèèh”@ PÎëwÊyýQdÙ¹sg`` …B™:õÿΧ¶¶¶¼¼|ÇŽp“Ïçs¹\OOOqqñúúú¤¤$¦ªªZ^^þ>zÉdrpp°¸¸øœ9s¥¥¥ã)èëë766JJJ~“ñyP€ººzBB¦M›äää.]º4wî\Ñí/\¸°gÏ …ÒÐГ“óæœâ(º»»«ªªFVºººJHHP©Ô´´4˜ºíÞ½{åååxÞs6›=cÆŒ•+WJHHìÝ»700P__Ñ¢EÑÑÑ"tavæÌ™»wïJKKÌÌÌnÞ¼I¥R—,Yoß¾Î~‰P:žüüü|˜¹[QQ166VRRò­JGQZZjmm½lÙ2€¼¼¼ŸŸßo¿ýf``0r²vÆŒpvv¼3HJJª®®Ÿ6mÚ÷ß¿ÿ~Ñ£wL9|>¿¬¬ìæÍ›sæÌ > vvvgΜyøð¡ººzhhè§Ÿ~Šïš?þ[ƒ(ÅG”´ðêÕ«øR¬¼¼<‰DÊÈÈõÄ­®®NJJÚ·oŸ²²2›ÍŽrrr#å§ç=F+**Ã2“ÉÔÔÔÄwÑétEEÅÞÞ^‹%++ ýESSÓööveeeÀ‹/\]]q÷ñ÷ߟ5k–¾¾þÂ… i4Ú[³JIIIIIq8œ‘•±±±k×®ÍÍÍŒŒ\·nݬY³>ûì3??¿€€€7=B???Çd2+++¿þúë¼¼<žô¨pºQýuœñ”ŽŸÏ):Cð?Ö;]¬‘ùÈ2úŽïôOwâß:F‘œœÌf³CCCåääÊËËÓÒÒ>ìejjjjjÚÖÖÖÔÔ´mÛ¶””èëëûØòn#âãç#Š}Ƨ¡¡±dÉ’´´48ÝZQQ hjjRSSSQQár¹ÉÉÉ£œ:. ;;;‹‹‹aT™´´4ƒÁèééáp8o}*§÷\544¢¢¢&m ‘HÌÎÎf0<ïÂ… 666°¾   ,,,111..ÎÃÃãÙ³g°ÞÉÉéòåËB¡°¢¢bÚ´ióçχõ¶¶¶¹¹¹CCCT*µºº¯„„„••Õ«W¯ÞÜeiiéäätúôi€¹¹yvv6\®ÈÌÌÌÌÌ”••yyya¦©©ihhÈb±ð÷u›››…BaKKK~~>ÇÛµk×Ù³g„Baaaaww7ÉxJÇcÍš5.\€¯IõõõÅÆÆ¦§§¿«Ò•+WfeeÕÕÕÁ`€ˆˆˆ­[·¾ë•’’rppHNN†ó‹111HoòâÅ MMMyyy‹5rTÏž=›F£ñùüׯ_Oħœ9s&•J…+éüñŒ îééYµjU[[Ûüùóõõõ555_¿~B£Ñ´´´Ðï @ Þ¿6ö±¾¾~éÒ¥0ö1&&fä®ÁÁÁèèh kkëŸ~ú‰J¥ÂÊcÇŽkkë„„€››lßßßÿã?êéémÚ´éôéÓ0‚ð;w˜())ùùù –ŸþYKKK^^ž@ Òh4J!ÏŸ?'‘H)))ïcïóçÏíííÍÍÍÓÓÓñx5))©åË—3ŒÊÊJ555:ƒð"##I$’··7‹ÅÂ…ôõõ?~üóÏ?wvv~þüùUgddøùùÁrVV–ŠŠŠ¦¦æ•+W0 ãóù›7o Â0ŒÅbíß¿ßÄÄÄÞÞ>** vcee¥……‰DÒÑÑqrrª¨¨ÀÅ666~óÍ7zzz;vìHLL„ÁšB¡0##ƒL&¯ZµêäÉ“½½½Ð;;» ¨©©2™<88…Œ©TµµµîîîŸþ9…B¹té”3¦RùG  ½áôéÓ°¾µµõ‡~X±bÅÖ­[ñhË»wïêéé@ÈÌÌ}&\.÷·ß~[³f|ÊÞÞ^ Œ9†‡‡7oÞ¬¦¦¶`Á8†9†a ÃÃÃCOOÏÉÉ),,L^^>66Z²téR555oooYYÙòòr Ãâââ¢E‹à³yóf¼ÛcccW¬XaaaqðàA86úúúÖ®]kii¹téÒ/¿ü2==~þF«©©utt Ø @±ïû(àëùkhäàzå*‚ö&ååå–––Èáþ›244߇QƒD||üÀÀ€——ê ø§RRR²råJøE8Ñ€`Ð,ˆ‹‹'GFFúНZš¢#ÏNE=û/ABB"66ö=Ã7ÿ$ÔÕÕáx'ûø/â­oØ þU¬^½u@ &š‹B @ ÷@ ÜG@ r@ È}D|8úûû‡††>ˆ(ü-ýÉQ[[ûÓO?ýûÏ磄@ Ä?Ä}¬¯¯_¼x±‚‚‚ö‘‘‘yòäÉ$Dݹsgrþ™Ðh4GGGssó7n¼µqqq±ŸŸß¼yó`‘ÎPtt4‰DòõõµK4GŽyøð! 33SAAAUUU[[›H$ž8qb``à­‡wwwß¹sg‚×ôäÉ“oîjhh¸víÚŸÜç/_¾tuu…_ºB ñ·w555ÏŸ?¿k×®ºÿâää49QT*&²ûhpqq ¾uëVvvö£GD·—°°°UŸžžÞßß_XXèàà0Á ņ††œœ}}}€­­í¾}ûbccëêêŽ$44”Ïç{yyÁTÅ­­­022"“É)))øúc~~¾“““¶¶ööíÛaV_Àáǃ‚‚ÜÝÝáfnn.`hhÈÒÒrÍš5ƒa`` &&Ûª««ûûûP(77·—/_ŠP xñâÌÚ2i?~lee5þ| ggg˜ã®««KWWW]]½¥¥¥¢¢BZZÚÆÆN•Ì›7?gœ¤¤¤mÛ¶M™2ÅÈÈhhh¨¹¹y"Ú|||¦OŸ>ª^(C-B¡pË–-222ÅÅÅG]½z5îVúøø,^¼xåÊ•#Å0ìæÍ›ëׯ·¶¶NMMÛ¶mtgŸ>}êëëkddtðàA6› ÈÌÌܶm[XX¼F'Nœ€BîÝ»çääºnݺõë×áÂ333) ‘Hܽ{wcc#®÷ÁƒþþþË–-³¶¶öööÆÛ§§§;::êêê’É䑱««ëÙ³gÑÝŽ@ ćá¯ÍyaXQQLÝ `³Ù°²··×¢²²’ÇãõôôÄÄÄDDDÀ]L&“Åb fdd„Ë ¿}ûö(ᦦ¦°<<< HMMÍìÙ³»ººZD(…yŸ•””ÂÃÃ'mijjêÅ‹a™N§ÛÛÛÃrCC‰Dª®®ÎÉÉ!“É£2>oÞ¼¹¹¹ß …RRR0Ç1†aû÷ïøðáD´ëééUVVâ›!!!0´¬¬ììÙ³GªðôôÔÑѹÿ>—ËÅ“AcÖÝݽbÅŠ‘2oݺµoß>6›ÍårO:ðšjiiÁLâñññ‘‘‘x‚ï#GŽŒ:1gkk{èСÁÁÁ®®.###˜…ùòåËAAAÃÃÃT*ÕÖÖ¶­­ ¦™–••mll …5556l€rªªª,,,8ÎððpZZÚ©S§p¯^½ôõõ¡ä§@9¯ß?çõG‘ufçÎ eêÔÿ;ŸÚÚÚòòò;vÀM>ŸÏår===ÅÅÅëëë“’’h4šªªjyyùûè%“ÉÁÁÁâââsæÌ”––ާ ¯¯ßØØ())ùAL9§¨®®ž°iÓ&99¹K—.Í;wrrDÐÝÝ]UU¥  0²2::zíÚµ|>Z§4Œ‹‹300ŒšnÅåË—=*-- gøð]ß|ó¦¦&`Ù²e¢§l§M›öÉ'Ÿ¸ººJJJJJJêèètttÈÊÊ^¹r¥®®îúõë°Y{{{YYÙÆ%$$öîݨ¯¯¿hÑ¢èèhØ@CCCQQqÏž=ššš:::nnn¸ŠO?ýÎ@/Y²ýcD â=ùˆ’^½zuÊ”)°,//O"‘222Fåh®®®NJJÚ·oŸ²²2›ÍŽrrr#å§ç=F+**Ã2“ɄބN§+**ööö²X,YYYÑþ¢©©i{{»²²2àÅ‹®®®oU-%%%%%ÅápÆS§š˜˜|öÙgt:]CCVΚ5k"M™2¼õn î×NÐÁ}óÀ… úúúšššŽj€a˜ŸŸÇc2™•••_ýu^^ž¤¤äôéÓ/\¸ÐÕÕÕÖÖvýúõüü||}|pp0{öltÃ#ñþ|D±¸ïÐÐÐX²dIZZœn­¨¨ 455©©©©¨¨p¹Üää䑇ϙ3‡N§ …ÂÎÎÎââbøJ²´´4ƒÁèééáp8iii¢O`<¥¸çª¡¡5i‰Dbvv6ƒÁàñx.\°±±õaaa‰‰‰qqqÏž=-ÇÉÉéòåËB¡°¢¢bÚ´ióçÏ«j +++¸†û&---ÕÕÕòòòïj‘££ãÙ³g»»»ûûûñY@Ìœ9“J¥òx<6›ýÇà¡«câììÂd2ÑÑÑOŸ>”••yyya¦©©ihhÈb± wóÛo¿Í˜1CKKËØØ˜J¥â¢˜L¦ššš¢¢"ºáxþâÙdž††ï¾û®»»ûÊ•+žžžøÂ±˜˜XPPPBB‚µµõ´iÓH$’ÀÒÒ²¶¶ÖÐÐPIIióæÍww÷sçÎ6lØpâÄ "‘¸páÂ+V,]º ))iccÓØØ¸eËÀùóçwìØñË/¿ÄÅÅuuuN:599YSSs<¥IIIUUÕwZY…´´ôùóç÷îÝûúõkOOOCCC@ii©­­­¦¦&—Ëåp8MMMÖÖÖªªª¾¾¾%%% OŸ>•‘‘¹r劒’ÀÎÎ.&&fõêÕzzz§OŸžàôÞ·ß~{óæM8™wëÖ­_ýURRrÖ¬YB¡pÞ¼yçÏŸŸ9sfssóÖ­[©Tjaa¡¤¤ä† <xôèÑwß}Ççóëëë‰Dâ'Ÿ|’’’¢¢¢bnn.¾ûî;€ƒƒTÔÞÞ¾k×®W¯^ÿçÏŸ›šš~ùå—:::fff¦¦¦3gÎ466Þ¶m >>>77wxxøÊ•+>„«Õ111ZZZÇŽ;tèPMMÍçŸnjj çk?ù䓿ææ/¿ü²§§‡@ ¤¤¤À؃3f\¿~=66V(®]»6<<·ýÎ;ï9yŒ@ âÿü´_Ï_C#8€Ô+W7nÜ8^ÓòòrKKKÔeS†††à›ã ,ø_ȯ©© ÌÎÎþØ ïïï766.**€@ Ä?’’’•+WÂ3ø.^€ág° ..^\\ldd4žè+¾jiŠŽ<;õì¿ ‰ØØØ>÷ìÙ3'''>ŸÿùçŸÃià >Ÿƒ|G@ >È}ü¡­­ýÁe.Y²ä­ß?ÿk™3gŽè÷Ç@¼( @ ÜG@ r@ È}D @ ÷ñáèïïú ¢ð·ôÿîðù|40ø—ºõõõ‹/VPPÐþ/222Ož<™„¨;wîLîÀ?æèèhnn~ãÆ·6...öóó›7oÌ ƒÓÞÞ¾wï^"‘¸{÷î¶¶¶‰k?räÈÇa™Ëåž;wnݺufffgÏžýå—_&çYFDDôõõýºk<áAAA¸!@ þ]¦æùóçwíÚU÷_œœœ&'ŠJ¥2Œ¹¯\\\‚ƒƒoݺ•ýÖïÝHHHXXXŒ¬ …ß}÷…ByðàÁÆÝÝÝ'èö544äääèëëÃÍÇKJJfffÞ¼ySZZzïÞ½“s z{{ÿG=6žp›ŸþùŸ1“Š@ r'Ohh(ŸÏ÷òòZ¸p! µµõÀFFFd29%%_¯ÌÏÏwrrÒÖÖÞ¾};ž4ùðáÃAAAîîîp 377044dii¹f̓Á000Àóûª««ûûûP(77·—/_ŠP xñâÌÚ2i?~lee5þ| gg第,@WW—®®®ººzKKKEE…´´´ ü(¼Á¼yóFå$Ä0,((ÈØØxÚ´i&&&/_¾d³ÙÑžàãã3}útNùòåöíÛ%%%gΜéää¿(Îd2üñG###GGÇÀc£¢¢¾ýöÛ3gÎûí·t:vïúõësssÍÌÌ´µµ‰D"ìCÝK¥Rýüüôõõ×­[wûömüÜ^¾|yìØ1ccc333KKK¸^?žp‘Häp8èF â/ À×ð{€ÃŽïŸœœì@QQ‘’’@°ÙlXÙÛÛkaaQYYÉãñzzzbbb"""à.&“Éb±F322Â儇‡ß¾}{”ðŽŽSSSX†î¤¦¦föìÙ]]]---"”bVYY©¤¤>iKSSS/^¼Ët:ÝÞÞ–H$RuuuNN™LîììyÔæÍ››››ÇxñâÅ    j×ÓÓ«¬¬„åüü|8{7ŠÞÞ^[[Ûšš@Àb±ÜÝÝ>|ˆa‹Åܼy“ÏçWUU‘Édü¯¾újÌÓ{³{1 ëëëknnîïï_³f ƒÁ€ÝÜܲ²²AGG‡¥¥e{{»há†GGGc@ Ƨ¸¸X(òù|>Ÿ?<<<44444Äår8‡Ãéïïïëëc³Ù999"œ@ÜW¤=¯ ðõü(²Îìܹ300B¡LúçS[[[^^¾cǸÉçó¹\®§§§¸¸x}}}RRFSUU-//½d2988X\\|Μ9€ÒÒÒñ”ôõõ%%%?ˆÉ#çÕÕÕ6mÚ$''wéÒ¥¹sç¾õp Ãbbb=:uÝÝÝUUU ¸v@ðf³ÒÒRkkëeË–äååýüü~ûí7III===2™ ÐÒÒÊÈȘD÷ÚÛÛÏŸ?ÿèÑ#EEÅׯ_ãó¦vvvgΜyøð¡ººzhhè§Ÿ~úVáóçÏÿÈ³Ý ñOå#JZxõêÕ)S¦À²¼¼<‰DÊÈÈ•£¹ºº:))iß¾}ÊÊÊl6;>>þ}4ÊÉÉ”?žRœ÷L­¨¨X\\ ËL&SSSßE§Ó{{{Y,Ö[³3KHH;v w¸E#%%%%%ÅápàæâŋϜ9#ðçp8ÒÒÒ£üÚ‘åIØ>ª{ûûû½¼¼N:uðàAqqqÜM˜ššššš¶µµ555mÛ¶-%%0ˆ ¯¯O^^ÝÀ@üù|D±¸+ÐÐÐX²dIZZœn­¨¨ 455©©©©¨¨p¹Üää䑇ϙ3‡N§ …ÂÎÎÎââbø¶²´´4ƒÁèééáp8iii¢O`<¥¸çª¡¡5i‰Dbvv6ƒÁàñx.\°±±õaaa‰‰‰qqqÏž=!¤¿¿ßÇÇGEE%00pêÔ©™™™yñYBBÂÊÊêÕ«WpSYYÙÚÚ:,,ŒÍfóùüââb++«•+WfeeÕÕÕaÖÕÕ±uëÖ·úÄÍÍÍB¡°¥¥%??ŸÇã×òõë×S¦LÑÐÐÿý÷ßïß¿ë{zzV­ZÕÖÖ6þ|}}}MMÍׯ_¿U8FÓÒÒB70@ ÿ:÷±¡¡á»ï¾ %‰çÏŸÇëÅÄÄ‚‚‚º»»­­­7nܘ——÷å—_,--¡¡¡½½ý¬Y³îîîð 6´¶¶‰DOOÏGÁi9IIÉÈÈH›… •n¨å—_~Ù¼ysrr2‘H422ª¯¯¡"))©ªª:‘•åñ––>þüÞ½{­­­-,, ¥¥¥¶¶¶MMM\.—Ãá455Y[[755|}}‰Dbnnî—_~ùÅ_0™LÀãÇûí·ÈÈÈÏ?ÿœH$:;;ÃÀÄ·òí·ßÞ¼yßtww_¼x±‹‹‹©©i^^ÞÕ«W¥¤¤fÍšõÛo¿%''›˜˜xyymÛ¶ÍØØðüùóÓ§Oâââ PΞ={bbbˆDâÑ£G[[[átã˜Ý«®®¾}ûöuëÖYYYÕÕÕééé9;;wvvN™2eæÌ™:::ööö[¶lY±b…á€ÎÎÎ7n¬^½ÝÀ@üùˆøzþ98À¤^¹ºqãÆñš–——[ZZ¢.û›244ß_°`ÁßÝ–øøø///tYAIIÉÊ•+á]0 Y€ß¿ƒqqñââb##£ñäÈÈÈ@_ñUKStäÙ©¨gÿ%HHHÄÆÆ¾gøæG‚ºº:|U@ ÄŸrÿEhkkÿ3 AËÖ@ü… œ×@ ä>"@ ûˆ@ @î#@ ¹ˆGÿÐÐИ»ð·î'È»¶G|´ðù|Ô ø—ºõõõ‹/VPPÐþ/222Ož<™„¨;wîLîÀ?æèèhnn~ãÆ·6...öóó›7oÌ 3ŠÒÒÒ)S¦äääL\û‘#G>|ËÃÃÃQQQÆÆÆëÖ­‹ˆˆ(,,}l@@ÀâÅ‹W®\ù>æ744\»víçg›™™©ªªÿ3nΡ¡¡“'OŽù7ÀÆÆÏ̓@ Ä‹I|Ôï/þp¦¦æùóçKKKa¯¯ïäDQ©T@°lÙ²ö𠏏¸$''+((øúú~öÙg"ÚKHH´¶¶¾¹‹Ëåùùù½“ë–““óã?ÂÍ«W¯¶··çåå …ÂüQBBBô×pN:uàÀ‘ix&‹Åª­­¥P(ÿ‹î9sfAAAiiéï¿ÿþϸɯ\¹‚ßÿÿ?Ÿ¸8…BIIIñññA?…AGGG^^ÞȼÐo‚aØ».N~D‹×¡¡¡|>ßËËkáÂ…€ÖÖÖ‘Éä””|µ.??ßÉÉI[[{ûöíuuu°òðáÃAAAîîîp 377044dii¹f̓Á000ƒí ÕÕÕýýý (Š››ÛË—/E(¼xñfm™´?¶²²š?¾„„„³³sVV ««KWWW]]½¥¥¥¢¢BZZÚÆÆ~ÞÀÀ`Þ¼yø9äòåËŽŽŽ‹-š¸ö„„ŸéÓ§ÃMƒ±dÉ’3fÌš5+00pÕªU°¾ªªÊÝÝ]WW×ÉÉ©¤¤D´L Ã233) ‘Hܽ{wcc#¾«°°ÐÞÞ^__ßÇÇÇÝÝÃádffnÛ¶-,, ^£'N¼õœëëë}}}õõõ·lÙX]] ë«««]]]‰Dâ®]»à…íµGFF𛛝_¿>55U „Bá–-[dddŠ‹‹=ºzõj< ã›<{öláÂ…{÷î=r䈱±ñÖ­[ñ„Ýï:^¾|yìØ1ccc333KKËþþþñº±¾¾~õêÕ•••°»6lØ0<<ŒŸÒÆúé§žžôˈ@ ̘1CCCc‰H´´´/^ünr|=1 à°8ìøøøîñÉÉÉÁþ)))Á$"l6VöööZXXTVVòx¼žžž˜˜˜ˆˆ¸‹Éd²X,@@£ÑŒŒŒp9ááá·oß%¼££ÃÔÔ–áÓßUSS3{öìÀÀÀ®®®ÆÆÆ––¨¯õK IDATJ1 «¬¬TRR Ÿ´¥©©©/^„e:nooË $©ºº:''‡L&wvvŽË—/§Óéø9 ñ§ñ%-¼zõ*¾6///O"‘222F…sVWW'%%íÛ·OYY™ÍfÇÇÇ¿F99¹‘òÇSŠóž £‹‹‹a™Édjjjâ»ètº¢¢boo/‹Å’••íÞ½{÷îÝ»€ŽŽ ‰4sæLѪ¥¤¤¤¤¤8ÜÄ0,..ÎÅÅESSSSSsÞ¼y!!!æææŸ}ö™ŸŸ_@@À-Z¸p¡¯¯¯©©é¨z7²¯ÔÔÔ&Ñ]|>¤èi½é|‹‰‰‰ŽØsõgÖ¬Y<¸ê  …3f̘Ä@255555mkkkjjÚ¶m[JJÊÂ… ÇëFÑttt@o@ ˆ?™(öqd\'\§OKKãóù|>¿¢¢"44ÐÔÔ¤¦¦¦¢¢Âår“““G>gÎ:. ;;;‹‹‹áÛÊÒÒÒ £§§‡Ãᤥ¥‰>ñ”âž«††FTTÔ¤ $‰ÙÙÙ ƒÇã]¸pÁÆÆÖ„……%&&ÆÅÅyxx<{öL„9sæÔý—Ç8pà­¾#@BBÂÊÊêÕ«W¸{·cÇŽk×®q¹Ü¾¾¾¬¬,<`nnž]SSƒaØÀÀ@fffff¦±ÎÎÎ!!!L&ÐÙÙýôéSÀ¦M›Î;××ׇaØ«W¯8ëgΜI¥Ry<›Íþã?ðÐÕ1Y³fÍ…   ¯¯/666==@¡PÂÃÃY, ¡¡!99†·ŽÉgŸ}¦  ••Åç󇆆bbb¼½½ñ©ÇwâÔ©S÷îÝb0ááá"fÇH===«Vý?öî< ‰£ø„C„ˆ¢"W¡ÈC­â*A9$(^ RA©5â–dz ZAi<–CAQ­P­rS,”ËGTðá —!‘#lÞ?æ×¼©•`©}Û~?mfggfg×ðuf7³¢³³SSSÓÈÈHWW¿==^7ÊÊÊr8ᤶðÿ8–-..ž\\ü±Ãdž††;v°X,‚ âââDGŒBCC9޽½½³³sNN~ç—N§»¹¹áq#???|ˆ““S{{;Aþþþeeex|êÔ©ÑÑÑzzzx¦×±aÆääd‚ h4Z}}½˜J±©S§jiiM8³,•J‹‹ ²···µµÅÓŽEEEkÖ¬innâr¹ÍÍÍöööÍÍÍ!ƒADffæêÕ«ÍÍÍqx!tèСðððððpüúÅ„¶nÝšžžŽ·¥¥¥=<<²²²ÌÍÍ׬Y3sæL<Ó*//ùòåÔÔTssómÛ¶µµµ™šš"„ÊÊÊ‚°°°¨¬¬$ÂÌÌ GuóçÏ ;x𠉉ÉÁƒñª­­­µµµ———±±ñÁƒ­­­ B|ðµµµ¥¥¥««kZZšðY…×ÒÔÔ£Ñh§OŸþòË/•””BçÏŸ'ÂËËëÌ™3Alܸ‘ÏçS(”#GŽ´´´ØÚÚ:;;+((øúú"„ž>}º|ùòk×®áV>ÿüó ;ð³Ï>«¨¨pttüüóÏ÷ìÙ3þü_{#IJJÊËËoß¾ýƒ>pssÛ¸qã²eËÄt£ŒŒLbbâ–-[¬¬¬bbbD_ùñÇ—-[&:€ ü×P˜ ÿHVôK!tõZª˜1•’’:]ö5<<ŒßÇO‚_åû￯¨¨xóiýß›··÷¶mÛ~ãÏpøÓËÍÍÕÖÖ–••“‡$I’$«««i4Úxyp¬ØÖÚ}V zö/BFF&>>þ7>¾ù×TSSãïïßßߟ‘‘‘ššŠ_ ú®®®xäøïƒðñ/ÄÐÐ:aôõõÅ?ú_F¡Pð<>ð?cQÂGá#€ð@ø ||gµ¶¶êëë«©©ÅÇÇ#„ž‰’ß{ï½Ý»w3™Ì_î²´´´´´ìììlnnvwwOIIÑÓÓî…¦ðçó§Šo6oÞüñÇ›˜˜(((à”šš]]]%%¥®®®äää K˜5kVSSI’uuu·n݉666wïÞ}øð¡@ àñx·nÝ»úúúV¬XÑÙÙ©©©idd¤««ûüùsaQ—/_ÖÐÐ}PÂÇw‹¥¥eVV–p–!´sçΛ7o.^¼ø³Ï>›?~rrrBBBèüùóAxyy9s† ˆ7òù|„““ÓÇuuu?úè£)S¦„……uwwËËË_¾|955ÕÜÜ|Û¶mmmm¦¦¦!IIIyyùíÛ·ðÁnnn7n\¶l™°j…yóæÉÉÉÁM€? “áÉŠ~Éã"„®^K½^QRRB§Ó¡ËþrssµµµeeeÅä!I’$Éêêj6^+¶µ6ÇDŸ…‡óÀ¯á#€ð@ø |>Á¯%ú+â>þ9eggÛÙÙ­[·®²²rÂÌ|>?&&ÆÌÌŒÁ`<{ö 'Ž]»vÍÍÍÍÎÎî­7ïСCT*U__ßÀÀÀÑѱ¨¨H¸«¾¾~÷îÝFFFÇ/..®¯¯×××WVV644444ܵk›Í†K ßš'OžÄÅÅݸq#::ú“O>áp8âó߸qc``   `óæÍL&S  „ŠŠJxxøïÑÂC‡YYY¾5YYYÞÞÞT*UIIÉÝÝí•——S©ÔU«Vñùüøøx …‰ó_¼xÑÝÝ]RR’F£ ?}ú!$%%µbÅŠÙ³g¿¶Š£G:::öööNؘ–––°°0kkk:>00ðJ ''§ºº:„P\\Ü¡C‡ôôô(ʬY³Nœ8±jÕ*ÑÌ/Ìáã[ÓÜܬ¦¦†·ÕÕÕÛÚÚBK–,IKK“èíííîî Ù½{7Èòóó•••q~}}}áüõx›Ínjj™°1GŽ122***JMM¥P(CCC¢{‡††***nß¾½xñb„Ð?þøþûï ÷R©ÔY³fám‹E„ŽŽŽ¹¹¹··7\eüRÐã¡P(Âí•+W’$I„››[xx¸”””øübÊ>>Ë–-C…††®ZµêÒ¥K†††L&ÓÜÜ!´zõê“'Ož;w®¸¸XZZzåÊ•+V¬hhhرc‡Ã¹víBHVVv÷îÝ .„ €I£0þ‘¬è—<.BèêµTggçñ²–””Ðétè2€?„ÜÜ\mmmYYY1yH’$I²ººšF£—GAAÇŠm­Í1Ñgaòü >„ÂGá#€ð_•mgg·nݺÊÊÊ 3óùü˜˜333ƒ!\½!äëë«§§ghhhhhxõêÕI7fllìöíÛ›6m277/++ɉ‰‰¸p&“)ÌÜ××·wï^“'N  Óëêê<<ŸüøñöööÈÈHñ¿Sÿêš››ÕÔÔ𶺺z[[BhÉ’%iiixÁëîîîÝ»w#„A~~¾²²2ί¯¯/:}àÀ¥K—z{{××× ›Ínjj™°1>\¸pá?ÿùO—ï¾ûNtWBB‚µµõªU«òóóqÊóçÏ,X€Ç>§OŸN’äàà B¨££CKK çQQQ©««›°Þ}ûö}õÕW¾¾¾ÒÒÒpKà0y=.á44BhåÊ•$Iáææ.%%%>ÿBªªªuuužžžùùù2228Ï™3gFFFðGñ:::bbb²²²CBB”••—,Y‚rrr211ÑÒÒêïï÷óóSWWÃYrÑŠallìçççíí}ýúu¸ Ffîܹx»µµU8)=zdjjZ[[;00 ŒÆ,--…#Ž555JJJx[CCCCCCJJÊÀÀ`úô颣’!ñÓÐBZZZ‘‘‘sæÌ±··¯¨¨Àé úúú222JJJ+V¬ÀŠsæÌyôè~>òŋӦMC©¨¨´´´ãQ]]Ý ëuqqY¾|ùÇœ˜˜· |‡N§'$$ðx¼çÏŸ§¤¤˜ššâØ1**ŠÃá\ºtÉÏÏÏÇLJÃáàüžžžW®\!I²¼¼\ZZZSS!ÔÐМœ<000::úý÷ßËÈȨªª «`0ÆÆÆ6ÆÎÎîæÍ›999 .Dñx¼³g϶·· ‚úúú›7o.Z´!4{öìÅ‹ççç ‚ÔÔÔO>ùBÄÝ»wÙlöÈÈÈ… Þ°+V­Z•””$Œ• || ///WWWÿS§Ná×®Ï;Çd2ëêêðã™™™›6mE¹ººÊÉÉYXX$&&žZ¾|yFFÆ×_-:Ù­ªªúÞ{ïM™2eÂÆÌž={ß¾}&&&!999vøðáÅ‹‡††FGG ‡H>œ‘‘annÎáp¶nÝŠ©Tj\\\PP½½½­­­±±±˜CCC W­ZUUU%++ëææ¶|ùòšš¸1 Da2ü#YÑ/y\„ÐÕk©ÎÎÎãe-))¡ÓéÐe¹¹¹ÚÚÚâG…$I’$«««i4Úxyp¬ØÖÚ}FÀ¯á#€ð@ø |>€ðñUÙÙÙvvvëÖ­«¬¬œ03ŸÏ‰‰133c0¢+¶´´ìܹÓÈÈèàÁƒÂ%j~-@˜˜¸|ùroo簾&azSS“É422òôô¬ªª¦÷õõíÝ»×ÄÄäĉÃÃÃÂôºº:›´´4ñ5:tˆJ¥hiia0)))’’’pcÂÇ×ËÊÊòöö¦R©JJJîîîEEE¡òòr*•ºjÕ*>ŸO¡P"##qþ‹/º»»KJJÒh´ááá§OŸ"„p9mÚ4))©éÓ§¿2zwôèQGGÇÞÞÞ sÿþ}:.//¯­­mkk{ïÞ=œîêêúÁHHH¨¨¨Ìœ9“$I„POOOEEÅßÿþw ‰7ž>}g®¨¨°³³ÓÔÔ”‘‘ñòòº}ûö„õòùüãÇ···GFFŠÿz@øøW×ÜÜ,\BZ]]½­­ !´dÉ’´´4¼àuwwwHHÈîÝ»q˜˜ŸŸ¯¬¬Œóëëëãùkiii‹¥­­­©©éáá±ÿ~aù€Íf755ŒŒLØ‚ îܹÓ××÷ðáCÿææfá®—/_2 ++«üãÓ¦MC=þ|Á‚xÑíéÓ§“$988ˆêèèÐÒÒÂG©¨¨ÔÕÕMXï¾}û¾úê+___iii¸%áã›Â¡¶råJƒADOOÏáÇ¥¤¤ÄäŸþyQQQuuuDDÄ™3gDóœ9s¦¼¼\EEeÂØØØmÚ´)%%åܹsÂ8!$++zìØ±‹/ 'µÕ‰all|éÒ%ooï¾¾>¸ á£8sçÎíèèÀÛ­­­Â‘H@ðèÑ#SSÓÚÚÚa4fii)|c¦¦¦FII H¡P–-[&//ïèèÏçóÖéoÔí ÅÝÝ=###44´¬¬ìoû›èÞ3fXYY-[¶ ?Î8gΜGáyó/^HHHàQI•––|HGG‡®®î„õº¸¸,_¾üã?>@ áãëÑéô„„÷üùó””SSS;FEEq8œK—.ùùùùøø_©ñôô¼rå I’åååÒÒÒššš!eee‡óàÁƒÑÑÑììlGGGÑÑJƒallÜÙÙ9acH’ÿüç?çÏŸâñx/^|þü¹@ hhhøþûïqD8{öìÅ‹ççç ‚ÔÔÔO>ùBÄÝ»wÙlöÈÈÈ… Þ°+V­Z•””$Œ• || ///WWWÿS§NÍœ9!tîÜ9&“YWW‡ÌÌÌÜ´iÓèè(BÈÕÕUNNÎÂÂ"11ñäÉ“xvXFF&))é믿611)))9zô¨hªªªï½÷Þ”)S&lLAA¹¹y`` •••¯¯/N”••URR X¼xñ±cÇ>ÿüsuuu¼ëðáÃææægëÖ­8‘J¥ÆÅÅÙÛÛÛÚÚ‹©144´°°pÕªUUUU²²²nnnË—/¯©©B&Ã?’ý’ÇE]½–êìì<^Ö’’:]ð‡››«­­-þwTH’$I²ººšF£—GAAÇŠm­Í1Ñgaôü >„ÂGá#€ðüu C?ÂljeggÛÙÙ­[·®²²rÂÌ|>?&&ÆÌÌŒÁ`àÕ ÿóŸÿèéé8qâ76cÏž=T*ÕÎÎnxx˜Åb©©©-\¸°»»û÷>ýÂÂÂÝ»wkhhc%] êÉ“'qqq7nÜàr¹®®®ß~û-^xf<7nÜ((((//g2™IIIóçÏ­¨¨ø- lllüæ›oBŸ~ú©¢¢â”)Sï‘‘a2™íííp3àµ`ôñg²²²¼½½©Tª’’’»»{QQB¨¼¼œJ¥®ZµŠÏçÇÇÇS(”ÈÈHœÿâÅ‹îîî’’’4mxxøéÓ§8ÃáDDD˜››»¹¹ýøã¢U=zÔÑѱ··wÒlii 311±¶¶¦ÓéxYj@pëÖ-‚ öìÙÓØØˆ3èèèäå幸¸øúú¶´´ˆ)|éÒ¥xõE'ÐÜܬ¦¦†·ÕÕÕÛÚÚBK–,IKKà ^www‡„„ìÞ½GlùùùÊÊÊ8¿¾¾¾pÂ÷È‘#¦¦¦,+::úáÇ8] °Ù즦¦‘‘‘I7òÈ‘#FFFEEE©©© ehh!tõêÕÊÊÊØØØ’’’íÛ·ïÞ½»«« !daa‘žž~þüù¬¬¬øøøIII¸Ð˜4˜¼—èÜÊ•+I’$ÂÍÍ-<<\JJJ|þ={ö,_¾!¤¤¤ôÉ'Ÿ¤¥¥}øá‡8Ï™3gFFFddd&Ý0WWר¨¨ÒÒR‹5g΄еkתªªnÞ¼‰ó<{ö¬¸¸X¸‚¹££cxx¸„„„ø¹x€ ÁèãÏÌ;·££o·¶¶ G"Á£GLMMkkkñd1Ž---…#Ž555JJJÿ×­¢a¥èÇWöއJ¥ÖÕÕñù|ü‘ÍfOŸ>o[ZZ¦§§{{{kii¹»»×ÕÕ!„ôôô¾ú꫊Ÿ´¶¶ cG„¢¢â›T á㯙4r IDATC§Óx<ÞóçÏSRRLMMqìÅáp.]ºäçççããÃápp~OOÏ+W®$Y^^.--­©©‰Ó?^ZZ*zzzÎ;çää$¬‚Á`wvvŠoÉŒ3¬¬¬²²²A{{ûíÛ· ‚@õõõ­X±¢³³SSSÓÈÈHWW÷ùóç!//¯/¿üǾ===111ÕÕÕpAðÖÁäõÏxyy¹ººR©ÔS§Ná©ÞsçÎ1™Ìõë×ãÇ3337mÚtûömiiiWWרØX ‹E‹>>Ë–-CÍŸ??,,ìàÁƒ>\²d‰¥¥¥®®.B("""!!¡···  @JJ*99§‡Á`üë_ÿjhh¨®®VPP¸v횪ª*Ü¢0þ‘¬è—<.BèêµTÑÏW”””Ðétè2€?„ÜÜ\mmmYYY1yH’$I²ººšF£—GAAÇŠm­Í1Ñgaòü >„ÂGá#€ð_•mgg·nݺÊÊÊ 3óùü˜˜333ƒ!\½ð­Ø³g•Jµ³³f±Xjjj .ìîîþ½OÿÙ³gAAAAìÙ³gÂ¥qð«ÎüÌ“'OââânܸÁår]]]¿ýö[¼ðÌxnܸ100PPPP^^Îd2“’’(Ê[iI```ccã7ß|ƒúôÓO§L™‚žùý$¹cÇŽ   #GŽ”””øùù¥§§¿­3ÀŸŒ>þLVV–··7•JURRrww/**B•——S©ÔU«Vñùüøøx …‰ó_¼xÑÝÝ]RR’F£ ?}ú§×××3 ##£7‹d=zÔÑѱ··wÒlii 311±¶¶¦Óé!@pëÖ-Ž«¹¹YMM o«««·µµ!„–,Y’––†¼îîî Ù½{7¶òóó•••q~}}}<ÝÙÙÌd2ïß¿Ïb±ž+++>>>$$DRRr¼’%%% ñöå˗ׯ_///wDÁäõ¸D'mW®\I’$AnnnáááRRRbòçæænÞ¼yîܹ!•øøø©S§ óœ9sfddDFFfÒ suuŠŠ*--ÕÑÑa±XsæÌA]»v­ªªêæÍ›8ϳgÏŠ‹‹…+˜;::†‡‡KHHˆŸ‹Ƹ±±±Ÿþ9Ü€ðQœ¹sçvtt,X°!ÔÚÚª¡¡!Œ¨=zdjjZ[[;00€ƒ0 …biiùìÙ3<`YSSãããƒâóùÿX‡w¢D÷އJ¥ÖÕÕñù|ª²ÙìE‹á]––––––ÍÍÍîîî)))zzzzzz ÃÒÒòµ¥)**¾I¥¡ÑÑÑððp™°°°×FÉø‹ƒÉ럡Óé <ïùóç)))¦¦¦8vŒŠŠâp8—.]òóóóññáp88¿§§ç•+WH’,//—––ÖÔÔDYYY]¸pÍf#„^¼xãÆ a ÃØØx—šg̘aee•••%ÚÛÛoß¾MB¨¯¯oÅŠšššFFFºººÏŸ?Gyyy}ùå—¡žžž˜˜˜êêê_{ú»víRWW–’’ºuëÖ‹/஀(^ú///WWW*•zêÔ)<ÊxîÜ9&“¹~ýzüøcffæ¦M›nß¾---íêêkaa±hÑ¢“'OâùkMMÍ#GŽ„††Þ¿_SSsݺuöööÂ*TUUß{ï½)S¦LؘÐÐÐS§N………½ÿþû_ý5~íZRRR^^~ûöí­­­ZZZ>>>Ë–-CÍŸ??,,ìàÁƒ>\²d‰¥¥¥®®.B("""!!¡···  @JJ*99§¿VEEÅW_}UVVjii)..ž>}:Ü¢0þ‘¬è—<.BèêµTáÓr¿TRRB§Ó¡ËþrssµµµeeeÅä!I’$Éêêj6^+¶µ6ÇDŸ…Ékð+@ø |>„ÂGð?1000<<üVŠ"IR L˜íÅ‹AAAŸF7=~üøèÑ£ïr ù|>ܽ ||ûêëëõõõ••• ¢  ðèÑ£I•••5¹ÿ›êêê<<\ZZÊçóð‹<ÏÆÆ†B¡ìÝ»gˆˆ/f‹‹STT¬¬¬üßö$‡ÃÉÊÊz»eÓét*•jhhh``°}ûö–––7?ÜÛÛ›B¡à~kiiñññ!I¾b@øø–éêêÆÅÅVýÄÓÓsrEÕÖÖâußY<ÏÛÛ;<<ü»ï¾»{÷î„aŸŒŒ “É´µµý宨¨¨òòò“'OÞ»w/f8¡†††ŒŒ ###))©Ë—/ëééÅÄÄ „äää®\¹bgg'Ì›={¶@ PQQym9Û¶m›ô5z‹ÌÍÍóóóßn™222—/_666®ªªª®®öööÞºuëèèèž Üž;wîØØXqq1|Å€ðñwÄb±ø|þÎ;õôôBíííû÷ï§ÑhŽŽŽ)))©ÀÜÜ\OOOCCÃ-[¶TUUáÄC‡…††úùùá!ÌÌÌLôÓ`’••BˆÍf/]º/*ˆ*((ÐÑÑ ÈËËsqqñõõÅãLãUŠª©©±°°¸zõê¤O°¢¢ÂÎÎNSSSFFÆËËëöíÛ¡ÞÞÞ… êèè´¶¶–——S©T}úá‡Ξ=[ÌáIII˜>}:BÈÉÉÉÑѧ_»v­ªªêæÍ›øã³gÏŠ‹‹œœ¢¢¢²³³©T*BÈÚÚ:==½¶¶ÖÀÀ൅çääxyy©ªª"„lll\]]…ý_\\œžžÞÓÓ3sæLuuuñç(++»}ûvCCC„Ї~˜””$Ü¥  PXX())ù&#µ¥¥¥†††ÝÝÝ‹-ºv횘3µµµ½xñbee¥„„„´´ôǼoß>a9sæÌÁÃÞã8ð%õî4%55URRo+))™™™}ûí·¯ü½¯¬¬¼xñbHHˆššÚàààùóçKŠŠŠ¢åW©ÐNGEE¥°°Pêêê w555©¨¨ô÷÷wuu‰äBZZZ‘‘‘8(±··¯¨¨˜0|”“““““N:#„¤¥¥?úè£~øááÇ...¿*Þ•——Çzzz ÃÒÒR4'þïΛ÷›„„„è+&ÂíäääÁÁA‹¥¨¨XRRrýúõ7oä/gü)Ê/_ËØØ8??¿§§ç³Ï>ËËË[»víxgÊãñDë½|ù!4cÆ ø–ð'ó=û(ŒBóæÍ300¸~ý:ŸÏçóùååå, !ÔÜܬ­­­®®>44”œœ,zøÌ™3›ššH’ìéé),,Äo+S©T6›Ý××Çår'Œ?Æ«T¹Î›7ïܹs“>A‚ îÞ½Ëf³GFF.\¸ààà€ÓóòòN:•”””°}ûö'Ožˆ/ÇÎÎîæÍ›999 .œ°j;;;<*dkk{üøñœœœ £O˜˜˜’$srr„=ïååõå—_vtt „zzzbbbª««)J``àÙ³gy<I’?ÏúZ¶¶¶ñññMMMCCC·nÝŽðÕÔÔèêê*))uuu½r­­þþþ+VlÙ²ellì ™={öÉ“'£££›ššÆ;S99¹Í›7'''ãêØØXÑ:::´µµÇ{ €ðq’vìØÁb±‚ˆ‹‹¦S(”ÐÐP‡cooïì윓“³zõj„N366vssÃs©~~~ø''§ööv‚ üýýËÊÊð<øÔ©S£££ôôôðL7®%""bÆ ÉÉÉAÐh´úúz1•bS§NÕÒÒšpfY *•doookkkllŒ***Z³fMssóÐЗËmnn¶··onnF1 ‚ 233W¯^mnnŽcÙìÛ·/ ÀÁÁÁÂÂÂÄÄäMjߺukzzºhŠžžž´´ôæÍ›…Ï ôôôX[[‘——G§Ó ‚Ào7ÛØØX[[oÙ²…N§×ÖÖúúúnÛ¶­££cþüùaaa4119xð ¢¢"Rݰaƒ¡¡¡›››••UIIÉ©S§„Uü’ººú_|áììÌf³½¼¼púÎ;oÞ¼¹xñâÏ>ûlþüùÉÉÉøÕæ²²2‚ ,,,*++ ‚033c³Ù===111yyyàèÑ£ÉÉɸ()))uuuUUUñã ÃÃÞžž¥¥¥vvvÓ¦M;tè]CCÃxgÀãñlmm=<\ZZÊçó|||B<ÏÆÆ†B¡ìÝ»gˆˆ/f‹‹STT¬¬¬üßö$‡ÃÉÊÊúîÉÝ»w988?~¼¸¸ø¿p:¡¡¡¥¥¥ð}ÂljéêêÆÅÅVýÄÓÓsrEÕÖÖ²Ùìw¹¯y<ž··wxxøwß}w÷îݲ²2ñùedd˜L¦­­í+éï¿ÿþ?þìîîŽ×VžPCCCFF†‘‘‘””ÔåË—õôôbbbBrrrW®\±³³æÍž=[ Œ·ÚÞ¶mÛ&}Þ"sss¼"ÎÛÕØØ¸cÇŽ;wÞ¿?))©±±±±±ñ¿p:8T}“±aà¯>Šb±X|>çÎxñ·öööýû÷Óh4GGÇ””áì^nn®§§§¡¡á–-[ªªªpâ¡C‡BCCýüüðfff&Bhxx˜N§[YY!„ØlöÒ¥K) Î_PP ££——çâââëëÛÒÒ"¦R„PMM ^µeÒ'XQQagg§©©)##ãååuûöm„PooïÂ… uttZ[[ËËË©Tªƒƒ^õnéÒ¥Â6 ÉËËKJJR©TÑ…ÂÅKLLܵk×”)SBÓ§O·µµ-//Ç»rrr¶nÝŠ+JNN644¤R©ííí¢‡ggg»¸¸ØØØœ;wŽËåâD@pëÖ-‚ öìÙ#Œ´H’Äéfff‘‘‘âÛVYYéáá3{zzÑÙÙ)bcc,XÔÓÓ#Ì¿k×.}}}ÑVݵk×–.]ºoß>ÑJ¹\î† ‚‚‚&ŒÏâââ:¤§§G¡PfÍšuâĉU«V!„ÚÚÚðýSWW·}ûvGGÇ¢¢"\ò¹sçlllÌÍÍOœ8Ñ×ׇËy픟ŸïééÉb±V®\¹jÕª{÷î ë%‚Ëå ¯ðNc2ü;Èãž?ž3¾ŒŒ ÁïàÞ½{ªªª‹/F âÄþþ~[[Ûû÷ôõõÅÆÆž9sïêèèèêê«««£ÑhÂrNŸ>}çÎW ïîî¶´´ÄÛ£££8âÁ>|8cÆŒàààÞÞÞÆÆÆÖÖV1• ‚û÷﫪ªž>}zÒgzõêÕK—.áí¦¦&777¼ÝÐÐ`ffVYY™‘‘áèèØÓÓ#zÔ† ž>}*šÒÛÛû·¿ýM]]!tïÞ½7¬}Ñ¢E÷ïß~,..Þ»w¯@ £ÓéÝÝÝ¢™×®]ÛÖÖ&ü˜››»gÏžþþþÑÑQ<íþàÁ@påÊ•ÐÐÐîîîÑÑÑÚÚÚ5kÖà°/%%%<<|ppptt477×ÛÛ›Ïç×°¦¦¦µk×¶··egg#„ªªª„»8ÎØØXZZZXX˜èQgÙ²e¢)yyyªªª?&I211‘Åb‰f666Þ¸q£˜f`VVV]]]¯Ý…ï—úúz‡óðáC@°k×®7n ¾|ù²  ÀÃÃÏçw#ŒŒ¬Y³æàÁƒ/_¾ìíí¥Ñh¢Ý#Þžœœœ†††v±ØlöÓ§O322ÄÂX±î?™ ÿwbÕ™O?ý488ØÅÅEJêÿÚóøñã’’’mÛ¶á|>hhÈßß_BB¢¾¾þâÅ‹uuuZZZ%%%¿¥^GGÇððp ‰™3g"„ŠŠŠÆ«!dddÔØØ8uêÔ·rÊ¢cŠ:::‰‰‰ëׯWTT¼|ùò¬Y³Ä{áÂ…üã... L&3##)ŠÁápüðä¤$á.…ÂÂBIIÉ ×l”‘‘ÁC¿wîÜÙ¿?BhÁ‚çÏŸ^¯ÄÄÄiÓ¦á2ûúúNŸ>ýÃ?9rïmhhhnnîêêzí$---++ëãã3uêÔ©S§~ðÁÝÝÝž×ÔÔœðyà]ð-Z˜šš*œŠURR233ûöÛo_ù{_YYyñâÅ55µÁÁÁóçÏÿ–E˯R¡ß¸`´ŠŠJaa!ÞîèèÐÕÕîjjjRQQéïïïêêšp¡ä .|ÿý÷Ó§O722ÒÓÓ«««›p5B999999á¤3BHZZú£>úá‡>|èââò«â]yyy¼¡§§Ç`0,--Esâÿî¼y¿IHHàˆ n'''²X,EEÅ’’’ëׯ¿y#9ãO¡P~™øKÆÆÆÍÍÍ***«W¯^½zuJJÊØØ˜è8vĦOŸþ·¿ý-##C4.Ç= þFzm#_¼xñ'XìÀ_Á;ôì£èc|óæÍ300¸~ý:ŸÏçóùååå, !ÔÜܬ­­­®®>44”œœ,zøÌ™3›ššH’ìéé),,Äo+S©T6›Ý××Çår'Œ?Æ«T¹Î›7ïܹs“>A‚ îÞ½Ëf³GFF.\¸ààà€ÓóòòN:•”””°}ûö'Ožˆ/gÍš5™™™ÃÃõµµ•••šššV-##cgg×ÖÖ&šhkk{üøñœœœ%K–ˆ?ÜÃÃ#&&f``€$ÉœœaÏ{yy}ùå—¡žžž˜˜˜êêj …xöìYG’dAA‡ÃÁϳ¾–­­m|||SSÓÐÐЭ[·„c™555ºººJJJ]]]¯\ë_«¿¿ÅŠ[¶lŸÓÛÛûرcµµµ$Ir¹ÜÎÎNñïçŸ~æÌ.—‹§Ú9288(þFO]]Ýüùóá+ „hhhرc‹Å""..Nt`&44”ÃáØÛÛ;;;çää¬^½!D§ÓÇÆÆŒÝÜÜð\ªŸŸ>ÄÉÉ©½½ ÿ²²2<>uêÔèèh===<Ók‰ˆˆØ°aCrr2A4­¾¾^L¥ØÔ©Sµ´´&œYƒJ¥ÆÅÅÙÛÛÛÚÚ#„ŠŠŠÖ¬YÓÜÜ<44Äår›››ííí›››B ƒ ˆÌÌÌÕ«W›››ã( !ÜØØhffvìØ±ÄÄDáX x[·nMOOMÑÓÓ“––Þ¼y³ð™žžkkk‚ òòòèt:Aøífkkë-[¶ÐéôÚÚZ__ßmÛ¶uttÌŸ??,,ìàÁƒ&&&TTTÄCª6l044tss³²²*))9uê”°Š_RWWÿâ‹/"""œÙl¶——Nß¹sçÍ›7/^üÙgŸÍŸ??999!!!TVVF„……Eee%Afffl6»§§'000&&&//O =z499¹¢¢%%%¥®®®ªª:áøñܹsOž<»bÅ ·bÅ „PNNÎÒ¥Kñÿ‚À¯=!„\\\–-[öÑGY[[ÇÆÆš››O›6m¼éüùó™™™Ÿ~ú)ŸÏ/**ºyófdd¤°çÓÒÒ,,,à+ À»ÂdøG²¢_ò¸¡«×RÇËZRRB§Ó¡Ëþ †‡‡ñ›ãsçÎ}gÉápoܸñW›Æ=þ<ÇÛ¹s'ܨޢÜÜ\mmmYYY1yH’$I²ººšF£—GAAÇŠm­Í1Ñg¥ gÿ"dddâããã㛿.—»nݺÎÎN55µˆˆˆ¿à#€:::øÇ€w„!¾aó¿B¥RïÞ½ûW¾40m àÖ¼>„ÂGðö ¿•¢H’|e=˜×zñâEPP‡Ãy—»åñãÇGýÃ]Í7¼„㪯¯×××WVV6ü‰‚‚£G&QTVVÖäüoª««óðð°±±IKK›0saaáîÝ»544ð :¿ÝáÇKKKù|¾ƒƒƒ‚‚‚BˆÇãÙØØP(”½{÷âl£££ãŬqqqŠŠŠ•••ÿÛžäp8YYYo·Ìááa:N¥R \]]E¡f2™úúúË—/ÿ-Uܹs'66¾w@ø8yºººqqqU?ñôôœ\Qµµµl6û]îk"þ¼’ IDATçííþÝwßݽ{W44y-&“ikkûVjohhÈÈÈ022’’’º|ù²žž^LL BHNNîÊ•+vvvÂÁ¼Ù³g •×–³mÛ¶I_£·ÈÜܯˆóÉÈÈ\¾|ÙØØ¸ªªêÉ“'gÏžýøã…£°'NœÀ ýfff'Nœèî>¾,‹Ïçïܹ¯ÜÞÞ¾ÿ~æè蘒’Âçóq¶ÜÜ\OOOCCÃ-[¶TUUáÄC‡…††úùùá!ÌÌÌLôÓ`’••BˆÍf/]º”B¡àü:::yyy...¾¾¾---b*EÕÔÔàU[&}‚vvvššš222^^^xá»ÞÞÞ… êèè´¶¶–——S©T’$BK—.ÕÐжYèµ=0¡ÄÄÄ]»vM™2!4}út[[Ûòòr¼+''gëÖ­¸¢äädCCC*•ÚÞÞ.zxvv¶‹‹‹Í¹sç¸\.N·nÝrqq!bÏž=8$Iœnff900 ¾m•••8³§§'A 66ÖÁÁaÁ‚AAA===Âü»víze pttt×®]Xºté¾}ûD+år¹6l úUÇccc###¿ì¡ºº:}}ý/¾ø!”ŸŸ¯££ˆww#)((øúú~óÍ7ðÕàŒÉð<î ;xþüyÎø222¿ƒ{÷ªâ%7qb¿­­íýû÷GFFúúúbccÏœ9ƒwutttuuÕÕÕÑh4a9§OŸ¾sçÎ+…www[ZZâíÑÑQñ`>œ1cFpppoooccckk«˜JÁýû÷UUUOŸ>=é3½zõê¥K—ðvSS“››Þnhh033«¬¬ÌÈÈpttìéé=jÆ OŸ>M¯Ä[´hÑýû÷…‹‹‹÷îÝ+ÆÆÆètzww·hæµk×¶µµ ?æææîÙ³§¿¿ttO»?xð@ \¹r%44´»»{tt´¶¶vÍš58ìKII ÍÍÍõööæóùã5¬©©iíÚµííícccÙÙÙ¡ªª*á.‡366–––&z‡ÃY¶l™hJ^^žªªêãÇI’LLLd±X¢™7nÜ(¦ÂFNNnñâÅóçÏG…††Š¯ôÞ½{ÇŽÞQâï^@••µiÓ&ðûËÉÉihhh‹Íf?}ú4##CL(Œëþó˜Éð'VùôÓOƒƒƒ]\\¤¤þ¯=?.))Ù¶mþÈç󇆆üýý%$$êëë/^¼XWW§¥¥õ'ÃÃÃ%$$fΜ‰***¯R„‘‘QccãÔ©SßÊ)‹Žiéèè$&&®_¿^QQñòå˳fÍì$z€Ãá}úá‡Ξ=[ÌáIII˜>}:BÈÉÉÉÑѧ_»v­ªªêæÍ›øã³gÏŠ‹‹œœ¢¢¢²³³©T*BÈÚÚ:==½¶¶ÖÀÀ൅çääxyy©ªª"„lll\]]…ý_\\œžžÞÓÓ3sæLuuuñç(++»}ûv¼²Î‡~˜””$Ü¥  PXX())ù&k6çççã`1,,,++ë×>? æîE©¨¨dggIJJÂ_ü½C‹¦¦¦ ÿ *))™™™}ûí·¯ü½¯¬¬¼xñbHHˆššÚàààùóçKŠŠŠ¢åW©Ðo\0ZEE¥°°owttèêê w555©¨¨ô÷÷wuu‰ä&×rrrrrrÂIg„´´ôG}ôÃ?<|øÐÅÅåWÅ»òòòxCOOÁ`XZZŠæÄÿÝyó~“À“õ˜p;99yppÅb)**–””\¿~ýÍùËg …"fúµEÍš5kË–-×®]ûµá£ø‰Ëå¾ÿþû;øãz‡ž}ýƒ:oÞ<ƒëׯóù|>Ÿ_^^Îb±BÍÍÍÚÚÚêêêCCCÉÉÉ¢‡Ïœ9³©©‰$ÉžžžÂÂBü¶2•Je³Ù}}}\.wÂøc¼J…qÛ¼yóÎ;7é$âîÝ»l6{ddäÂ… 8=//ïÔ©SIII Û·oò䉘BÄô€222vvvmmm¢‰¶¶¶ÇÏÉÉY²d‰øÃ=<ÿùóçÂLüÔÚÚjff_= |œ¤†††;v°X,‚ âââ„é %44”ÃáØÛÛ;;;çää¬^½!D§ÓÇÆÆŒÝÜÜð\ªŸŸ>ÄÉÉ©½½ ÿ²²2<>uêÔèèh===<Ï‹k‰ˆˆØ°aCrr2A4­¾¾^L¥ØÔ©Sµ´´&œYƒJ¥ÆÅÅÙÛÛÛÚÚ#„ŠŠŠÖ¬YÓÜÜ<44Äår›››ííí›››B ƒ ˆÌÌÌÕ«W›››ã(MLˆ·uëÖôôtÑ===iiéÍ›7 Ÿèéé±¶¶&"//N§ßn¶±±±¶¶Þ²e N¯­­õõõݶm[GGÇüùóÃÂÂwîÜw¶‘ÇÑÑñÆJJJÊ«ðïÿûèÑ£W¯^ýU3éÀääææjkkËÊÊŠÉC’$I’ÕÕÕ4m¼< 8Vlkmމ>+=û!##ÿßüp¹ÜuëÖuvvª©©EDDüYcG„¬¬ì±cÇ vð‡áã_~+ùD¥RïÞ½ûW¸⟤þ`Íká#€ð@ø |ï$’$_Yæ­xüøñÑ£Gÿ²½ÊçóáÖáãO}}½¾¾¾²²²áO=z4‰¢²²²&wàS]]‡‡‡MZZÚ„™544p·0™Laú³gÏ‚‚‚‚سgOggç›×~øðáÒÒR¼¢¯¯O¡PŽ;ö&Çž9sæÅ‹¯ÝÅáp²²²ÞÙ>ohhøæ›o~{9L&S__ùòå¯DäÏŸ?‡¯>þ—èêêÆÅÅVýÄÓÓsrEÕÖÖâ…@ÞY<ÏÛÛ;<<ü»ï¾»{÷nYYÙ„‡°X,Ü-'NœÆ+;vìpqqùñÇýüüÞp@±¡¡!##ÃÈÈ ¿|ù²‡‡GbbâÐÐЄ‡çååõ÷÷¿v—¹¹9^œæÝÔÕÕõøñãß^Ή'ðÂE?û÷#!áââ’’’_% |ü`±X|>çÎx}äöööýû÷Óh4GGÇ””áann®§§§¡¡á–-[ªªªpâ¡C‡BCCýüüðX]ff&Bhxx˜N§[YY!„ØlöÒ¥K…?×\PP ££——çâââëëÛÒÒ"¦R„PMM ^µeÒ'øÿڻר¦®Dà;¼!Õ‰ÕòPD¹h£„: (AìÈ«XÀ‘A U™«•©v,Š+WEÓ"(¨, Nå!P@iÁhEä%”ð <Nî‡3“E©D Î\«ÿß×ÉÎÎÞ'gg±þî}’}ëÖ-{{{===eee__ß+W®BºººLMMçÌ™#ø|>“Éttt¤(j¬F$IXX˜¹¹¹¢¢¢……ÅO?ýÔÛÛ;žÞããヂ‚”””¤%YYYÞÞÞvvv#S‘P(|ö왾¾~GGÇ·ß~»sçNºphhÈËËëûï¿~òäÉþýû¿øâ ú)WW×ÆÆÆç¶, —-[6²$??ïÞ½ôñ7öìÙ#{LŸ«µµuýúõ Eµ¶¶:99]»vM"‘Ü»wÏÛÛ»¥¥…¢¨899µ··K$’¼¼<--­{÷îQ)=ýû÷?·‹ÀÀÀùóç ܸqCFãc½Sš……EII‰àsíÚµººº™ššš333e„@iV¬yp/$8ð•Øuæã?Þ½{÷úõëþy>÷îÝ+))Ù¼y3ýP, ÊÉÉÕÖÖ&&&ÖÔÔÌž=û—‹‰âìì.''7mÚ4BHqqñXBÌÌÌ>|¨¢¢òRÞòÈmëæÌ™ÿþûïϘ1ãܹso¿ý6]¾nÝ:ssóÙ³g?yòdË–-:::ô¼,‚cbb>|øù矧;¡PxçÎ iIiiéŠ+¦OŸÎáp<<<>ýôÓiÓ¦UUUikk›››B¦NúÉ'Ÿ´··OâÝYXXìÝ»·½½]]]ÇãmÙ²Eö˜>·‘ÜÜ\///z‡nMMÍØØXúâóÍ7AAAZZZ„###//¯¼¼¼7ªªªÐ;ë¼ûî» ã9Õ¸¸¸%K–Bè Ô±—ÝÈ»ï¾[__¿téRüwޯЦ…ÉÉÉòòòô±ººº¥¥ååË—Ge‹²²²ÄÄÄÐÐPmmíÞÞÞ3gÎüšg̘1²ý±:•ú•Fkjj^¿~>nmm;w®ô©úúzMMÍ'Ož**êÑ£G„ºº:GßÞ:–)S¦TWW õööþøãÒûeŸk¢B†‡‡¿ÿþ{}}}ü5ÄÇÿ„ººº?ÿùÏ‘‘‘l6ûôéÓÒrƒ& \\\®]»¶víZBˆÝðððÒ¥K=<<èy#za”²nݺ––6›xóæMzZNEE%::ÚÑÑÑÐÐ^é¦{9|øðÿøGÇf³9Nmm­ŒNi***³gÏ–®,O“É<}úô®]»lmméµÎââb''§†††¾¾¾††‡††555‡³ÿþE‹………EGGkkkBnݺõå—_FGG/^¼˜ÍfûúúÒYç…>üðÃôôtBˆX,öññ;vì „tuuíܹ“ÇãíÝ»WYY™ËåfddXYY9::Þ¿? €~ùÿ÷ÇÄİÙìÏ?ÿ¼¥¥…ž¼yó&›Í¶¶¶.++c³Ù–––Ò/¿³X,WW׳gÏÚØØÈÓ±èééþúýë_MMM=<<Ž;&þÇ(,,Lz•à•‹sçÎ=}úôÎ;ïÿ‹Ï䚪®®–nòjêïï÷óó ÿÇ?þqõêUi”áèÑ£|>ÿÈ‘#………l6›.¼téROOOAA——WHHÈ8'ëêê233ÍÌÌ臛6mºÿþÞ½{cccïß¿¿bÅŠ—øNŸ={Fï‚8NŸ}öÙ¢E‹nÞ¼‘˜˜ØÖÖöÿ8LŽŽŽÿó?ÿƒiZ€W4>Ž)‹·mÛfhhHiiiÙ»w/‡Ãqvv¾pá‚tI177×ÇÇÇÄÄäƒ>î_ü·¿ý-,,lË–-ôfVV!dppÐÎÎŽÞ³¸©©iÉ’%ôæË„‚‚‚9sæìر#//oýúõúÓŸ~úé'Bªªªè][&ýoݺeoo¯§§§¬¬ìëë{åÊBHWW—©©éœ9sŸÏg2™ŽŽŽEBø|~SSÓ¾}û´µµ †ô¿===ååå9Îàà`ccãxz RRR’Q'??ßÇÇ'22rõêÕkÖ¬¡§$+++ wíÚµÿ~sssww÷¢¢"—·¶¶ÖÚÚúöíÛôX¬[·N$É>·ŠŠ %%¥™3g~õÕWÒ ËÊÊüýýÙlöÎ;éšÄ˜ŠD¢ÄÄÄ5kÖ˜››2:•H$·oßÖÒÒŠŠŠšô;ýú믓’’èãúúzú¸®®ÎÒÒ²¬¬,33ÓÙÙ¹³³“.‹‹ûä“O\]]¯\¹BR¥¦¦&‰è‡Ÿ~úiiiéxz_¸páíÛ·GFEEeeeI 999}öÙgÏž=ëêêâp8‰$??Ÿòý÷ß?zôhÓ¦M%%%2.¯P(\´hÑ„>¶¶¶GŽÉÊÊ’¾ý{÷îy{{·´´PõàÁ''§ööö‰Ž©D"9vìØ™3gRSSé×Þ»wÏÍÍ­±±qxx¸­­í£>ºqㆴððp.—+ø»víZ]]]‹LMMM™™™2B 4+Ö<¸øJì:óñÇïÞ½{ýúõ ÿ<Ÿ{÷î•””lÞ¼™~(‹åääjkkkjjfÏž]RRòkúuvv—““›6m!¤¸¸x¬N !fff>TQQy)oY:gF™3gN||üûï¿?cÆŒsçνýöÛtykk+—ËÍÎΞ1cFhh¨††ÆâÅ‹e´#ƒP(¼s玆††ìjŠŠŠªªªþþþ******óçÏïèè˜>}:!d×®]æææ„uuõmÛ¶¥§§/]ºôe}¬¬¬ÒÓÓkjjîß¿ïêêš0kÖ¬o¾ù&((HKK‹bddäåå•——·qãÆ éÐÐÐW_}U^^N¢‹‹Ë»ï¾Kϳ–””Hwxïíí}ë­·¤ûVëééçÖ€7Ó+´iarr²¼¼<}¬®®niiyùòåQ{4—••%&&†††jkk÷ööž9sæ×ô8cÆŒ‘íÕ©Ô¯Ü0ZSSóúõëÒh(]¢%„Ô××kjj>yòäÑ£Gt\#„Ìž=;""ÂØØ˜âààpëÖ­Å‹3 ›öövmmmBHUU•¿¿ÿ »VSSSSSëëë›tÆ–SõÖ[o½¬qüøñ?üàää´`Á‚ ˆÅâüüü?üpÔ 0ŒñÜ8jLéÛF…uBÈÌ™3·oßòÜFž>}ª®®Ž¿ÏOD¯Î©H³#!ÄÀÀÀØØ8%%E,‹Åb>ŸIihhÐ×××ÑÑàñx#_>mÚ´úúzŠ¢:;;¯_¿N%™Éd655uww÷õõ¥¤¤È>±:•&WƒS§NMú ²Ùì«W¯655 ={ÖÑÑ‘.ÏËË;~üxBBB\\\@@@ee%]nooŸššÚÖÖÖÓÓsíÚ5SSSºÜÇÇçüùóEñù|EEE==½v­¬¬looßÜÜ<é“ÿßÿýßüüüÁÁÁ¦¦¦¨¨(zÞn¬Ë«ªª* ;::D"Quuµ44?WKKËæÍ›ïÞ½K¯#§¥¥ýþ÷¿'„¬_¿>**êÑ£G„ºº:Gßò8¡1UQQñòòâñx"‘hxx¸¼¼|Û¶mýýý«V­ºzõêÝ»w%IFFFFF†ôU555óæÍÃ_€W1>ÖÕÕýùÏŽŒŒd³Ù§OŸ––3Œ°°0¡PèàààââríÚµµk×Bìì솇‡—.]êáá1uêTBÈ–-[è—¬[·®¥¥…ÍfÞ¼y“^WQQ‰ŽŽvtt444¤Wºé^>üÇ?þ‘Çã±Ùl‡S[[+£Si™={¶tey˜LæéÓ§wíÚåàà`kkK/þ;99544 ôõõ544888444B¦OŸþé§ŸîØ±ÃÑÑÑÚÚš^;&„¸¹¹©©©Y[[ÇÇÇ9rdœë×~øazzºôaRR›Íþûßÿ¾mÛ66›M'¼3gÎdee}üñÇb±¸¸¸8555""‚®¿gÏž[·n9;;þùçùË_èt5ÖåUVVŽÿàƒÞ{ï=.—+û«3Ó¦M³³³;tèÐÂ… üýýéEd“={öp8œ¨¨¨cÇŽÑ3‚SBÈÎ;Ÿ={¶víZkkësçÎ}ôÑGjjjS¦L9wî\rr²••ÕæÍ››››-,,èúiiiÖÖÖøëð\ŒàÀˆÈègý}„¯/&Kïû¥’’;;;\²ß¨ÁÁAú›ã³fÍšèk¿ûî»[·nµÔûš9sæLÿ¶mÛð™€ßºÜÜ\}}}UUUu(Š¢(ª¢¢‚ÃáŒU‡ÅbÑY±YÐÀ>©€+û†PVVŽÄí›UUUOž<ÉÌÌLNNf±X¯÷…š3gý;ð\ˆo“I¼ÊÈÈHz;æ›ËÖ²aÏk@|ÄG@|ÄG@||e ###mmíØØXBHee¥±±1“ÉLMMë%===+W®œ={vxx8>ã÷:üp®®nRRRrr2½û³±±1—Ë---uuuë%S¦LÉËË+..þî»ïð!¿×dñÚÌ̬°°P(ÒSRRè¥%ILLŒ££ã‚ víÚÕÙÙ)£‘ŒŒ ÜÜ\BÈÑ£Gµµµ“““é§îܹ³eËSSSŸ7nH_òÓO?8pÀÜÜ|åÊ•vvv===Ò§¾ýö[KKË;w}ûâ=IDATîàCˆ¯…M›6BÚÚÚ½)3ƒÁX½zuRRRYY™……—˕ш““Shh(}¼cǎÇÓÇ÷ïß?pàÀÞ½{üñÇÇ_¸p¡¸¸˜~êàÁƒfffÅÅÅÉÉÉ c``@ÚšP(|ðàAoo/>dð:y}v±µµ uqqÉÉÉññña0„±Xüý÷ß§§§wvvN›6MGGg-ççç—””Hwïíí}ë­·–/_Nqss;zôhiiéœ9s"##ßyç髼¼¼ÜÜÜTTTð!ÄÇW‘H$ª««KHH.:óx¼ÞÞÞÈÈÈ3f”””¤¤¤L¢å™3gnß¾=$$ä—OÙØØØØØ´µµ544xzz^¸pÁÐÐPúì$6˜xŽVùÆËËkëÖ­æææ,‹.©ªªš;w®ººú£Gx<Þ [xûí·ëëë)Šª©©ÉÈÈ  W­ZuõêÕ»wïJ$’þþþŒŒ ú©îîî+V´µµééé™™™Í;÷ñãÇÒ¦Î;§««;òFIÄÇW‹Mvv¶t•™²mÛ¶ÔÔÔE‹íÙ³gÞ¼y</..ŽræÌ6›íëë{âÄ 6›½qãF±XLY·nÝÝ»wçλiÓ&%%¥tttL™2åܹsÉÉÉVVV›7onnn¶°° „ÈËËO™2% `þüù7n\¶l™´k‹e`` ¦¦†¼N!Á‘ÑÏúû!__L™½F)))±³³Ã%øMÈÍÍÕ××WUU•Q‡¢(Š¢***8ÎXuX,› Ü蓸9&ññña¢FþŠø«I$=}ú#ˆ“—““coo¿aƲ²²V‹Å\.×ÒÒ288¸½½.¾xñ¢‡‡‡½½ýäÎA ikkÇÆÆB*++™Lfjj*!D(~ñÅVVVVVV_|ñEbb"!äÁƒ¦¦¦ £µµõ…]ÔÕÕ8p`þüùØ'¯²²òôéÓ—.]ŠŽŽþ裄B¡ìú—.]êéé)((ðòò ‘H$„‰D¢©©>éÓÐÕÕMJJòööö÷÷'„s¹Ü¿ýío®®®ýýýÞÞÞæææß}÷]ffæÛo¿ýÃ?BæÍ›WVVfggçã㓟ŸÿÂ.(Šruuݶm'/;;ÛÏÏÉdª««{zzBø|>“É\³fX,Že0týÄÄDOOOyyy‡388ØØØHQPPX±bÅôéÓŸÛÅ¡C‡œ»ººdŸ‰™™Yaa¡4¿¦¤¤8::Brrrìììllläåå™LæŸþô§O>ù„®ÓÒÒòðáÃ]»vñx<:ÈÊ`hhhbb¢¨¨ˆAÄÇÉkhhÐÖÖ¦uttš›› !‹/NKK“““ëêêêèè ݾ};!D"‘äççkhhÐõŒŒ¤ë×c‘H$MMMõõõCCC²k*((lÚ´©  €ÒÖÖ&æÍ›G©ªªZ°`´ƒÁÐÕÕ¥óóóßÿ}ccc¡PX]]ÑÄÇÿ(ƒ!=^½zupp0›ÍîììÜ¿¿‚‚‚ìú2Ú>>çÏŸ§(ŠÏç+**êéé½°‹ààà¥K—¶µµç|¼¼¼¶nÝjnnÎb±è’?üá999EEE"‘H$µ´´Ðåyyy'Ož¼ÿþýû÷+++.\øã?b@ññßËØØØ×××ÍÍ-00ðøñãô,ã©S§BBBjjjèÛ³²²ÜÝÝE"!ÄÍÍMMMÍÚÚ:>>þÈ‘#ôúrww÷êÕ«­¬¬666ÙÙÙ...Ò•¸¸¸’’GGGKKË+W®øùùåååýõ¯ ¿yó&!$>>>77×ÛÛ»ªªj¬–y<›Í§勊Š0ú0ŒàÀˆÈègý}„¯/&L*£”””ØÙÙá’ü&äææêë뫪ªÊ¨CQEQg¬:,‹ÎŠÍ‚nôIÌ>À >â# >â# >â#¼~D"ÑÓ§Oqñqòrrrìíí7lØPVVöÂÊb±˜ËåZZZ···KË‹‹‹½½½MMM?ùä“ŽŽŽIœÆ¾}û˜L¦‰‰‰©©éöíÛ›šš!ÀÈÈH[[;66–RYYillÌd2SSS…B¡•••‘‘ƒÁ011qwwù[å¿TWWwàÀùóç߸qƒã‡=¯¦²²òôéÓ—.]êëësss»|ù2½ñÌX.]ºÔÓÓSPPÀçóCBB EQwî܉ˆˆxçw®]»öÙgŸŸÏd2׬Y#‹ccc FDD]?11ÑÓÓS^^žÃá 666Bäää¶nݪ©©)//¯¯¯ÿìÙ³‘]:tÈÙÙ¹««kügehhèë뛞žN133+,,”nº’’âèè8‰wjhhhbb¢¨¨ˆAÄÇÉkhhÐÖÖ¦uttš›› !‹/NKK£7¼îèè ݾ};!D"‘äççkhhÐõŒŒF®_×ÖÖúûû»ººîÛ·OZ(‘Hšššêë뇆†&šöÊËË ! ›6m*(( „´µµ ‚yóæaàà?‹×cb0ÒãÕ«WSÅf³=<<ÂÃÃd×'„Ì;7,,¬°°0&&æàÁƒÒ:'NœRVVžèÉH$úØÖÖ644ÔÅÅ%''ÇÇÇgT¿£øùù•””Hª©©}óÍ7ººº_@|| fÍšÕÚÚº`ÁBˆ@ Æ,‰DR^^naaQ]]ÝÓÓCßÉ`0lllÚÛÛé ˪ª*ú–D)mmmww÷ .<~üøwÞ‘–ËÉMxÒ·¶¶–>+BˆH$ª««KHHHNN–ý¸¸8 +¼DX¼þ;;»¸¸¸þþþÇ_¸pÁ‚ΎG …III[¶lñ÷÷—ÞzèããsþüyŠ¢ø|¾¢¢¢žž!¤¡¡!--­¿¿_$Ñ3#¿¼téÒ¶¶¶ eǘ˜˜uëÖIK¼¼¼¶nÝjnnÎb±0jðŸ„ÙÇŸ166öõõussc2™Ç§cß©S§BBBÞÿ}úöǬ¬,ww÷+W®(**º¹¹ÅÄÄX[[/\¸ðÈ‘#ô:²††Fww·››[WW—­­íW_}5r±[KKkæÌ™JJJ²Ï$::º´´”ÍfËÉÉ™››ùå—#3¨Í† ÂÃÃ¥%ÝÝÝ6lxüøqmm-›Íþ¯ÿú¯øøxÓœ<ïÈ‘#ííí***S§N=v옕•>ðBŒàÀˆÈègý}„¯/&»¸¸ŒUµ¤¤ÄÎΗ à7!77W___UUUFŠ¢(Šª¨¨àp8cÕa±XtVl4p£Obñ&ñññ^²¿vøøÊ‘H$Eá:Àëñq´œœ{{û 6”••½°²X,ær¹–––ÁÁÁííí£ž=yò¤¼¼¼@ ˜ÄiìÛ·Édš˜˜˜ššnß¾½©©‰"ŒŒŒ´µµccc !•••ÆÆÆL&355U(ZYY1 wwwÙÉu``àøñã–––žžžãy§4ì:ó3•••§OŸ¾téR__Ÿ››ÛåË—GîõòK—.]êéé)((àóù!!! ôÆ3„úúúï¾ûÎÁÁargTTT”ŸŸO©©© àñxºººIIIÉÉÉôæÚÆÆÆ\.·´´ÔÕÕ•RTTÔÝݽvíÚâââ¶êÔ)‹•››ÛÖÖæí휜¬©©‰À뤷·÷álj„~(ã`B0ûø3ÙÙÙ~~~L&S]]ÝÓÓ“Îa|>ŸÉd®Y³F,ÇÆÆ2Œˆˆº~bb¢§§§¼¼<‡Ãlll”ÆÁƒ?ûì3&“9ª‹C‡9;;wuuÿ¬ }}}ÓÓÓ !fff………ÒM·SRR'ñNW­ZµiÓ&eeåY³fY[[OnŠ^eo½õÖòåË—-[¶lÙ2óáp8K—.]²dÉ’%Kÿ âãä544hkkÓÇ:::ÍÍ̈́ŋ§¥¥Ñ^wtt„††n߾Έùùùt}###éúunnîìÙ³,X0ª}‰DÒÔÔT__?444¡344,//'„(((lÚ´©  €ÒÖÖ&æÍ›7‰wº`ÁzGì;wîTTTüòTà5#yžI|O‹×c’.CBV¯^MQ›ÍöððWPPQ¿··÷ðáÃçÏŸn'N )++Oôd¤Ó˶¶¶¡¡¡...999>>>#Ïó—üüüJJJ¤ÕÔÔ¾ùæ]]]úá7Ž9ÂårUTT0â€ø8a³fÍjmm¥§â4fI$’òòr ‹êêêžžú†HƒaccÓÞÞNOXVUUÑ·$Þ½{·©©ÉÊÊŠÒÐР¥¥uìØ±‘½ÐÓ~R[[+ 400‰Duuu ÉÉɲ_7ÖSiii)))±±±, Cˆ“agg·ÿ~KK˾¾¾ .¤¥¥ÑÙñèÑ£B¡0)));;Ûßß?66–N>>>çÏŸß±cÇíÛ·õôô!Ë—/¿ÿ>ÝàÆCBBFv|ýúõ«W¯Žÿ«*µµµ111çΓ–xyymݺÕÜÜ|rÉ¢(.—[SSóÕW_©©©ýøãªªª“[€W_zzzzz:½’)ý×ÉÉirßñŽ?cllìëëëææxüøq:#ž:u*$$¤¦¦†¾ý1++ËÝÝ]$BÜÜÜÔÔÔ¬­­ããã92ry``ÀÑÑ1++ëèÑ£#»ÐÒÒš9s¦’’’ì3‰ŽŽ.--e³ÙK–,‰ŒŒüòË/G~ÜÆÆ&;;ÛÅÅEZÒÝݽjÕ*kkë²²26›ýÁȸ•¡³³sÛ¶mÙÙÙVVVl6ÛÕÕµ¢¢£ðºZ·n³³óÈ'''''§ÉµÆ ŒˆŒ~ÖßGùúbòÈD2JII‰à7!77wåÊ•ôŒ’D"IKK»|ù2=ïHÿr EQ‰DNNîúõëg¬vX,› Üè“X¼x#ЉÄÑÑqr¿øHC|xƒä¯ßT÷>â# >Àÿ;ÜûðFþÂàÈÙÛ×½„ø˜••…Kð[‘ýÒÛœ@|”ñk@ð†À½€øˆ€øˆ€ø€øˆðïñ³Ÿ ÿðÃqE`¼ñ±»»WFQVR”cñ&ññññà?‰Ïç+))!>À¸,_¾ü—… ¸.ð\CCC¿,Äì#üŒtÍ‹×ðbÒ5k,^À‹I׬±x cúåš5¯`L¿\³Æâ5Œé—kÖX¼€Ñd¬YcñF“±fÅkMÆšõs¯••q@,^Àüsö±YЀk/Ä ÄU€qú?"eÄ~Ã\IEND®B`‚ddcui-0.3.0/screenshots/ddcui_features.png000066400000000000000000003405231427175135000206520ustar00rootroot00000000000000‰PNG  IHDRjÁ¦åÅÅsBITÛáOàtEXtSoftwareShutterc‚Ð IDATxÚìÝg\ÇßðÙ½ÎÑ^EšÒ¤ƒ¨h, Ö¿£&Æ^5–hô‰&šh%*j4н+‚‚‚4±#*½‹tŽëw»Ï‹ÕËyh¢ñ÷}ÁçnËÜÌììÞïffìpìA$I ‚ kËJ/qôôq Ãq†c8†Ñ•±£¸®ÞÊÚzÒ„O Ž€RܹÅEEr&'qÃéÊØqÚ¬P;o›H(ËeÙ’Ngp4¸ÿúî†D!„výú£ŒÎ q’®ŒI’„à ðV Íu5Ï/;Ý‘#† ×30Ôàj¾ »ùß'‡÷ï‘Ñt‚ ­¬­BAøðVcGAÍógqÎN™1›Î`´¿±\&ۻ㗃‡kp¹ÿúî!+këÇÅÅ´@o Ÿ|N„ÊödaqeqYMM=¿¦¾¹¶QPS/¬©Ö5 kêÕõüçµüç5M•Õ"¡PW[! Z]DT=¼t>ã~NËÆŒÇèÜÚ¥_›så\Ú½GÕt+s=æ¥Òþ½B½×õùŸl ¼wác3ÿìÉ£>™Áb³_»1N£Ä]8ëàäÌbküë»3™,]žÞô›ô—£J×#!ÿólZV‘BS›ÍÑÒ 1ÙR†3é8'Ô6¤‚  ÌY‡ÿÕÿô­€.}?Ÿ£6f‡¬¹s>=?Ô§;ëàÚ† Wï±¢‡i’õ÷/ÞÌ ðë¡Ù…_{¤¤®,ïIie5_(%élŽ–‘•}wË. ŠÊŒ“YåÝÜo€—9Þ…¨ýB‘‚‚Õ!¶uPˆ»1u™“”¦$f•ËH„h¦îƒ̺pÝjå£9ÏþNYZ%«/ÍyPXQ+(0:“¥¡­£ocïbõº#ײV_]ò†àoÂ0!ÄÑàvpÒ ¡±é‹½Hò_ß]éEø¨ºŒ I‘Œˆå]†s—+’ %r…‚P!…‚$ £áM…œ h4h t‘êùH¶˜AÒþÚÎ~êR ŠºiYϵmúöÑæ²p¹HȯyVüø éhoÕ…RQ™qæ™ÅÈa}iŠÒä+™¨_kQI’†u¥P¤ 0ù†ÄuÔ0}!R\˜”x {¥IÉÕöá#‚!Eùí‹Édx—"ÈW>ZQ‘q¦êuei÷è·(¦ìÙƒäl̺—G˜&‹NÊ%baScMiÞdÛ^Ù²VMªÔ–ôáüýÆxá#޵r‰ïÀ^dk»Ÿ;y¤­]†|ýÚÝ©h4𛇷©¹eEYɽÛº<}ßÀP¬µOWUË@(!!•’ÂfK›ÔТ5V7I¤ BAàLA"BAÐpB.‘76‘$I ¸ç€N âªÜ{wŠŸ G‡C0tT¿ÔI²ýµˆTçeç—>kÈÍÕïÑËËAUÞ¿”\*Å»¹ñ¶b!âÅ[#¡}-Sãb“ˆfèßω‹uòl%ø9iw¥vAá&8B‘ ‚ÁÕ2àjr¥i‰…|sž>Éöôa~Ùs¾HŽ15umíly, µ¯^ËoÆxöž&â¼ÂÊ)MÛÈÁÓÅUV˜Å‹ôåe7/V¹öw$_ËoÆxžÆÂÜÂÊF†mh€#'š[IœAª‡Ø¯DÙªa6Æ6ïaó¸JÄ•ä M{›0Ôv”w2ó6zªõ騸÷¤EYYÐ_—¬Z1ÿŠ ÅåYw§þîf, !R!'él®.‡«).¿PÚìl©‰#D4W=}˜_ZÕ$’c,m}sGGG M¼±E­êëâ„Æ«ys µ,‹Wi Šš6ŠÉ£#DJªòîÞ-z.@Ý,œ,d2KD¸¾Û`†äüÒ9¹eõ 3˜lM“ž.N&,èÌ p oÙsס½H²ÕÝ?R •Ο:P“¬¿1=ŸëÛ©ñJ’_t»Dß} ‰ŽMe÷ÓsŠj¥ˆÎÔ44µ6Ô7×¥+žg§Ü•š¹¸ùhs褔__™÷$9ÙÔ×Iö€M“>N¯Ðñ ðà1åÏgÞˆSXtÐÅB4‹€!•÷.ÞçGÓ$ësÒ+L½ƒúèÈó¯&?²Ô«Î—µ–8‰ÔbjòÕ¨PY›b˜X™Ý}˜ûX†ÛøèÓ‚ÀqüÅfòçÙéÊü­ŒGVº•%&/ëóz<ÞJY.Å—3–y»Éª3Ç- 'ïÅAQTWÕñÌ|X’Uß»r« ™@ˆ®¡ßÍÄP×ÁL#IEÍãwDfν‚¼´9 RÒXSòèÎõrŒ¯­ž“êg|}cµz~¨Ì|zžŒW’×z1s\½løwo–òz„ùjbÂçÅÙ%šaczS“( eY„–޾½xš,œIDÍM•¹sHgˆ èP?âË®s½8u­ëøîª´µ;NG¦¡¡áž‘zÝ?(\CCC(66Ôµº{ËÞÇ¿)äDcƒ¸±NÈæ²ëêEbD.•iwãÊЦ©¸Y& d"\!mÔ’)ä Љ€,#W³w‡n DÊDHÛÊÓ“†c/Î@BÐÞZR\™‘)² ó¶ÔÀ!4‰GÓPŸ~ë‘c)Od¬+ jetœ •·Íá8þꦲ Ò¢·!RŸñ°ÉÒp“‹ùÕ•åb}£¦´d¹S¿>flŒ” ›šqMn6}ôxÙ©éù±B×uðÑÔ5‹lMž™«gSMº„_/ÐÐã21RÚÜ$’„@þ2:öÞº¤L$•8®¨ÌU¸„·›8jyùRã'¥Ueün–ú66XâcM—AšHRUQohnLÍ ¬ÏºCt.ó}š®Þ¬%X/Ç€IŒÉ’µ( ¤œžÜÛMV¥˜4\5ÿ$ŽcA"„p–¦®&[Ø$cr8L$gê;šk‘¢ŠŒ,‰C˜§…’6ÕVÕ1xFÆ~<Í´wé õœ4‹Å¸€Ój=£WÇÌZ3õî3Œëþ¢Š1+Ï>¸²Š ³Ÿº†Ùëb~u…€dq´t»rs²eŽ&,8Çxm?b—¯q£NÁVw?ÿêö‹þH• ÚÚÝ¥·gÊõx*j ˆc˜P(L¹ïÒÛ³ÕÝÕÃG©T¢\$‰êkê„õœfP•WI$‰R±B‰š%â>)átÉ›µ4ákoü¼8[óK0k"¥Uw.e•Ši†^A¾6ª³LPTÚÞÚ‚<©µ—…†äõÒrÅ ºœ`[Ú{˜VÝ©UvÅ 9ÑFhEÊ¥R©S !äÕ÷Sï–SŽÅµíúxõТ©ÜºÓØ âZqq„¬®ºQßÊ›&—HÂÙzf¶ˆ¬{œ/·ö6ec¤äYÖ¥Û2LÛ9 ÈIK×ÞV÷\ösMjج˜œœ+ÂL=õ5¦ëêó$wï$H=FxšÓˆª»Éwj¹\öË ƒ˜¸83ñVbp 1†±Ýëo­PR©ìè-)®4Ò7·±22Í4(·¨’ÕÍœZ)x®°íÛéÌËË*ÿ èÆÖ’û 9n*ea3¤¬×'ûW1ͼN*¿› vW­UCô¬¦wëõŒ"岿*J½˜²ÂFû^/Ûá­R ÃÐ3PÙ%M"Ž%GdSá½´» C8C϶—«M&‘ÂIÀkû_K$¢Žoa8ªµµ{¿ˆ!Ô‹„KçT7hw=##“ŒÔëTìHdFêu##=ƒVwWU»(ÅRiSm¸ILJ¥A DMÌ! …B!• ’ ÑqœiÑ¥2|´ý_ÙÐÔÖ’Wø+µêfXs÷ymëõ¬v|[“FÓÒÑ JQÁ¶÷ïYw³¤FfcAÝ'ÅâiÖV×ImŒ´†ö ùµÏ* ËšÌ{ràË€ô#¾¼ãX¡P „¯\lkËþƒBt:ŽÂpœË[öV¹¤ýÝŸ?«¬zVéNÅŽ8†y÷ JIŠ×ÒÖ146i¹{‹ðQå¹"¡ØÞFÏ@WJg0h8Žc8I(BF$NÃ0œ ‚$å …OC(“¯<3Ðvïã_ç A4œD4DP£•TèÓÞZôê ’ êfR9{Ã0R!—´¿†¼_ýxÕ³•$ÈÖ†² RÙ•Çæ²››ÒÁz†:ÙE%Bž%“KšëªžI´4ÈWƒK¡VK(4†°1¦Ò’$¡ ŸH™DÊb3H‚ük˜¤ÝÄ[ ‘¯N§iÌ/i°sä1¼ª¨DHê¶ž:›yµV+ Ù‘l«‘„Ú@ÍbŒ§Ç‘5”<,½_/auïÔǘ¥ilª™["AZT¶š*óÊ*ûIhæZ´’W‚h¢EÞˆWé«L}]1_Í!ÍØÉîɽë)uÖ–)ŒçìæÜj÷?š9Þ¹s[ÏßÓDCÛÜ£¿¹;APS¨E¹iO™Ý8…¹¶îflÏÁ:M"\S‡#EÃÓü:žMÖV÷Îd š›I¤‹{…ðÅÍ%Ùwøj™D\ ìvGW-Ô«%À¸=zÒ]=›Šéöpµ”ÜiP®àè¡®d^- fsØjeyt· +Ù~ñ;^&¬h{õq¶°w¦…¨YîdsU¥PÏÜC«øNnywwsMk¿A:Õuœ£©£«É¨º{![a¤–“Ò'Ù4iûõÜf#ÆÕعtc{~&Ñ9Lœ|Ù-)©È©5ð8kjhŠI¶¾!E_Àá²á뀎ô>ªÇçÛxv£j‡c8u~½ÙÝ}B®'\¢ÑhÝ{8èw3ÔÔÔºžpQ—§ïêî) [îÞ"||5¨‹ÅP&“"„›êꫵµu1„ë=zÄãé"„èt††GCCšÆ1íe–•üÔÍÃÚPÇÀ@Qñø¾À©·ù‹‰Ùí®¥wsvj¾{-ƒïÜÃÒX—«Í•‹šŸ×ÊttLº•=J/àxXés8¬†²;wXnîfÌVzËÈÎŽhظõÈ»—_ÕÝÑÒÔP›zZ¿º²¨œaeif¨(¹{5‹ïbki¤£¥EH›ªKrŸ>©3p±Ý/|¥—NõÒ©mÅ)¿—§ïae ©¡«ÏÁ«Ñ2“LCg~Ç¥P$IªÞ~Nâ³^F¢ÑñÚ•Ípm'þƒNg^-äâšÙr¾R’®%Íî|¶_Ð2±©}öà!ab¢¯«Éf±hr‰°±ª<÷a%×ÅE—k96ß¾šÙÔ«‡¥±Ž¡)’‰E‚gEÏJdÆf榘øÑ+9‘:Œöê™TïIUÁ46jÈJ~âÖÇÆKGM%·JY½=ÍYˆ 8CGÙPYYoÈÓæiБLT_Zöøaƒ™³3›„©ðt ÷ñ•ácï¾mmI¼Òÿ‡‘/ºßäîª) OO¿·BHÐÌW˳Ú% ÛôÝ7 –¬ª«yþÊG„\® ®ÄAÐh´—?À»>Êår—››û^”9""bïÞ½ïõa{¿Šð~5¼™ðQ&“988ÄÄĨ.‰DVVV'Nœ Ñhßÿ½¡¡á?™õ[·nñx¼Ï>ûìµ[öïßÿþýÊ·_|ñEß¾}ÿ­¯¨¨øâ‹/ ÝÝÝ×®]+‹ÛßE,óx¼‚‚‚w¡ÑÑÑ‹/V‹e×®] çáã+ ÆøñãUƒ0„Љ' Æ!C0 ›6mšŽÎ?úìñ˜˜wêÔ©úúúNí8tèPGGÇ¥º+++ÃÂÂjkkO:UXXøë¯¿ž9sfôèÑr¹ü}) |ì¨I“&ݽ{÷þýûªÜøñã™L¦êè$I’{÷îõõõµ´´ ¹~ý:B¨¡¡A__¿¬¬ !”’’ÂãñöíÛ‡R(ÖÖÖ™™™ÍwSSÓ‰'¾ûî;mmíÇ+—ýïÿspp°²²Šˆˆhll\±bѾýö[ & WG~>|8tèPkkëÞ½{ÿý÷TwùòeWW×M›6………¹»»Ïž=[&“!„d2Ù‚ ¨Ä]]]9ÒÙl÷Ýw:::trrâr¹þþþGÍÈÈ8vìõ¹...kÖ¬‰ˆˆèÛ·ï¢E‹¨ŽÉáÇS=<<6oÞ¬V„S§Nùûû[XXœ9s†ZøöŠÐ¾’’’‰'ÚÛÛ;::.Z´H(ªmÐVð ­¬¬BCC©°!”“““••õ¿ÿýOm³={ölÙ²e×®]EEEK—.?~|ii©®®®››[bb"B(11ÑÖÖ–z}ç΂ ÜÝÝ;›ï#GްX¬ÈÈÈÑ£G+‡ÔÁ°aÃLMM333óóó׬YC§Ó¿ýö[—+Vܾ}û?þPM¤¡¡!222((èÉ“'±±±‡úå—ÿA¼´´TCCãêÕ«©©©·oß>tèõ¡ééééééÅÅÅñññ½{÷îl¶ãââFE£ÑTkÕßßÿÊ•+ÔÛ²²2mmíK—.%%%¬_¿!túôiêïíÛ·çÍ›§š`jjêgŸ}¶zõê•+WN›6-##ã­¡"‘hèСvvv÷îÝKMM-**Z±bEËÍZ-#þƒá#BhòäÉG‰D¡½{÷ÚÚÚªm³cÇŽ/¿üÒÅÅÇñúûûS]bÁÁÁÊðqÙ²eׯ_'"))) €N§w6ßûöí9r$‹Åš8qâÓ§OSSSB/^”ËåëÖ­ÓÖÖ¦ÓéÞÞÞ\.·D.]º¤¡¡±hÑ"‹eoo?wî\åè<—Ë¥fU²ÙìÐÐÐÛ·o#„X,ŸÏðàT*544tppèl¶kkkMMMÕšššVWWS¯™LæÌ™3©_|ñÅÁƒÛOðàÁƒ‘‘‘ááát:}À€C† 9pàÀ[-BèÀ¶*²²²¨å/^D­\¹’Ãáðx¼åË—ÇÆÆ¶Ü½³eÀ{>4ˆÃáœ8qB,ÇÆÆNž<¹å6ÅÅÅß}÷÷K÷ï߯««C…„„ܸq£©©ééÓ§C† 144¼wï^bbbHHHg3™™™MD;88xzzR#¹%%%666ª}{í+//·²²Â0ŒzkccSQQA½ÖÓÓS.g³ÙÍÍÍ¡#FLŸ>}ÅŠ666cÆŒyòäIgs®¯¯_YY©¶°²²ÒÀÀ€z­««Ëd2©×FFF555‰¤ý"ØØØ(ßÚØØ”——¿Õ"P‰ÜPáêêª<ôÕÕÕÊCÿé§Ÿ2™Ì¦¦&µÝ;[F¼S:×íG§Ó'L˜°oß>Ç ÆG}Ôr ‹eË–EEE©-÷õõmjjÚ±c‡··7“É ½xñbffæ¦M›:›i*X=z4õ–êNÛ°aƒ¥¥eQQA8þJX¬Œ¢Ô˜™™•””$ImPTTÔ²kð•XÇgÍš5kÖ¬ÆÆÆU«VÍœ93!!¡S9?zôè¼yó”1niiirrò?þH½­­­åóùZZZ¡‚‚‹%•JÛJÐÌ̬¸¸Xù¶¨¨ÈÌÌì­!¤¡¡¡ZQ CyèÍÍÍ•£çJj7µZF8€÷E§Ÿû8iÒ¤¬¬¬ 6P7Í´Ü`ÆŒëÖ­£&5ŠÅâ”””ÂÂB„‹Åòõõýå—_¨îÆíÛ·óx<{{ûNe ±±ñÔ©SëׯWö~effjjjþù矃 Â0lÅŠ|>_.—gff „±±q^^^ˤ"""š››·lÙ"•Jsss·lÙ2qâÄv>:%%åþýû …‚Ëåêèèt¼›SiéÒ¥õõõ“&Mzüø±@ ¸yóæ¨Q£úôé£ …BË—/‹Å•••?üðÃØ±cBL&“ÇãµZ„qãÆ>þܹsT§ìÛ+B; $‘HÖ®]ËçóI’,//¿téR«[¶,#þ³á£¥¥ehhhIIIË›f(Ÿ~úéܹsgÍšemmíââ²eËeçSHHŸÏ§ÂG±XÜ…‘ë#GŽhjjNš4Éð%33³O>ù$&&†Ëåž9s¦°°ÐÝÝÝÖÖvÕªUÔGÏ™3çòåËÖÖÖC‡UMJWW÷ĉñññööö#FŒ=zôìÙ³Ûù說ªéÓ§[[[;88Ü¿ÿ×_ílæÍÌÌ´´´† fcc3sæÌÁƒ?~\9ûÓÔÔ´Gîîî^^^Ë–-£–¯ZµjÞ¼yÖÖÖëÖ­SMÐÏÏoëÖ­Ë–-³¶¶^¹råo¿ýæããóñ+Þ IDATV‹Ð.—{öìÙÂÂB///++«¨¨¨Ç·Ü¬­2ཀ-œóùÆ-ÛDBBH"•Aü‹._¾¼xñbÕG#Að.`1¡òÒ¢íÛ¶vtî#ÇkkUgŸÚ Þ¶¶)ü} !òxÀÁÀÛƒC¼;øŸÕýÊ@ø„ ó^™ûØò¢`meÙzøØ£G¨ F.“¶>µÚs„àíxeðš$Éÿvióóó›››ëêêàÀw–žžž––V÷îÝ¡*?ùùù$IúøøÀQ@ @øø¡hnnöööþÏ÷°¾=ÎÎÎP„ùo‡V0fýFêâoà×Þ­3iii4Mõ€ð±Mþþþj/À®½Ák¹\®ö¼>@˜ÊëözÓÓÓétºê‹ ÿý÷ß;›­k×®ÙØØ¼íÐç¸}ûvòÝ'º8x=bÄ.—Ëårõõõ{öì9eÊ”[·n)×Ξ=û½ï:tèìÙ³U—­X±‚z­­­M£Ñh4š¾¾þ€îÞ½«¶{XX­…¨¨(*àŽŒŒ455ÕÖÖöõõ½páµKUUÕ§Ÿ~jkkËår7mÚ¤LmþüùÐ"ð‡r¹œ¶V¾P5}úôÆÆÆÒÒÒ'N‡……|X"‘\TTôý÷߯^½ZÙMûñÇ;;;C‹À;®½¹~~~r¹\ùBmgÆápþïÿþÏç/\¸pذa8އ‡‡3æÓO?---3gNVV–B¡055‰‰qvv^¶lYAA›Í...Ó¦M›6mšòÓ©¿;wîܱcGYY™®®nTTÔêÕ«™LæÞ½{·mÛ–™™I}zII‰‹‹ËÝ»w¹\îèÑ£ß|pãt:ÝÔÔtöìÙÇŽ«¬¬433S®e2™Ê×YYYÓ¦MÛ¹s'Õƒ­\µtéÒÍ›7gff:;;;;;oذZ>lذˆˆˆäääO?ý!4~üø3füÃ- ¦¦&%%¥årƒ–ËaøaXá£???µí3fÌÞ½{?~ܳgOåÂ5kÖçåå1Œ¼¼Ÿ?|øð5kÖèèè „Œ•›%''+£êo\\Ü–-[ŠŠŠH’ …VVVÔò)S¦ 8pÆ )))"‘hÈ!3¦‰ŽŽ^½zµòíÈ‘#U×nذaÈ!:::l6»ÕÝ Ÿqã¸\îîÝ»[®­ªªŠˆˆÞ¸q£Z\>eÊ”ÂÂÂóçϳX¬w¡PáãéÓ§‡®J¶‚Ãi|pTF¯Ûë}ìÔàõ‘#GŒŒŒUòx¼ 68pà˜1cV­ZE­b04M DFF"„Ž;F§ÓÅb1FS-Ý¿K-úxMø¨6.™™™éçç'“É”/T×îÚµk×®],ËÐÐÐÇÇ'..ÎËËKuäš$ÉÛ·o/Y²¤¡¡ACC#<<|Ñ¢EÔòÈÈÈëׯ/Y²DKKkåÊ• P¼677_·nÝСC ttt§LyäÈ‘K—.íÓ§½½=µðôéÓúúúÔÿIëׯçóùžžžª ²³³cbbJKKøáe‡ëêÕ«¿þúëäääk×®!„ºuëF- ‹‹‹{Z ^¤¿†R±…s>߸e›H(@ɯ<×ê“ÉdÊoäÿþúëÚÚÚíÛ·w9…Þ½{õÕWcÇŽíÔ^ÉÉÉýû÷‡ƒÿw\¹ržm|€è4!T^Z´}ÛÖö¯•ñ¢Zà¨|þN«šššÞjî;ÖÜÜüÏ÷5ÔþÜǶ¯ßv€Ø;;;‚ ¶nÝúŽÜ° ðA‡jÓÚúöíKMIT¾x#¹víZÔÕ)tÔ#$ÌÀû÷@Í>¶©­ÁkáãŸê#ÍA—ë*€ðñ/ÿíèŠËåæää899!„TŸã ^‹j=ÒÔÔ„€ðñCaiiYRR’••U__¾³x<ž¦¦¦……TáãÄÒÒ9À a\t"|LKKƒj‚ƒ[ƒ‚‚ v@ dëácll,Ô P5yòd‘PÐzøˆŠŒŒ„:mÁ¡ „ÂGá#€ð@ø |„*>„ÂGá#€ðª@ø |ïWøHÄÎ;Œ»wïuÿþýŽì¸yóf·yóæ×nillÌãñ,X@½2dÇ»uë*Ð5T‹âñxÆÆÆ~~~§NB]¹r…Çã;–Ú¦ÿþ<oÛ¶m!¡PØ­[7kkk’$•‰XYYñZøå—_ÞlV?úè#wîÜ9å’~ýúñx¼„„„V· äñxp”¼»áãœ9s¾úê«ŠŠŠ©S§N™2E(Þ»wïmdëÀpxÀ›òå—_Ž?>''gúôé555>>>8ާ¥¥‘$)‹©_A©©©¡ŒŒ ¹\îããƒa˜jË_¸pá¨Q£BFFF .\¸p¡··÷›Íä¸qãBGŽ¡Þæççß¾}ÛØØ8$$Ž €÷2||ôèÑÁƒ™LæåË—×­[·bÅŠK—.Q_¨×¯_0`€¹¹¹““Óœ9sêëëBµµµcÇŽµ´´|øùóç©íårytttBBš5k6nܘšš­:JˆÂq|Ö¬Y'OžTëÚŒˆˆØ¾}{ll¬§§çæÍ›Oœ8¡\uüøñÑ£Gã8¾lÙ²]»v}þùçuuu , ¢  `Ô¨Q|>ûöíÓ§Oß³gϲeËàÀhjjj233«ªªôôô•bjjjZZš––Ö´iÓjjjrss[ [š={6Bh×®]¡cÇŽ‘$9eÊåÚŸþÙØØxíÚµ l„\.wèСR©”a?vìBh̘1,kêÔ©û÷ïß¿?†a3gÎ,++k¹;FS[rìØ± 8::îÛ·ÏÃÃcéÒ¥-CO ³è?‰øøx‰DB gOœ8ñèÑ£qqqR©ôÚµk¡ŸþÙÀÀ ´´tëÖ­¡§OŸ>yòÃ0êÛW¡P455ÙØØ¨¦ùÅ_üþûïkÖ¬Q.‘ÉdÕÕÕK—.­©©‘J¥¡{÷î1‚Z;kÖ¬™3g&%%]»vmÉ’%Æ ‹}òäIMMM||¼X,~òäɤI“”†ÿ¡ñ÷÷Gihh>|˜ËåRâ®]»RRR¼½½ýüüp¿qãÆ­[·X,VïÞ½ÛOÐÑѱ_¿~W®\)--ÕÑÑùøã•k¿üòK‡©S§ÎŸ??>>ÞÆÆ¦ƒpìØ±GŽ9|ø°‹‹KAA»»»££cYYÙõë×7oÞÜÐÐ ‘Härù£GÌÍÍ_[ê3gÎ „Ο?þüyêGZ||<5büá#5ÓëÞ½{¹¹¹ÊH±XL½P(F¡¾®Øl6BˆÅb©.´··ß»w/µ„ “–Ý0‹-úꫯ´µµ©%‡Ú¾}ûG}´bÅŠóçÏûí·"‘H¹½BˆÁ` „ •ù‘ËåÔ'FGGSk«Yÿy;vìHOOß³gÏüùó¯^½Êd2ýüüB7oÞsçÎÕÑÑqrrÚ¾}»H$êÛ·¯²Å¶cÖ¬Y ‹-¢¦Tr8å*‰D‚¢~ç(›}GaPP¹¹yFFÆ÷ßOE“¡Õ«WŸ={öë¯¿ŽŒŒ\¹råÅ‹U?BˆN§S­!TWW§v®_¿žŠž©3 €¿©ƒ×NNN&LJ¥\²dÉêÕ«Îb±:ôûï¿ÏŸ?_,8Édöë×!´nݺ«W¯R³¸BöööOž<9{ölYYY\\ܼyó¨SÍäÉ“­¬¬šššT¿©á¹‹/v<Ûýû÷g³Ù/^¼}ûvAA†ÂÿЄ„„lÚ´ÉÏÏ/;;›q622²±±yöìŸÏ§†ªûöí›››‹òõõí`š½zõŠ‹‹C©Ž\#„–.]ºgÏž_ý!ÞñFˆaXtt4BèÊ•+ #**JÙøétz]]5AS¡¡¡††FnnîÑ£G—,Y¢\>|øp„о}û ²³³7nÜH ÿPøˆÚ²eËúõëMLLbbböìÙCñÙÚÚÆÆÆÚÚÚ~óÍ7W®\™8q"õ@“uëÖ 8ðÀk×®UÞ£J§Óccc###ÿý÷‰'îÛ·¯­ÛW™L¦êü°ñãÇ÷ïßÿÊ•+“'OîÑ£GÇóܽ{÷£G:99-[¶lÆŒIII^^^pà?LÔtˆM›6566¢—™L¦‡‡R™ïøÚ‰JÔ4_j>¥jd¹eË‘H´|ùò~ýúuªR7è „  ¯¯O£ÎÎÎ?üðÚ5kÜÜÜZîB§Ó7nܨ­­½|ùrÕy #GŽüñÇårùÔ©S¿üòËêêjggghþ&láœÏ7nÙ& BGbFFFB¥ÐYYYGŽÙµkמ={”>|˜mjj Uà¿AWW—ŠËK‹¶oÛJ‡ k&NœX__?eÊøÑàƒá#]ôèÑ£– oܸ5à¿ þç5€ð@ø |ï“NÜ:“žžõðŸäããóæÃG„PeeåÛÈîäÉ“cbbà°w¶]½›Ií³°° #!D’$õÏlI’$‚zM­B%''w<ÙN?¸çí=âžÞñvõn&´%++Kõ­2|T %I’ÄñÎÍf„¹ÂGðvÀøPœ9s†$É!C†@ø^;Ráãߌ aðà¿ïôéÓgΜ¡^Ÿ={öìÙ³ïPø¸qãFWWWWW×õë×SKV­ZåîîîääzóæÍŽ$âàà@Ý„êÙ³gNNοUÝ7n”ËåÜ8::úòåË]û ¿³/è`»êÕ«—‡‡GŸ>}¨§ç¬_¿~îܹÔÚ„„÷ðáCêíøñã÷îÝÛÙ&*—Ëׯ_ïîîîêêêééùÍ7ßH¥Ò.dU"‘¬ZµªW¯^ÎÎÎ~~~'Nœ€Ã÷fÅÆÆtpã;w†víƒ~ùå—+V¼ÁËÑÚµkßF…¤¥¥EDD¼wÇqãÆÊïU#GŽ|üø1BH$M:ÕÕÕµOŸ>.\h'©Ë—/{zzºººNžÜµkBÈÂÂÂÊÊêüùóPÏàý2|øðÝ»wÿþÒÎ;wîÜ9tèÐ:|ÌËËsvv.**¢¬I“&!„Ž?­©©ÉápÆŒsüøq„ШQ£tuuB¡¡¡ ü6]¶lÙÿýßÿQ¿ö”nݺ5dȰ°°ÄÄD„ÐŒ3¨OÙºu«¹¹9µ½¿¿ÿ“'OTw¬¨¨˜0a‚ŸŸŸ¿¿ÿ–-[Bà‹/¾ðóóëÛ·ï?þHmf``ðÓO?M›6-,,Œ É×®]+•J£¢¢† "6nÜ8uêÔ©S§~üñljdË–-}ûöõóóûüóÏÛ*×O?ýôå—_R¯»wïÞÜÜœœœ<`À€àà`ÿ£GªíúàÁêõ!CÒÒÒBUUUÿûßÿ¶mÛgÂßáææÆãñ***¼¼¼ÊÊʪªª¨ðqñâÅTøøðáC&“Ù£GN5Ñâââ'NlÛ¶­[·n!‡3oÞ<==½Îf¯¢¢âÏ?ÿܺu«ŽŽBÈÕÕuéÒ¥?üðu®M:õóÏ?ŽŽŽŽŽ‰D!©TºbÅŠ°°°ÀÀÀÙ³g‹Åbµ[6Tµ–¬úciÆŒü±››Û´iÓîÞ½;xð`77·•+WRDFFúûû]¹rEyâlܸqòäÉ»wïn¿¡v0ÿ………^^^!‚ ¬­­©ïò³gÏN™2E55‰Dòõ×_÷íÛ7 `òäÉíVõCOŸ>••µråJêüJKK ^°`Áرc322¨ssذayyy­£ÌÌL???åÛðð𤤤êêêaÆ…„„ôíÛ·eãŠ+~ûí7êõúõë7nÜØÖ±Û¼y³ŸŸ_HHHpp0Õ8U•••EEEyzz*+pûöíýúõ êß¿ÿ½{÷ں켶H$’éÓ§‡‡‡‡‡‡+/¡‡êׯ_HHHTTTqqq[yŽŒŒ\¾|ùôéÓ ´zõjµ”‹ŠŠ ðý÷ßS§›Ú5°Õ*m5ÍÍÍS¦Lñ÷÷9rd«hÿþýQQQÔëãÇO:!dggçááqéÒ%±XDuÃܼyÓÓÓ³©©)..ÎÅÅÅÉÉ !ôÉ'ŸP_+®®®^^^†q¹\ooï²²2*Í#Fìß¿.¤àCÖõð±GkÖ¬ùä“O’’’>üË/¿ „JJJ,,,¨ ,--•'e×®]AAAÔ7âky{{;::îÛ·O¹¤±±qîܹ»wïNLLûì³çÏŸS{™››ÇÄÄ̘1ãµ µ#ù·±±‘H$wïÞµ··WžãAAAªIýøã%%%IIIÉÉÉ›6mj§°j:|øð>}ú¬Y³æÜ¹s¾¾¾¡ÇÏš5ëÏ?ÿìѣnj3víÚ•’’2zôèO?ý´Õcäåå%—Ë©X-77÷ùóçAAAÚÚÚ‡JLLLNNÎËËS†×íhYv‘HôË/¿$&&&&&^¾|™Çã©í’••µgÏž[·n1™LªGŽ™pýúõ 6,X° ­ËNûí„jÀ3f̈Ÿ={öôéÓB©©©Ç¿páBbbâŒ3æÏŸßN{“J¥;wî<þüÙ³g©Ö¢3xðàk×®%''öÙg¡–×ÀV«´Õ |ÿý÷ÚÚÚT#luB5’@½.--UûVb³Ù{öìY¶lYVVÖÌ™3wíÚ¥­­­öåU^^®:<]WWwüøqå}ÞÞÞÉÉÉÊÿÕÀèoÝy=bĈ¤¤¤èèè .hkk«­U›rêÔ©ƒž;w®ãé¯\¹2**jüøñÔÛŒŒŒªª*êw$BˆÍf—••oذA&“-Z´(11±¼¼\í‹_ ܺuëôéÓÔ[}}}„Pbbâúõë1 ÓÒÒ=ztbb"5ï§ÿþ!333>Ÿ/‹Ùl¶Z®úõëG-LLLŒŠŠÒÔÔ¤~­R×µ–LLL\\\._¾ýì³Ïš››étzvvv[—öÛ uLûôéC rÍ;·¾¾þÒ¥KEEE#FŒ š%5òÛV:Taq·³³+**²µµU¦ìëë»téÒ†††€€€ààà¶®-«´Õ $%%QCF<¯åÐAUUU­þŠSžY=zôX¹råÀ׬YãîîÞþ (ÆŽ;}úte稖–I’õõõT«ÂÇΑÉd999ºººÊá ‹’’åo>sssêõéÓ§×­[wòäI##£Ž§ïää¢î!¢{÷î-P:~ôèQOOÏàßMâ IDATàà˜˜˜ŠŠ µ.ж¾¡1 S¾U¾f0/:fq¼ÕYP§ýZ7nÜŸþéààP]]€úꫯ‚‚‚¨™4ýúõSE¢ÓéÊëÕ@ýoÊcÇŽµú}:îèÑ£...'NœøüóϽ¼¼ŒæÍ›§££ãïïòóó»qãFjjê·ß~ÛÙ&êææVRRòüùó¿Ùéä䤖Nzzº““©6Qj®!AÔ`b§šº²%«QvFÒh4e{£Ñhr¹¼e\«–ZGjó_UUõóÏ?ß¾}ûäÉ“"‘ˆŠðþæyÝêͶÎëvNí1cƯ^½:66–º'c÷îÝååågÏže2™«V­jÿ¼¦Óém•ýâÅ‹™™™7nÜ?pà€‡‡G[ˆ:('N|¸rê‚òRÜj:íTrDD„‡‡Çµk×vîܹwïÞýû÷·z lY¥­f!D ªª„ã8“ÉTþø777/))133£¾•|||¨ÍîÝ»§¯¯_QQ¡üòºvíšòËËÌÌŒ:î`äÈ‘ýû÷WÞcGUŽL&kë à]¦¼ ©¾h'€iËߺufõêÕNNNgÏž]¼x15NËçó…BááÇ©Ù'§NZ»víÉ“'•ÑdÇ-[¶lûöíÔMpÞÞÞ………Êñ ÌÌLå×ÌúõëCBBŒŒŒø|þ•+W¨_·JÔ´åKuu5B(44tïÞ½$IòùüØØØ¶ò ­­ÝêlëÐÐÐcÇŽñù|’$÷ìÙÓN }ôQFFÆ–-[¨ßÓ¡úúzjx=77W9ÍQÉÚÚšºgêÀ@ijjúúúnذúú),,¬©©Ó Ë¢¢¢"""¨ÉgžžžeeegΜ¡¾býüüvïÞÍf³_©´l¢VVV‘‘‘3gΤ†t…BáæÍ›ëêê:›=33³èèèY³f566"„]*•vëÖêkËøñã§NºuëVêí'Ÿ|2uêÔ)S¦Ðh´Þ½{«m}¨û{>œ™™YRR²gÏ„ÐàÁƒ©ßœW¯^6l\EÁ{ÇãùùùQSu•3¬H’¤‹¨>~jKjFJG{1Îù|ã–m"¡!t$öhddd[›¦§§WVV¶³A—éêêÆÄļ”Á‡ì ¶«w3)@«êêê† võêUå÷D5©€à—­>ª¾P†$Iâ8žœœ¬œÝÑê—+–—mß¶þë €ÿ==½U«V•––¾Ä+++©Q ¨gð!ƒÿy à¿æµ÷¼w™™™ÄŽ@ï#€ð@øþu›û¨ü¯²oÜÛK|ÈÞ`»z7“Þõð1&&æ-}Ç¿¥”Á;¾©võn&´ïµeý'ÂG„ÐÛ{^< ¼ãíê­&URR" ëëëßñúäñx\.·å“ù¼ƒ¨ÿ]÷7®¤¤Çñvž×úNyøðaii)DðÁ‚[gø÷ …Bggç÷%·½zõ¢þß1ÿŽwÌú}Ï0À¿æ>þ?{oåúÿñ_cdi¦íœŽ¤ädÉR²Ù™J8C'ulçCQN$„>å{PÑFdgêH()k–¶ó![©lm¶1–aæ÷Çõ{ÌÏÏÊI§ëù×=×}ßïë}_÷û¾ï×ý¾®ëb^ÿº@ ˆùÏçÏ>†††ÊÊÊÊÊÊ.ðàÁÒ¥KÇN†¸¸¸´´´¼¼üÆgô•“òòò‚‚‚Ïu,T*UUUUGGçÇÓÙþÕ«WqqqsqžLMMKJJ>—Ÿ€S§Nùøø|ö›ÏïÛ·.ççç„ÇßÖÖÖ111ð ÚÚÚJHHHHH˜˜˜TUUM¢D"‘­ù¤¤¤êêêÃÃÃÁÁÁ6l••UPP8zôèÐÐЬ}~ÿþ½ '''…BÙ»w¯¡¡¡§§çôw§Ñh‚‚‚è6‡@ ˆy-KKKSRRîÞ½[QQ‘™™YXXË<==I$ÒôM%%%=|øðâÅ‹/_¾œ¾|dW:5###Ý&&&&,,ìöíÛ‹-š¦|ŒŸ¦«Óq`šÌÔÏÙµØ×‘H,--…Ë%%% P‘³X¬²²2 ááa33311±šššºººÝ»w¿xñb2ƒ===éééc ]]]ïß¿óæÍªªªââb<O£ÑfíóâÅ‹ƒ‚‚888Μ9••STT„î\ø*åcccãºuëššš¡¡¡»wïdddXZZòóóóòòîØ±###nðË/¿|ÿý÷3­ENNŽ@ ¼zõ pÿþ}###---˜0kjjÚ¼y³¶¶6‘H<~üøóçÏcccÓÒÒŒŒŒÎ;ˆˆˆPUUUSS£P(ð)jggggg÷ÓO? &&&êêêjii‘ÉäæææÑU9räï¿ÿöôôüõ×_ VdeeÅNòÅÅÅ©««‰D]]ÝwïÞùúúÖ××¹ººòóó555ÕÕÕ¡VÓÔÔtwwß¹sgRR’’’»:--­»wïŽvàéÓ§úúúºººt:vttØØØèèè‰ÄÈÈÈ1~¾}ûÖØØXKKKUU&>>>gΜËÁÁÁ¡¡¡ì*Æ´Øàà ½½=‘HÔÒÒÚ±cÇ¿,ÖÛÚÚ::: |ôðð€òññãÇ8NLLìêÕ«X,ÖËË ‹Åb02™lhhÈnºñ>|8((ˆÁ`°Kš››©TjddäÒ¥K¼¼¼û÷¦ŸB° tuuz{{ýõW///;;;èd¿§§§££ãáÇ0÷éââ¸~ýº••Õ¡C‡¬­­á+™Ý‚ ÂÂÂH$77÷ÀÀ@vv¶½½½———µµukk+ºE"b<³û(&&`kkëçç—œœ|ûöm@KK ûÛu+W®„"ïîÝ»AAA=ši-EEEx<^FF¦»»{ß¾}T*õ»ï¾{ýúµAeeellì–-[\\\à“UPPpÏž=ÝÝÝ~~~€[·n¥¤¤äååñññ9;;;v PSSSPPÀÃÃSVV–‘‘‘ÍÍÍ}ãÆ 777*•Ê®úرcÇß°aü¹xñbÀÉ“'#""üýý‹‹‹ÃÃÃsss—-[F£Ñ¸¸¸¼¼¼²²²o߾ݻwovvöÚµk/_¾loo[£¾¾>&&FTTpùòåÂÂBMMÍ{÷î ©©©>ö½{÷R(”íÛ·?|øP__Ÿ]xàÀ ÁÁA…Ñ~BAÌÏÏ?22òóÏ?çåå±wœQQÑ1-ÖÛÛ EUOOÏ¿,Ö¹¹¹KJJH$Rww·žžž§§'‹Å*))ÑÐЀ¡¤¤„Á`Ø»(++§¤¤LfPIIIBBâÒ¥Kööö°¤ªªjåʕ˖-›…{“}d±XL&“B¡¼|ù²¬¬LOOÏÐÐÅby{{KKK;99±X,eeå¶¶6vþüy@PP‹Åòóó;{öìÉ“'áµiooßÐÐ ššjooŸ}þüù¼¼<œœœsçε··»»»WUUqqq%%%¹¸¸\¹rÝ%ñÙä#ÀÌ̬°°ÐÒÒ2;;{ü+ø8¤ÓéžžžIII35¾}ûv&“ùîÝ»K—.ñððwttØÙÙÁµ<<ŽARR²®®ÎÝÝ]CCÃÀÀàß¥x<^YY™ƒƒC\\¼¦¦¦¤¤ì,&¯øúú’ÉdkkkvÌÏÅ ŽÈÈH‹E¡P,--q8ŒÞÖÖV8:ó‡~xö왪ªê,,,¶oß~àÀ1F ÅÄÄjjj666 ƒ‹‹  §§pppHHH Óép„(Ngç¼ølò‘Á`ÔÕÕáñxØ!niiË­­­+V¬xöìÙ«W¯6oÞ èììäààèéé ú¨ñ´´4*•J¡P™L¦¨¨(Lì±ùñÇåååïܹsöìÙ˜˜˜1ÓVX,ÖèL{™——.0™L__ß:S]]ç[äååEDDL'™4ºv¶ìÚÛ¶m;zôhUUÕ;wÂÂÂÆžNN¶ø˜g2™,+==Êßñ\¸páåË—×®]Ãáp~~~Ð[Ó qrNzÒ…„„ÊËË‹ŠŠîܹãïï_ZZÊÇÇ÷o w"‘¸ÿþ… ª««CU\\\VV––}â***äää¦ÜZZZìn99¹–––7oÞÌ.95 ÆÕÕÕÄĤ®®žS'''(|‡††0 WmmmnnnttôñãÇ+++Ç[ýjÇþÉÍÍÍ._±bßOÐ-@ ä5>egIIÉk×®yxx´µµÈdrjjjoo/NONN&“É222UUUUUU;vì P(ÓÑŽlÈd2‰D URRzñâE^^,¿wïàùóç‹/¶´´ôóó{øð!@PP°»»n£­­žžÞÛÛËb±.^¼¨¥¥5Æ8‰DJLL„C Æ}ëË–-#ö€N‰”œœüæÍ@OOÏàààèÚ«««ëëë—/_–””\¸páxhcc³sçN2™Œö¹½½Åb‘H¤ÀÀÀ¡¡¡·oßþËÂ]AA¡­­-33“H$Bùxá˜611a0¿ÿþ;œÕD¥Rsssœœ¦¶yøðᨨ(˜¨155uvv†QA§ÓÃÃç?þ£HII‰ŠŠ&$$Àðc_ŽŽŽ¹¹¹åååFFF™™™ýýý8ŽÉdÔÔÔž>}ÚÛÛ (++ÓÑÑÿ"¡©©ùäÉxÞŸ>}úÑcG Ä·Éì³¹¹¹ùùù·oßæååõöö¶µµÍÎÎÖÐÐ077WQQXYYWl³ÀÇLJH$º¹¹%%%ùúú9rdddDJJ*..îúõë \\\°Ó>Sãââ6mÚdnnîêêZSS£«« ——?tèÐËêêêGµ²²f±X;wî„Ã'ÌZ‰ˆˆ˜››„åË—C­¬®®îææfll X°`AZZš˜˜ØÚµkÕÔÔ$$$.^¼íèè844´téR8•g<»víúïÿË<7š¨¨¨,]ºT@@@RRž?ÞËË 0]´hÑÙ³gGïbkkkgg÷Ë/¿`±Øõë×ÃB ‹œœ <¿fÍšñšÝbrrrÞÞÞp°ÝîÝ»W­Zõ/ wßCV¬X““kooß²e \ËÅÅE¥R½½½¥¤¤âââW¯^e4˜ aaa33³¨¨(øóôéÓÇ×××g0¼¼¼¦¦¦ã6LÈ„½Þ>|ðõõe2™...x<ÞÅÅÅÅÅ¥½½=00pÿþýÎÎÎX,†F ¼zõê‡üýýaž{ëÖ­¶¶¶ðzŒŽŽvppjooŽŽf±Xaaa]]]ÞÞÞÞÞÞ«W¯^±bÅÅ‹ÄÄÄ:;;Oœ8¾F‰@ ˆñ`¸RB#"ûé}€”Ô4SSÓÉ6­¨¨xýúõÌ<;–ç?T*5!!ÑDÌϸškSeee3¥úÅÉËËSUUE1†@ 󜚚555ØÓCì˜ € %%%ìÙÏ>¼ V|ÙÚù'ú×™/‰……ÅÓ§Oa_$@ ÄW’_’ÔÔTÔ@ |D 3ƒ@ |]£ á42@ ùˆ@ ¾ |||uuup‚Ô˜ï=Í+ Æ­­­æ| @ ùˆ@ æaaáÖÖÖtvvÎsW ???œºŽ@ $?Ξ={æÈ¹³Œø–ùŒq5צðx<:_øÊÇØØØ9zÆÏ‘eÄ7®?W\ÍOS@LÍ?þøåå#`î¾Îøm~÷1×|ƸšSS---t:ý«è¼æããF¡…@ óŸšššy!Äg§¥¥…ƒƒcŠïµÎ+?~ÜÚÚŠ$@|³p &@ ¾8t:}ݺu_‹·ÒÒÒ}}}è¬!’â‹1ÿû¬¿v‡ä#@ âË€Æ>"ó‚¯ë_gñ-óù³¡¡¡²²²²²²ÁÁÁ°ÄÇÇGDDDJJJJJjïÞ½Ó1"...---//¿qãÆ}夼¼¼  às •JUUUÕÑÑùðáÃt¶õêU\\ÜçªÝÔÔtêcyôè‘¶¶öMA"‘æÔÃ1ttthii}Š…O?}¡¡¡ÃÃî Þ·o\ÎÏÏ'?†?­­­cbb`ûØÚÚJHHHHH˜˜˜TUUM¢D"‘­ù¤¤¤êêêÃÃÃÁÁÁ6l••UPP8zôèÐÐЬçýû÷666œœœ eïÞ½†††žžžÓßF£ ¢Û@ æµ|,--MII¹{÷nEEEfffaa!,?xð`mmmmmmttô4M%%%=|øðâÅ‹/_¾œ¾þ`W:5###Ý&&&&,,ìöíÛ‹-š¦|ŒŸ¦«Óq` †‡‡ÅÅÅ###g´×Œ<œ)ÙÙÙãëLåã„§o2E8#ùH$KKKárII‰‚‚BII €Åb•••ihh ›™™‰‰‰ÕÔÔÔÕÕíÞ½ÛØØøÅ‹“ÕÕÓÓ“žž>¦ÐÕÕõþýû7oÞ¬ªª*..Æãñ4mÖ ²xñâ   Ž3gÎDGGgeeÅÄÄ¡;@ ¾JùØØØ¸nݺ¦¦&øÌÞ½{7 ##ÃÒÒ’ŸŸŸ——wÇŽŸèŸœœ@xõêàþýûFFFZZZ:::0GÕÔÔ´yófmmm"‘xüøñçÏŸÇÆÆ¦¥¥;w¡ªªª¦¦F¡PàS<44ÔÎÎÎÎÎî§Ÿ~LLLÔÕÕÕÒÒ"“ÉÍÍÍ£«>räÈßÿíééù믿( ¬ÈÊÊŠŒŒ‹‹SWW'‰ºººïÞ½óõõ­¯¯722ruuäççkjjª««766By¤©©éîî¾sçΤ¤$%%%vuZZZwïÞsø7nÜ066VRR €%¦¦¦ÞÞÞ666hhhpvv†åŠŠŠ!!!FFFlÕåâ⢢¢²iÓ¦'OžÆx¸dÉ’°°0k×®Á½>Ú΀¼¼¼M›6ikk«««ßºu îxýúõ­[·ÂÃ400€-åà„M±iÓ&OOÏÝ»wЉ‰ØÚÚúùù%''ß¾}ÐÒÒÂþvÝÊ•+Ù‘§OŸ>wˆˆ···ŠŠÊôk)**Âãñ222ÝÝÝûöí£R©ß}÷Ýëׯ *++ccc·lÙââ⟬‚‚‚{öìéîîöóóܺu+%%%//ÏÙÙ988øØ±c€ššš‚‚ž²²²ŒŒŒììlnnî7n¸¹¹Q©TvÕÇŽ«¨¨8~üø† àÏÅ‹Nž<áïï_\\ž››»lÙ2ÆÅÅàåå•••xûöíÞ½{³³³×®]{ùòe{{{Øõõõ111¢¢¢€Ë—/jjjÞ»wohhHMMmÌá777_¹r…Á`lݺ5''góæÍðHaô£Gàf¹¹¹………ÅÅÅ8ÎÖÖ–½{uuõüqêÔ©èèè'Nœ;wn´‡5kÖ¸¹¹½|ùR__Û¶mÓig@HHHDDĆ ˜L&NÐh´ææf™>ØØØ$$$(**ŽŒŒÐh´É𢱱1))IHH(%%º7úôAV¬XqðàA@wwwvv6''gWW—ŽŽŽžžÏ©S§êêêp8ÜÀÀÇ‘#GNŸ>M¥RyxxÆÇ77·¢¢bII ‰DêîîÖÓÓóôôd±X%%%00”””0 {eeå”””É‚SIIIBBâÒ¥Kööö°¤ªªjåʕ˖-›Å5ÙØG‹Åd2)ÊË—/ËÊÊôôô Y,–···´´´““‹Å’‘‘QVVnkk£ÑhçÏŸ±X,??¿³gÏžÌÌÌ ---³³³Ç±b?)Ê‘#Gp8ܵk×vîÜyÿþ}¨Ã¦fûöíL&óÝ»w—.]âáá)..îèè°³³ƒkyxxÚÚÚTTT¼¼¼ºººˆD¢¦¦æ d2™ŸŸ`kkëææËuuu¡¼ÈÍÍmjj233ƒÞBa4YYY©©©L&³¯¯ꃛ7oîØ±.ÃZFóàÁiiéµk׬­­<“FP;öîÝ{áÂMMÍsçÎ988Œ¯tÇŽX,‹Åš››@ù¸eË–1››ššÂšÎ‘° IDATƒ²²²‚r %%%++ eÐønVˆ¾¾>@HH¨··w`` ²²r:í¬¡¡qàÀSSSiii˜ÔÕÕÜ»wOBBBQQ€Åb.\˜››;aSHJJ Á6¢g<0 “mlnnÆáp>|xöìÙÆ׬Ycgg§««khh¸|ùò•††Fii)WVVæà௩©yM0«É+¾¾¾d2ÙÚÚšós1†ƒƒ#22’ÅbQ(KKK£·µµŽÎüᇞ={¦ªªzàÀ ‹íÛ·8p`Œ‘ÂÂB111€ššš ƒÁàââèééèt:!J§Óá‹@ ŸS>2Œºº:<;ÂÂÂ---p¹µµuÅŠðÙKŒƒ‚‚êëëÕÕÕ?j<--MFF†J¥R(EEE&“)**::møñÇåååïܹsöìÙ˜˜˜1“BX,ÖèL{™——.0™L__ß:S]]ç[äååEDDL'™4ºv¶ìÚÛ¶m;zôhUUÕ;w¦68Þÿ ë-_¸¹¹á‹lD P£ŒŒŒL³ýüüŠŠŠœœœlll¯_¿ncc3£¦]õdî±öСC›6m‚Úººº &''çÞ½{ÅÅÅzzzñññòòòS·!‘HÜ¿ÿÂ… aª©©—••¤¥¥ÃÃÃG{[QQ!''7…AIII---v·œœ\KKË›7of—€üh¸ººš˜˜ÔÕÕqrr²X,'''(|‡††0 WmmmnnnttôñãÇ+++' !$ìŸì8a±X+V¬`¨ý”Q›øóISgüýý%%%¯]»æááÑÖÖ “É©©©½½½t:=99™L&êëëÙéÀW¯^Íèß»Éd2‰D URRzñâE^^,¿wïàùóç‹/¶´´ôóó{øð!@PP°»»n£­­žžÞÛÛËb±.^¼8~R0‰DJLL„C »/x<Ë–-#ö€N‰”œœüæÍ@OOÏàààèÚ«««á±_¾|YRRráÂ…cÅ;'§ÍÎ;Éd2ßøz“““GFFúûûÓÓÓ§˜Ô¬¡¡qåÊ•&“™””4E{ŽöpB¦ÙÎOŸ>wppسgÏÇ Æýû÷aç»’’RCCÔ.ÃÃÃÓiŠº×ÙÙ)..«®®®†é±ŽŽEEÅÚÚZhaŠ,²‚‚B[[[ff&‘H„òñÂ… <<<0lbbÂ`0~ÿýw8«‰J¥æææ:99M¢‡ŽŠŠ‚‰:SSSgggt:=<<|šÓö§ƒ”””¨¨hBB ?öirttlllÌÍÍ-//722ÊÌÌlllìïïÇápL& ¦¦öôéÓÞÞ^@YY™ŽŽ'çØ·GMMÍ'Ož¼}û¶óG@ ß&³Ï>ææææççß¾}›——×ÛÛÛÖÖ6;;[CCÃÜÜŽn´²²‚Š'00ðþýûX,ö»ï¾‹‰‰™ibÆÇLJH$º¹¹%%%ùúú9rdddDJJ*..îúõë \\\ N ‘Hqqq›6m277wuu­©©=ªòòò‡cY]]ýèÑ£VVVÃÃÃ,kçÎp˜ã„Y+sss°|ùr¨•ÕÕÕÝÜÜŒ ,HKK[»v­ššš„„ÄÅ‹£££‡††–.] ÓfãÙµk×ÿû_öà¹ñÉ­mÛ¶utt˜˜˜L1©yóæÍ•••êêêßÿ½²²ò_Šãáø ÂtÚ988¸¦¦‡Ãñññ #..ßUœŒŒ¸¹¹srrðxüû8êc˜—““koogàââ¢R©ÞÞÞRRRqqñ«W¯²GL†°°°™™YTTüyúôéãÇëëë3 ^^^SSÓñ&dÂ^ï>øúú2™L—€€<ïâââââÒÞÞ¸ÿ~ggg, O(F ¼zõê‡üýýaâvëÖ­p8¬••Utt´ƒƒƒP{{{tt4‹Å ëêêòööööö^½zõŠ+.^¼èàà &&ÖÙÙyâÄ ô5J@ŒsÀ•ÙO襤¦™ššN¶iEEÅëׯ§Ø`ÖàñøØØØ¹°<ÿ¡R© Ÿ>EN§/X°€Åb8p`åÊ•û÷ïÿ'ÂÃÃCCC*éùÃgŒ«¹6UVV¡~-äå婪ª¢(@ÌsjjjÔÔÔ`Oœ‹É^€ ¸ÀÁÁ3AS<¼ V|ÙÚù'ú×™/‰……ÅÓ§Oa_ä'²gÏž·oß®_¿~šßfÿŒœ8qM@ ¾|ü’¤¦¦ÎCS@ H>"óðu2„ÓÈä#ø2ðññÕÕÕIJJ‚QßÓ™‡@[[[;Íù@@ò@Ì Â­­­<èììœç®~~~8u@ H>~œ={öÌ‘sgñ-óãj®MÿÌ@ ÿù;GÏø9²ŒøÆµã犫ùi @ ˆ©™ÑµÌ•|ÌÝ׿Íï>"æšÏWsjª¥¥…N§×|||ÂÂÂ(´bþSSS3/ä#øì´´´pppLñ½ÖyÅãÇ[[[‘‚D ˆoÔćN§¯[·îkñVZZº¯¯5@ò@|1æŸõ×î0@ |D @|ÐØGb^ðuýë @ ¾e>ö144TVVVVV688–466nݺUUUUAA!00p:Iqqqiiiyyù7Îè+'åååÿd >zôH[[û[ŒÝV㩯¯ß´i“ŽŽÎíÛ·§oSHHŽN FÞ·o\ÎÏÏ'?†?­­­cbb¯^½²µµ•011©ªªš"D‰D";˜¥¤¤êêêÃÃÃÁÁÁ6l••UPP8zôèÐÐЬ}~ÿþ½ '''…BÙ»w¯¡¡¡§§çôw§Ñh‚‚‚èÔ#b^ËÇÒÒÒ”””»wïVTTdffüüüôõõËÊÊîܹ“’’RVV6SIII>¼xñ¢‡‡ÇË—/§/a¥eddäŸlèYW÷×_ß¾}[GGgvÚÉG‘H,--…Ë%%% %%%‹UVV¦¡¡1<ÅCCCíììììì~úé§ÁÁÁÄÄD]]]---2™ÜÜÜ<^Œ¨««‰D¨Jóóó555ÕÕÕÇlÿÑêØ[Òh´_~ùE]]ÝÜÜœmghhÈÇÇGGGGCCÃÅÅe`` %%%>>>!!ÁÈȨ§§'**JWWwÓ¦Múúúÿûßÿ}}}"""l³K–,íϱcdž††Èd²‘‘Q___xx¸ššš–––¦¦fGGÇ·늊ŠmmmðÀKJJ<<< ||üø1‡»zõ*‹õòòÂb± †L&ž9sf2ƒ‡ b0ì’ææf*• ƒœ——wÿþý‹-ú\‡ÐÓÓ300ÐÕÕèííýõ×_½¼¼ììì “ýýývvvžžžŽŽŽ‡Àܧ‹‹KHHàúõëVVV‡²¶¶†¯dvvv , #‘HÜÜÜÙÙÙööö^^^ÖÖÖ­­­è‰@ ˆñÌ~죘˜X@@€­­­ŸŸ_rr2ìZmiia»nåÊ•Päýþûï–––qqq]]]GÑÐ‹ŠŠðx¼ŒŒLww÷¾}û¨Têwß}÷úõkƒÊÊÊØØØ-[¶¸¸¸À'«  àž={º»»ýüü·nÝJIIÉËËãããsvv>vì ¦¦¦  €‡‡§¬¬,###;;›››ûÆnnnT*•]õ‡lllGFFh4ÚÛ·o÷îÝ›½víÚË—/ÛÛÛî(ÿhu£ëøñã‚‚‚¥¥¥ššš«V­œ|èîŸ?uë9räôéÓT*•‡‡§¿¿ÿÔ©Suuu8n``€ƒã››5ÅÍÍ­¨¨XRRB"‘º»»õôô<==Y,VII‰††ÌÌÌ ---³³³Ç±b?ccc·mÛæååÕÑÑahh¸aÆé|yûöíL&óÝ»w—.]âáá)..îèè°³³ƒkyxxÚÚÚTTT¼¼¼ºººˆD¢¦¦æ d2™ŸŸ`kkëææËuuu¡˜ËÍÍmjj233ƒÞöôôŒÞýÞ½{ŠŠŠ,»páÂÜÜ\iiéµk׬­­<ó@Ó¬n4………üñ€@ lÛ¶ æää@5••³×“'Oœœœh4''çL¿#ÏÃófÍ;;;]]]CCÃåË—ƒá®¡¡QZZŠÇã•••988ÄÅÅkjjJJJ À¬&¯øúú’ÉdkkkvÌÏÅ ŽÈÈH‹E¡P,--q8ŒÞÖÖV8:ó‡~xö왪ªê,,,¶oß~àÀñ!'&&& PSS³±±a0\\\===€ƒƒCBBN‡#Dét:ì4@ âsÊGƒQWW‡ÇãÙ=¡ÂÂÂ---p¹µµuÅŠ€óçÏÃ<Ùwß}§®®~÷îÝéÈÇ´´4*•J¡P™L¦¨¨hVVÖèm~üñGyyù;wîœ={6&&&..nŒ~Ib/óòòÂ&“ibbâëë;ýüÐhƒ£mN§º1@€pè켞¬ö]»v]¹rEVV¶¿¿ÿ‡~€º–­W¦ž¢Á`rrrîÝ»W\\¬§§///ÿ­…;‘HÜ¿ÿÂ… ÕÕÕ¡Š*...++ HKK‡‡‡>rrrS”””ÔÒÒbwpËÉɵ´´¼yófv È©Á`0®®®&&&uuuœœœ,ËÉÉ ß¡¡! ÃÅÅU[[›››}üøñÊÊÊñF¿Ú±rss³ËW¬X ~ʨM@ü‹ù¤LIIÉk×®yxx´µµÈdrjjjoo/NONN&“É‘7n:;;ËÊÊ$%%§_™L&‘H¡¡¡JJJ/^¼ÈË˃å÷îÝ<þ|ñâÅ–––~~~> vwwÃm´µµÓÓÓ{{{Y,ÖÅ‹µ´´Æ'‘H‰‰‰pÈ#ƒÁxôèÑèµJJJ ð<<<ÜÙÙ©¨¨X]]]__¸|ù²¤¤äÂ… ÙÛ´ºÑhiieggÃzoݺÅöçäÉ“pÆtww÷Ó§OLjõ111T àáááçç‡ãØ`#APPfUétzGG‡ŠŠŠ‡‡‡¢¢bmmí7î mmm™™™D"ÊÇ .ðððˆŠŠLLL Æï¿ÿç9Q©ÔÜÜ\8Z` >u"""¦¦¦ÎÎÎoÞ¼mþáÇÏå¿”””¨¨hBBŒöåàèèØØØ˜››[^^ndd”™™ÙØØØßßÃá˜L& !!AMMíéÓ§½½½€²²2NαošššOžû˜›››ŸŸûöm^^^ooo[[Ûììl sss€••”P§OŸ>xð`LL “É477'‘H3ªÈÇLJH$º¹¹%%%ùúú9rdddDJJ*..îúõë \\\ N ‘Hqqq›6m277wuu­©©ÑÕÕÈËË:thŒeuuõ£GZYY ³X¬;wnذ½–@ ÄÇÇ{{{÷ôô`±ØàààM›6EGG;:: -]ºÎÎa£§§7uu£ñððpqqùùçŸ,X .. ÝÜÜ´µµa&ÉÏÏoô8Qçããcjj*&&¶zõj, ËCBBvíÚµzõjiiéñ9;;qssÇÇÇ;88ôõõa0qqq¨ì¿5p8|yq99¹ööö-[¶Àµ\\\T*ÕÛÛ[JJ ..~õêU¨,§@XXØÌÌ,** þ<}úôñãÇõõõ //¯©©)ÏðQ&ìõþðჯ¯/“Étqq Àãñ......íííû÷ïwvvÆb±jjj4-00ðêÕ«>|ð÷÷‡iï­[·ÚÚÚÂë1::ÚÁÁAHH¨½½=::šÅb………uuuy{{{{{¯^½zÅŠ/^tppëìì"ˆ9AXX¸µµõÁƒóÜUÀÏϧ®#ÉdzgÏž9òcî,#¾e>c\͵)<Î@ þ…ò166vŽžñsdñkÇÏWóÓ@ S3úÒ_L>æîëŒè»ˆyWóÓ@ “QSS3fч{@ H>"@ |D @ ùˆ@ @ò@ äã4 •••••• †%¦¦¦322<<¼aÃYYY…£G M¸¥¥¥å7fáäððð|8¯^½Š‹‹û\ÖN:åãã3?C-55õùóç_Öqqqiiiyyù7ŽþzNeeåæÍ›%%%%$$œœœÞ½{7SD"‘ýOƒRRRuuu3 Ý©ÑÖÖ^»v­”””””Ô… `á7dee÷ìÙC§Ó§ØÝÔÔ´¤¤ähÒžžmmíÁÁÁñ«Z[[·nÝ:þÏcbb¬­­áò­[·¤¤¤ŽŒŒL&ãããgwã±°°Ø»wïçõð3ÊÇ/^|ñˆOJJzøðáÅ‹=<<^¾| hjj²´´tuu­«««®®&?ýôƒÁ˜ŽrJOOŸ»ÐMII©­­­­­µ³³Ðh4ggçøøøªª*~~þ°°°9j¢]þù§¥¥%77÷øUÂÂÂ"""ׯ_Ÿlß+W®¸¹¹eddlܸq¦N~J¨#â‹ÉÇÆÆÆuëÖ555A5¶{÷n@FF†¥¥%???//ïŽ;222ØYccc%%¥€€€Znnn¦R©‘‘‘K—.ðòòî߿ѢE}}}¿þú«šššªªêü1f¯çÏŸ›ššª««oÚ´)//.Y²$44tÏž=ìü àØ±cCCCd2ÙÈȨ¯¯¯££ÃÆÆFGG‡H$FFF²w ÓÐÐØ°aCii©¯¯/¬÷É“'€òòr"‘èææfgg·mÛ¶††¸Wbb¢®®®––™Lnnn†-cggggg÷ÓO? R(mmm"‘heeõáÀ¯¯o}}½‘‘‘««k__ŸˆˆÛÏ%K–Œ?Š ½-Ñ¢££¡‡›6mòôôܽ{·t{ppÐÛÛ[UU•H$Â?>)//×ÔÔtwwß¹sgeeåýû÷ŒŒ´´´ttt`¸¼¼\WW×ÙÙYIIIWW·¡¡ÁÆÆFQQÑÌÌ f¿†††|||ttt444\\\¦¦¦GŽqttܼy³¿¿?௿þzð௯¯‘‘Qyyù{999ðêÕ+@xx¸……ÅæÍ›\\\½½½9995røðá   ÑBs²Ðý,>ß¼ySFFþ/¶­­-ûâbóôéS}}}]]]vnr€ÉÌÌTVVÖÑÑ9}úôôÃl|xâããÉd2Œ.{{{"‘¨¥¥µcǸÖÌÌl²äz\\\@@@ff&<¢);,,ì·ß~ƒËÝÝÝ¢¢¢4êð£P(––––––ýýýè¶Ž@ sÍìÿóZLL, ÀÖÖÖÏÏ/99ùöíÛ€––eee¸ÁÊ•+ÙÏ˜æææ+W®0Œ­[·æääÀGõdTUU­\¹rÙ²ecÊOœ8(--¥ÑhRRR$‰½ÖÑÑñ—_~±¶¶nhhزeKYY´°bÅŠƒ޶säȑӧOS©T€µµõ444MLL”””x<¾¸¸8++ËÂÂ"&&& ***44ôìÙ³€†††øøøÕ«Wß½{×Ñѱ°°°¬¬,###;;›››ûÆnnnT*PSSSPPë:vìØâÅ‹'OžŒˆˆð÷÷ðòòÊÊÊLÖO7ú(LMM'ôvB}Ÿ””$$$”’’râĉsçÎýñÇ---………8îýû÷p³úúú˜˜QQÑîîî-[¶P©Ôï¾ûîõëו••€ÇŸ:uJJJÊÓÓ“L&ß¼ySHHh×®]ééé666'OžäããƒgßÇÇ'22ÒÝÝÊʳgÏ2™L%%¥ŸþÙÄÄ$>>žB¡èêê·¸/**Âãñ222ðQ(”ÿï’àä”——ÿßÿþgll<µ%%% ‰K—.ÙÛÛOº³J|…€€!!¡––aaaöÅõòåK‹…Á`ØÛïÝ»—B¡lß¾ýáÇúúúìÂ1³zõêƒæçç Ÿ={vtÖyŠ0ß·oߘðxõê'''<ÞâââÞÞ^ØcÞÓÓÃn¢]»v1™LŽÿß›jYYÙ½{÷ ~øá‡ÉüdöŽ;455;†Ãá222 øùùG[{öìÙÍ›7q8œ‹‹Kjj*|•E Ä|”0µPXXhii™-((8fíè1O;vìÀb±X,ÖÜܼ  `jùÈb±Æ—c0 ‹‚‚¶|¤ÑhÕÕÕ;w‹¯_¿¾²²ÒÈȰuëÖ)ê¢ÓéwïÞ vás˰qãFNNNø g§|$$$V¯^ PSSkmmíììÌÍÍmjj233ƒ‡À~‚êêêBíÈÊÊJMMe2™}}}3ð(¦ðv<’’’BBBÐÕóçÏÃôÕÿû_€*®TVVvttÀ~RO[[¿ƒMÑÚÚ mnܸöDçää°X,(deeáîP¾pppüøãMMMkÖ¬™'¿}ûv&“ùîÝ»K—.Áó2a°M___2™ÌÉ7Yè΂˜˜˜•+W2Œßÿý—_~¹yóæd¤···¡¡ÁÜÜ ///--=YÀ¼ÿ^^^*QkkëC‡M'̺»»Ç‡G{{;;Œ%%%ëêêÜÝÝ544àõ`±Xìxƒ¬Y³¦³³3--mß¾} ìåË—ËÈÈܸqcÛ¶m‰‰‰~~~cŽ]SSFµ„„ìA Äü• £®®ÇwttÀaaá––¸ÜÚÚºbÅŠñ{ΗLˆœœ\KKË›7oƬ1¹–ÑË㟦쵼¼¼SÔÅd2Y,Vzz:[á±Ã¹°X,{‹e ÝeÉ`00 “É411ñõõc‡í@uuuDDD~~>@ÈËË‹ˆˆ³%‹eȘùÐÈÞŽ‡‹‹ .pppL1ší“É…yP6ïß¿gk›°)˜L&켞]íÿÍd2………ïܹþ¸„„„Æ\JœœœìØþLvvöd×àavãÆñáÑÝÝ ‡+„„„ÊËË‹ŠŠîܹãïï_ZZÊÇÇÇb± ÆøkpÙ²eñññFFF ÆÕÕõ£mee•””$..þöí["‘øµ@ü[ù¤©3þþþ’’’×®]óðð€™*2™œššÚÛÛK§Ó“““Ùääää‘‘‘þþþôôt--­©ÍŠˆˆ˜šš:;;¿yóf&ÂÃÃ?|ø ­­Ãb±z{{SSSGÛ‘‘IHHÔ××ÿý÷ßŠŠŠST!((³ƒüüü***!!!P·½xñb:³nOž<¹wï€J¥®Y³Ç“H¤ÄÄD8ä‘Á`ko!$éÌ™3p’ìÛ·oǬURRzñâ{Ø(<ºéØÒ/™L&‘H¡¡¡€}ûö¥¤¤äææÂçëëËÇÇ7u‚|4‡ŽŠŠ‚c ' Ý™ºG§Óák“ɼté’´´4‡Auuumm-àÂ… ì‹‹} ˆ‰‰•––BqùøñãÉFAAáÁƒÐþåË—§f†‡¸¸xKK ìþnoog±X$)00phhXccãÊ•+,X0¾–ï¿ÿþÚµk—.]:uêÔG{ëÖ­•••;wîüèû'@ æ¯|ÌÍÍÍÏÏ ùñǽ½½mmm‡‡‡544ÌÍÍUTT·nÝÊVx’’’Û¶m#‰ššš£,NÆéÓ§7lØ ¯¯/%%¥¡¡ÑÛÛËÏÏïááÅb•••uuu·oßnhh8z—³gϦ§§«¨¨ØÛÛŸ9sfêô³³³‘‘‘††F;þ|ss³²²²’’…B™ú{(läååãããµ´´þüóO8„_]]ýèÑ£VVVÊÊÊêêêã¿UD$EDDÌÍÍØî‰‰‰­]»VMMÍÖÖ²k×.;;»ÆÆÆ ë·ýû÷ khh¨ªª²ç"°!IIIaaaÊÊÊ §NšŽM77· 6hkk+++oݺuŠ®ÃŸþ988xÓ¦MÅÅÅó!ô}||RRR^¾|¹zõꤤ¤ððp iiéwïÞ]½z•Ðú(ÂÂÂfffle»ŠŠŠ×¯_O³SoFàñøØØØ¹°ñû‘›6mzöìÙàààøO?¾~ýÚÍÍ iGø÷äãlPQQA©GÄ׋—————×ç²öË/¿LX.$$„´#@ü+Aÿy@ @ò@ ä#@ â‹3³±ð_Ôæ‚¹³Œø–ùŒq5?M!1ßåcllì=ãçÈ2â׎Ÿ+®æ§)@ ¦æÇüòò0wß«ûоûˆøŠøŒq5?M!1555óB>"⫦±±±··÷ýû÷¨)&dñâÅ .EM@ ùˆ@ ¾>5ƒäsÑÚrrrßæáß¾}ÛÌÌ죛=xðàùóç(ð$ÄüU3ÚÚÚS<ÈŸ={¶fÍÔVŸ…ÞÞÞ)Zû[þQÛÔÈËË¡hA &}¸@|1úûû»ºº6lØÀšyyùÎÎÎþþ~Ô\ŸÔgÍšïÞ½CÑ‚@LÊ>"ˆ/Nïêêúh6¨««‹N§óòò¢C|ù8úç_ý011A-ƒ@|Iù°²²òôôœ‘áááÐÐД””‘‘gddtøða7~KKKK[[[CCÙ:¹ÿ~NÎ/¯ž_½zuëÖ-›¯4€æOKNqqq...‡Á`\\\öìÙüúõ눈@~~¾¹¹yqq±´´4ÀÚÚZOOo²?tž~ˆÎˆë÷NÝøßÛ.Ú7rè 5‘üèfƒƒƒEEEè–=}øùù×®]»hÑ¢ë®Zµjpp‹ÅnÞ¼)%%û믿‰D:þüGåcff&”cccv9ƒ™Ñ‹ÅVWWCgþóŸÿQ(”ùÓ\G½zõjsssNNŽŠŠ  »»ÛÕÕõÞ½{™°°°~øÀ`0|}}©T*ƒÑÖÖ>sæ ºšs.KKKSRRîÞ½‹ÅbuuuUUU555gaÇÕÕõÍ›77oÞ\ºtitt4Fû”ûàðððh‰úŸÿüçŸ=###ðÎ2^>ÆÇÇOS>Ž9ŠYT7òñnÉO$))IFFæÿûŸžžž¾¾>‘HÜ¿?\URR¢  PRR"--Íb±ÊÊÊüýýÿ±…DäVáÖé¬ãå¬oâ4ÔÛ À‹éŒEƒ²1}ž>}ª¬¬ü/>À{÷î­X±btÉÎ;'Sãåcfffff&\þ믿X,Öh9#–-[VPP «« o2ëׯŸomµyóf{{{2™Ì.a2™d2ùܹs\\\ÞÞÞLLL={öìÁƒüüüÏŸ?G×â3ËÇÆÆF“ëׯ¯Zµ*44´ººúÒ¥K–––üüü€;vdddhjj¾zõê·ß~{þü9ƒ±°°Ø·oßÔ–›››©TjUUÕÒ¥K¼¼¼ðß××÷Ûo¿=zôˆÅbmß¾ÝÝÝ}ô^ÏŸ?wwwûö-‹õññÑ××,Y²ÄÓÓóñãǪªª{÷î…[;vlhhˆL&spp¤¤¤Ðh4¶¶¶¡¡!+++ggg¸£··7•J¥Ñh§OŸ¾qãÆ­[·X,Ö¥K—Ö®][^^~ðàAEEÅžžž7oÞ„††Š‹‹/\¸022²hÑ¢°°0‘ÐÐкº:ÀÛ·oÓÒÒöïß___Ï`0V®\yúôéE‹ùúúÖ××‰ŠŠþþûïRRRÍÍÍÐÏ%K–ÀÁ7£ÂÔÔt¼·£ÅÜèê222Æøo W®\Y¾|ùúõë>|˜••åããóÃ?Àåàà`NN΃ –––2Œõëן8q‚‡‡'<<<55‡Ã±X¬ÔÔÔsçÎnI>>¾¯%îåää«W¯ÛÚÚ:::¾ûî»’’¸¸8''§Çãp811±…è§ó¾»wýBþW´áoä4ÌàÓ›ÊÀÍÍÍÍÍnÙ3¢··5Âdòq´vütimm˜˜¨««ÛÜÜÜßß/)ùÿæÔ£¢¢ÒÒÒ 77whh¨œœÜ„Α‘‘¾¾>AAÁ¹;êñ/Ýe¯¥¥uìØ1ÀÐÐPTTTii)|Ž£¹çˆÏ/ÅÄÄlmmýüü’““oß¾ hiiaÇèÊ•+ $éòåË`z£¶«ªªV®\¹lÙ²1å'Nœ”––Òh4)))‰Ä^ëèèøË/¿X[[744lÙ²¥¬¬ ZX±bÅÁƒGÛ9räÈéÓ§©T*¼ì8 ¡¡188hbb¢   ¤¤ÀãñÅÅÅYYY111QQQ¡¡¡gÏž444ÄÇǯ^½úîÝ»ŽŽŽ………eeeÙÙÙÜÜÜ7nÜpss£R©€ššš‚‚X×±cÇ/^ 8yòdDD„¿¿@@€——WVVÔÇ“µ û(LMM'ô– »º ý¹yóæÍ›7‹ŠŠ¸¹¹§þ뼓'OòññÁÓêããI¡PN:UWW‡Ãá888Æ´äWDQQ—‘‘áææVTT,))!‘HÝÝÝzzzžžž,«¤¤DCCc¦!úé,[Œïæ"p³¾‘ì#ÇÀ˜„Ðx`7"‡Còq¦üë»ûµµµ™Læ¶mÛBBB`x\¹r%//OXXø÷ߟì†Á¶mÛ¶mÛ¶M‘›œ©'gΜéîîNLLܱcÇ£G`¹¹¹¹““àáÇîîîùùù>:kkkŒŒØ¹ƒ^OŸ;wêæ––—œœ|ýúu^^Þß~ûÍÀÀ]JˆÏ)fff………–––ÙÙÙã_›àEØ××wÿþ}öà(ž>Ê^ÀÁÁÁ F@@À¢  €-i4ZuuõÎ;âââëׯ¯¬¬422lݺuŠºètúÝ»w‡‡‡CBB ÆÆF(È,,,7näää„ׂ‚BFFÜQBBbõêÕ55µÖÖÖÎÎÎÜÜܦ¦&øE1‹ÕÓÓ·ÔÕÕe««¬¬¬ÔÔT&“Ù××7#ñb oÙ°«›ÐŸÂÂB3338ÁÚÚúÔ©S“Õ˜““U```@VV–‡‡gÍš5vvvººº†††Ë—/ÿ#~ûöíL&óÝ»w—.]‚ ¥¡¡QZZŠÇã•••988ÄÅÅkjjJJJ¦¸iN¢ŸŽi}Xî_Þw}#7 ‘>`"9ö|ôèû8#×®]û/>ÀÂÂB‘÷ïß[XX„„„øúúnݺuûöí ,¸r助©é‹/&ÌçÍÅÅËÁÁabb’‘‘qåÊ•ÜÜ\¶||ò䉓“FãäädÿùÇøG§¨¨hJJÊ—jI///NNNØ…2<<ÜÓÓÃÏÏ_ZZúèÑ#SSÓòòò¯ôn˜¿ò‘Á`ÔÕÕáñøŽŽX",,ÜÒÒ—[[[ÇŒJ™&rrr---oÞ¼#°X,ÖèáÌ£—Çߨk§ž­Éd2Y,Vzzúøü|—Åb±ìUX,vxx˜}ì£ÛƒÁ0™L__ß1vØTWWGDDäç焼¼<8]c4X,–} CCCãLáíøê&ógüpNNÎÑõÂŒL&ÓÇÇGGGgŒ¦¼wï^qq±žž^||¼¼¼üWñiii222T*•B¡(**~ÿý÷pøãÂ… ÕÕÕáû@qqqYYY``àLCôÓ1X/j°þê-zÿþý£G˜LæÔœœ***ÓyùD|;ÀÑ8‹/Þµk|±‡ƒId2ÙÝÝýéÓ§7nœL>¾y󦢢bÌ*eeåY_ÔÖÖÖ$I]]=šÅbíÚµëÊ•+²²²ýýýpbÊ„N>>>8åŸçðáÃÏŸ?‡w~!!!KKKÀ† V­ZU[[‹ä#b‚W¦OÙÙßß_RRòÚµkp4¼hSSS{{{étzrr2™LæããSRRŠŒŒ„»¼}ûv:7SSSggç7oÞÀ”[xxø‡´µµcbbX,Vooojjª––{™„„@}}ýßÿ­¨¨8õ{9ÌÆñó󫨨„„„ÀÊ‹/¦ù­¯'OžÀ kT*uÍš5x<žD"%&&ÂÞƒÁ~ûdÓÙÙ¹lÙ28üŸÅìîî†Ë<<<üüü/_¾ܸqc|¥3òvB´´´ÒÓÓûûûGFF`sV­ZU__7»sç{÷“'OÂþôîîî§OŸÒéôŽŽEEÅÚÚÚÑ-ùuA&“I$Rhh(@AA¡­­-33“H$Bùxáž)ýL¢è†2S,X°pᾦ .X°5bôíÞ*ét:•J…¢S[[;22¸sçNWW×dŸš‡Ùn8¸üÚ(Þ½{·dÉöwgê’˜˜˜···‡‡ÇèЀC¨Ù÷ü ===999ÿ|3zyy={ö,>>ž=2D@@ÀÀÀ 77ÐØØØÜÜ Gö#ÿ{çuöÿÿc0CY†q©„‰ÜsË¥ÓN-¯H%«Û¶è²ˆÝJV]ô±•®ªmÓ…Ü• Ë*2¥VòÉ]Q¹%·"Ì`Ƽœïo~ócf(”8¿ÞózŸ÷kÞïó>ïsžçÞ¿á鳯LKKËÌ̼w¸x@@À† RRR¬¬¬œœœ`-jÍš5Pá]¸pÁÏÏÏÄćùººnÛ¶mPç§OŸ>zô(™Lf2™âââþþþ¿þú+[¹jÕª~‹õ\¸pÁÇÇçÌ™3"""çÎ\ƒôòò²³³#©©©þùç®]» [8´qP ¯]»æïï/,,|þüy€……ÅÞ½{׬YÃb±0 [½zµ÷%–––***NNNÒÒÒS§N…¹†ššÚìÙ³ÍÍÍçÌ™ó×_…„„¸¹¹Íœ9®3¡ß-Ïû!“Éyyy––– .ÌÉɬ\¹255uåÊ•D"‘“áúøøtww[[[ ‰ŠŠIII¹»»wuu ihhÀ|Ü1 ‡Z+ZZZúøø(**š˜˜¼~ý6–ëéé½{÷nÙ²eŸ‘DQ†ò©ˆ‹‹ËÈÈ<þ\WW hÇ0ŒÉdÊËË£EÜ455-_¾¼££‡Ã-]º4 péÒ¥ÈÈHaaa99¹ØØX"‘ÈO>rÚ ÛÚÚàtCMMMWWW0¼®í~ë|áñøÀÀ@55µ™3gÂÕ0xÕÕÕ£:ö1 ))©¹¹ÙÍÍMTT´´´´¢¢"<<\^^UrrrÙÙÙ€ÿüç?žžžaaaáøñãŸ×‹ˆ÷íØîv–AïÄÄÆ988ð úäÉ“††>"‘1žG‰ÇïÝ»ÖϾ]?~ gíŒKF0]MWã†ÊÊÊææfžÍ·rrr$ íX8‚üóÏ?NNNöñããã¹› ì…ðóó㮢àp¸ÔÔT[[[”`ß:%%%æææpŒ†aܰ²p8F°Ô‘H„Z±¾öMøÙ3h×ñ•QSSã·F1âpµ%pù3 x .àÉÇÏÁÌÌì[oz„O1Ž›OÐ ¤~ÝÓ°›ÛˆÃáØlö8Þ°>81q’’ÊÏÏŸÈ1 4l6»¸¸˜ßÐIPë#@L(TUU«ªªîß¿?”MÆ%‚ÈÈÈHII¡ W$ñ¿ ©Hâ‹ÊGÁÛÜ ‡ÑóŒ˜ÈŒ`º›®ëò1""b”ÊøQòŒ˜àÚq¤ÒÕØt…@ „`ÔÕÕ¿¾|ŒÞzuh%<ÄOWcÓ@ üàl¶þ•å#@ ¾i*++;::&ìÔ™A!‘Hhê ä#@ŒuÝöÅ$Kee%‡ƒ›DO@îÝ»·bÅŠAƒåçç¿zõ )HÉGøÊÚ‡ÃY[[ ,UUU£=-º££CÀ=L†²«µ¡¡áƒP¢E ø– G ˆQ‡Á`´µµ`ü144üðáƒÁÕ;A}ÖØÐhiiAéàj}D ˆQ‡N§·µµ ÚîÕÖÖF§ÓÅÅÅQŒª|äþyëÖ-•JE1ƒ@|5ùXZZêëë[XXhbbróæMNµ{ëÖ­yyy¢¢¢X¶lÙ ~444DEEñx<“É\°`Á±cÇB¿0ŠŠŠ/^¼˜’H¤ààà/^ÄÆÆrŒ'OžÄáp………/_¾\ºt©¥¥¥¤¤ä ®nܸ¡££ÓÓÓC¡PW¯^ýÿ2â¾>aaáÛ·oj=44tëÖ­H>Nd`ºzþü¹­­-™L¶´´ôöö†§h4š‘‘FÓÖÖÆ0,77wß¾}üülß¾½©©)==]NNŽÁ`œ?¾³³søEuXZ!~îâ¹â8€¡w5®èíøÀ롌ºSSS“––‘?}ùò¥©©éøŒÏÞ^ww÷’’UUÕC‡íÙ³'..îéÓ§ÁÁÁ÷ïßWWW¯ªªâw-ç-$'''''Ãã[·naÆ­ ? yyù¬¬,˜Éèëëµ[ºté¦M›¹ÞÞÞ®®®ëÖ­‹ŽŽÞ¾}{jj*?#1bò±²²’J¥Þ½{wÆŒ¡¡¡EEEW®\QPPPPP¨©©á™pòäI€ººº¡¡aZZÚÊ•+‡ø/,‹Éd­ëCCCËÊÊÍÍÍqqqööö°õ199ùàÁƒ“'OvttÜ»w/gÀÊ™3gâãã;;;÷ïßoooÜÛÛëèèˆÃábbb\]]µµµ›ššjkkÍÌÌ‚‚‚þþþuuu½½½kÖ¬ñòòêééÙ²eKyy¹ˆˆÈ”)S¢££ß¼yãééÙÝÝÍd2—/_þ믿¢dôÍ¡§§'--ýöí[cc㺺ºÆÆFæïïõêUââb<¯¦¦ÆóòêêêÄÄÄÂÂB999€¸¸8Gƒ“Öö})‰·,ôŽÆ,¦(Ú¤ 0°³åóèèèÇQ*,,ÜÙÙ èììTTTDDDlݺ¶– ˜ß·v¾‚tuuŠŠ²±±©®®f0ššÿÛÒÇd2 Bhh¨žžÏ¢³¯¯¯««k( +ŸÍÀŠDccc~~~BBÀÙÙù·ß~{ûö­°°ð@ã´iÓÐ'Œ1ù¨¦¦¶ÿþ 6EGGß»w_ÈÚÚZ%%%x¬¬¬\WW7ÿk×®%555d2™B¡@cIIIVV–˜˜'Xss³ŸŸ_ff¦’’Ò… úúú8§&Ožœ““SRRâäädoo¿gÏžÓ§O'&&r.ïíí½pá›Í611Y»ví¬Y³~þùç;vXYYõôôP©T##£?vttÐh4ÀÇaµlÙ²mÛ¶q,ˆoމD`llL£Ñ(J{{»­­íÎ;1 £ÑhVVVü./,,TVV–——ñ“'?°D¥ j}g­e¸î~M_¦x<~¤äãˆt‚Mðxü7-Z$..>eÊ”ììlÀëׯ‰D¢©©)“Éܸqã–-[ÈG{{{{{{~g?kkësçε··GEE­Zµª  Úœœ<<<Ïž=óõõÍÌÌäYt–––ÚÙÙUWWÉ8¬­­UPP€Cn„……§NZWW‡Ãá‘|DŒ¤|¬X±";;ÛÅÅ%%%eˆÕ¦¡™×¯_×ÑÑéîî^¿~ý©S§¶oß°±±áÖŽ€§OŸByêêêúÛo¿qNÁþî¹sçvtttww÷»@&“8N]]ýÍ›7S§N}ôè‹Å 5ÚÊÊÊ… –••ùúúZYY-Y²`ff¶k×®¶¶6KKË… ¢4ômáììÌf³[ZZ®\¹“„••ÕÇa©ƒÃá444JJJh4|Ýü’16:ú·¢<íVAkzS㌾î.@ÕJÊ)((Ù'))9{öìñŸL&óÈ‘#™™™[·nˆˆ Óé¹¹¹ÙÙÙ]]]fffóæÍ)(G¥R’’’ÒÒÒ8òñÅ‹"""œÍ?ªªª111_7JyF †*²ˆÑL&³¬¬ŒH$666 6}úôššعP[[ûIcqÄÄÄàØG(vÄ0ŒßgN ^XX˜»U’ƒ¨¨(çËg±Xl6ðøøø~BóñãÇ<¸ÿþ¾}û>|H¡P ïß¿áÂ…Ë—/_½z%£oˆ¸¸8ÄÄDOOOccã)S¦ÀáRRRss󜜜ÜÜÜðs¢§§WSSÓÔÔ4â KôU—裕ŠÇ!­­­l6[pù-""bffF"‘PŒ æßÿmmm500899ÙÙÙ¦M›f`` &&&&&fbbRXX(@>655=yò¤ß)SSÓÏþ¨]]])Š……g 4†annnIIIººº ƒÓ†7°èœ¿T‘z IDAT!h##£üü|8ÚòúõëƒVÇt7KHH˜™™…„„ÀÌåõë×---ïÞ½Ã0ŒB¡8p ···¹¹ùÕ«W$ÉÅÅ%((èÙ³g( }‹8::R(”ÐÐP˜„êêê’““---¡|¼té’˜˜˜€ 'TTT¼¼¼šššt:ýĉïß¿G‹àǤI“¤¤¤­KJJNš4 E× L:µ¦¦æÕ«W€û÷ïÃi×d29++ Ž#,((€FžòÃ0YYÙ–––Û\´´´ÈÊÊrÖ}üÔ[RSS ð÷÷ç~¡ÝÝݰü‚£ ù?~üò3T "##a½ZKKkÚ´i<(½!òù­iii™™™÷îÝذaCJJJSS“­­mww7N×ÒÒÚ²eË–-[~ùå—-[¶Ì;—@ ?~|Ð<âììŒÇãÙl¶‘‘Q@@¿`òòòGurr"‰Ë–-ìÜËËËÎÎŽ@ ðûPÿüóÏ]»vÁöQ™ .¼~ý: Ã06›íîî>cÆŒS§NEFFŠŠŠ ÁnnÄ·H`` ¥¥¥¢¢¢‰‰Éëׯa%[OOïÝ»wƒ./uúôé£G’Éd&“)..îàà !!bÁqqq™çÏŸëêê‚ëÂ`Æd2 åååÑ¢CAUUõرcK—.‘••½páÀÍÍ­¨¨H__ŸÉdº»»›››ó“ðÀÕÕµ­­ ÎÈÔÔÔtuuÃë®í·Î tppPSS›9s&\Ö‡gÑY]]íáá1ªc’’’š››ÝÜÜDEEKKK'Nœðôôüã?äååÃÃÃaHžF¢B;¶{††eл1±qü‚>yò¤¡¡A@€Ï†H$FDD|¶g:ëëñññÑÑÑñññè½"†Ÿ®Æ¾+Ä7Geeess3φj999‰4Ú;þùç''§ û âãã¹{À ì…ðóóãî8.55ÕÖÖ%ZÄ·NII‰¹¹99ÛÂ8°²p8F0¼H$B­X_û&üì™ñ°bXXØßÿÍf³¥¥¥?ŽÒ ›¨©© Šƒø2p@%^^^ð@ðÈTÁÍx»víÚµkz—1(h^N¿îi¸®0·‡Ã±Ùìq¼a1|p( bâ %%•ŸŸ?‘c@h0Ølvqq1”•‚'hû>˜@¨ªªVUUÝ¿¿µµubÆ@FF†à222RRRÖ^@ H>"ÄÄâ LÐA H>þ?Ö­[7J÷1zž™LWcÓ@ c]>FDDŒR?Jž\;ŽTº›®Œººú×—€Ñ[¯­„‡ãéjlºB ‚œÍÖ¿²|D Ä7MeeeGGÇ„:3($ MA |D ˆÑÒ[ߜԨ¬¬ÄápzzzóUÞ»woÅŠƒËÏÏõêR’ñùzËÚÚZ€Ô¨ªªúV¦3wttx–‰ÀPvµ644|ðàJü?вáÁƒÑÖÖf``€ñÇÐÐðÇ ã›x"Ôg ––”þ~ ÖGà Nokk´½ª­­N§‹‹‹£û&ä#÷Ï[·n¨T*Šâ«ÉÇÒÒR__ßÂÂB“›7oBcPPPrrrww÷”)S¨‹Ó×ׇÇãíììvïÞÇã‡x±±±FFFŸ=låñãÇÝÝÝ‹-Bécœ¡¡¡!**ŠÇã…„„¶mÛ¶nݺ#GŽ444„……233œœrrr´µµ®®®¶¶¶ëׯ$Ê»O+Nýý¼¹­½¬1B_wW(UsÐ`===<øî»ïÆÎKHHÌž={¼nÜœ——÷?ÿó?𸫫KWW7;;ûÚµk{÷îííí•””<|øðòåË•ÉÉÉP>¸Ã }RÆ",,\TT$,, ˆŒŒÜºuë¡C‡<==ÇNŒíÝ»÷æÍ›ÕÕÕ©©©fffÐXUUåááÑÜÜL"‘ÂÃÃá /<ÄèÊG‰üâÅ‹ØØXŽQ[[ÛÇLJH$Þ¹sgíÚµ/_¾„ߘ¶oßÞÔÔ”žž.''Ç`0Ο?ßÙÙ9ô|066–D"õ“}}}ƒþ/G>¶··#ù8.¹qㆎŽÎóçÏmmmÉd²¥¥¥··7ª©©íᨒ AAAÑÑÑ÷îÝô’‹/.X°@°v*++ËËË÷³ÿç?ÿ<|ø°³³sÉ’%ZZZ ÐÛÛ{áÂ6›mbb²víZ*•zíÚ5OOOX¤Ñh%%%YYYbbb€àà`‰8yòdXXؾ}û"""–-[¶mÛ6ÀÇ%%%×­[×ÞÞ„ÒÇxåÁƒD"QGG‡@ Óh4 …ÒÞÞnkk»sçN Ãh4š••Õ§&Ñá#O"~`‰*J0Ôú86èÅu÷k²ìèÄãñcM>Ž©ÎôQâúõëßÿ=‘H„?oß¾½uëÖ–––k×®ñ{|ø*ííííííùýT¬­­Ï;×ÞÞµjÕª‚‚hwrròðð<{öÌ××733“gÑYZZjggW]]ý%£®¶¶VAA¹ž:uj]]‡hDò1’ò°bÅŠììl—”””A«M7oÞŒŒŒ¼sçΠnᬷö¬¬¬#GŽ }÷Ýw+W®ÌÊÊ‚ò‘L&p8œººú›7o.Ÿaccµ#àÎ;±±±l6»«« ÿfff»víjkk³´´\¸p!Jãggg6›ÝÒÒråʘ*¬¬¬>|H$MMMq8œ††FII F[²dɧ&ÑáãCÑ?žv« µ ½©1B_w jåŒ)¹&))9{öìqÿ‚þüóÏ£Gr~BQøàÁ___{{{NÎ?|(G¥R’’’ÒÒÒ8òñÅ‹"""œÍ?ªªª111_7&yF †*²ˆÑL&³¬¬ŒH$666 yëÖ­ƒ&%%)(( êVOO¯¦¦¦©©©_ë†aÜÙ9Ç¢¢¢œ˜ÅâÑëÇ™YTT–™™)--‘‘'LP(CCÃû÷ï_¸páòåËW¯^EÉb§££“˜˜èééill]XXx ¥4*Óp.Þ·oŸ¦¦æíÛ·ýýý9£˜róæÍààत¤!¦B//¯¦¦&N?qâÄû÷ï­­­/_¾ŒaXGGGll¬€©-’’’íííí>|——‡ÃÛáØÀ«W¯H$’‹‹KPPгgÏ\Ž78::R(”ÐÐP€‘‘Q]]]rr²¥¥%”—.]0sŸ_E;þ˜4iÒ ãm˜L¦¤¤ä¤I“Pt}a.^¼èîîŽÃýoAF£Ñàê›ùùù/_¾œ1c?¹a˜¬¬lKKËm.ZZZdee9ë>~êͨ©©øûûs'Œîîn8„šSâð,:?~üøåg¨(((DFFÂzµ––Ö´iÓxQJCŒ¤|LKKËÌÌ QWWذa‹Åzûö­–––ŸŸßãǵ´´Îœ9ð÷÷onn†£µ´´^¿~=¨óÓ§OÉd---++«ŽŽ aaaSSSggçï¿ÿžßåk×®=räÈ‚ rrr¸í–––***NNN?ýô§Šy÷î] ++«Í›7‡„„(ʳgÏ,X‡c#Æ%111õõõx<ÞÄÄ„ÅbÁêžžÞ»wï ”üÔ$Šbuü!...##óüùsž’ðÞÞÞçÏŸËËË£E¿0]]]ÑÑÑëÖ­ãXîܹ£®®>mÚ´5kÖ„‡‡óÛˆó*]]]9s\455]]]×¢âŸqKëׯ‡Ë~Aðx|`` ¬j644À¥?xÕÕÕpˆäèË_777---h ¨€HKKOž"@ |¥¥¥ eÚ´i'–æççËÉÉ9rd(~ÍÍÍ utt6nÜÈ/Ø©S§‡~{?ÎÊÊúì§STTS]i±±±¯^½B‰xèhhhhkkΛ7®žsäÈ‘_~ùžÍÌÌ”––...†?]]]/_¾,À•¥¥%gŸ\--­²²2‹Å:r䈮®®‘‘ÑÞ½{{{{‡ro˜@‚ƒƒgΜ9sæÌ½{÷rÛŸ’H¤àààÐÐÐ~öîîî;wR(”¡8©¯¯÷öö¾råʳgÏþûßÿþôÓO#u{?ÎÎÎí8íëë¥ÀåãëׯQ"þ$nܸñìÙ³¿þúËßß¿¾¾ÞÒÒòáÇðF322¢ÑhPÌåææZYY põñãÇøøø~ÆíÛ·?}ú4==½°°0''‡H$vvvóž³³³¯_¿þüùóâââÄÄÄ{÷îq>+;;»OòPSSSSSsõêUN!',,üêÕ«äääŸ~ú©½½ý“Œ)))±µµÝ¿ÿ~¼ü.-----½yó&‘H„Ç×®]û}:ü`ÌÌÌ =**ÊÆÆfÑ¢EŽŽŽÕÕÕý®x¶§§' `þüù–––ëÖ­{õêUDDD\\œÝÅ‹¹¯}ûöíÚµkÍÍÍ-,,¯^½rpp°°°X°`ÁÀ R333.\haa±|ùòÊÊJ(L.\èëë»zõêÿý—[°ZZZúøølܸÑÞÞ¾¢¢b`à§OŸÚÙÙ-Z´hñâŰqôÍ›7K—.µ¶¶¶´´¶dÉ KKK(ƒ:çæÄ‰æææ‹-Z¸p!ü¸dee<èááA¡P8m®<\½zþ‘MKKKEE…——|G===T*5<<œcä™ówvv®_¿ÞÂÂÂÉÉ æÏšýš››µµµá3ÚØØxyy™˜˜ØØØTTTüøãÆÆÆ+V¬à¼¾ºº:GGG###N@BB‚‹‹‹„„„¸¸øªU«>>>¿ýöü ôôôþûßÿ666æçç¯Y³àìì\ZZúöí[žF•JçÎsˆ¯Åç/Ü£¦¦¶ÿþ 6EGGsZDòèÑ£ÊÊÊC‡ ±h777×ÓÓ³²²233srr’––ÎÍÍMHHHII!ÿý·Obb"çžg;VSS“Çã[[[I$ÒºuëÚÛÛƒ‚‚úýãO?ýD¡P®_¿hmmlÞ¼yýúõ®®®Ë–-ËÍÍ•——‡›››þùç”””Ù³g_¿~}Ó¦M0ã+//¿|ù²ªªj?ç×®]›9sæ£G6oÞ 3_NàöööeË–%&&*((444,Y²äßÿˆˆX¶lÙ¶mÛ`àäÉ““'O†‘xöìY__ßk×®yzzÚØØ tü©}ʹ|(üñÇgΜ™1cÆþýû-,,555ÊÊÊÐÃŒ3ª««1 º‘ûèt:™Lމ‰!“Éün‰D"ýöÛo!!!ð[ãXH$ÒПBÿüóOLLLFFÆäÉ“½¼¼Ž9ÂÝçÈóS‚lŽíéé‰ŠŠ’èëë[»vmFF™L†R#==ÇoÛ¶-66ÖÝݽ_ÃÏù_ýE£Ñ"##Þêï¿ÿîææ+ C¹ù={öœ>}:11VÑdSííí¿üòK¿Œ¥_6¥®®+Ïž=óõõÍÌÌ„×Κ5ËÇǧ¾¾žL&ÛÛÛ¿ÿþÇŒŒŒ466îëëëììäé\\\^Î`0N:UVV†Çã»»»q8Çm@@@[[›¥¥¥™™@èäéÓ§'NœHKK“——ïììå<{\\ܬY³`…S”ðÌù=*))ùðáÃ>,\¸pÆŒü’ ìpàü,..>uê”––ÖÎ;ÓÓÓÝÜÜâããüñG@~~~FF‘HtssƒiàèÑ£°àè§ž/^\SSÃYŠKYY‡&“ÉÉÉÉW¯^õòòÒ××úô©‚‚‡Í%S§N­««ÃápÓ¦M›vìØÃ‡ÓÒÒÞ¼y³bÅ XJAQÅçÙôôôƒÂ/D"ñû»®®®§OŸÞºu‹S’uvv­^½¶²èëëÿûᅵ.Âüü|mmíÙ³g\]]ýüüÚÚÚsæÌ¨¡}æÌ™ssóÚÚZ8“”øßÿmllä ¾«««333ÛµkÌg.\HMM…šÐÝÝ­««‹ÒîçáììÌf³[ZZ®\¹Ë`++«‡‰DSSS§¡¡QRRB£Ñ–,Y2¨·ßÿÝÑÑÑÕÕ•£Ÿ†/€V­ZuïÞ½åË—geeIIIñT™]]]ÞÞÞ7oÞüTçÛ·o?pàOJJrpp(++“••èŸçŸÅ(&&fmm}öìÙE‹q—ýý••å(H¨ûÝÆpÈÊÊrtt”lذ¡_×$¿OiÙ²eð@HH($$äßÿ®¯¯/))òqáÂ…03™3gìu˜ÃðtN¥R-ZÄóVõõõŒŒ.]ºôÝwß åæ¹œMñÌXúeS/^¼ðððèììáÞ—>¯¢¢bGGGwww^^Þœ9sŒ¡”‘’’ÊÈÈ蜳1š˜˜Ø¬Y³6nÜhccóý÷ßO:Ú—.] ‰†††Ož<è$==}ÕªUPÃH Ïœ?;;öðJKKÛÛÛ ¸üíÛ·Ü•=8p0oÞ¼ÚÚZEEExÌ#D¡PˆD"l9†ià×_ýõ×_‡X9„yùòeØ.ûóÏ?Æ·&//___ä#âÛ–L&³¬¬ŒH$Âî ~½oß¾…LJp8ÜÇ:4¨óY³fÍš5ËÍÍmþüùÙÙÙl6›J¥þþûï< >ûyí@Ü qŸåþÉ9Ë©|Œ%îã~Ùl¶ªªj¿N@uuuCCÃû÷ï_¸páòåËW¯^e³Ù°S %Ùa§££“˜˜èééillÉK—.Õ××ß¾}ÇÁhçYp8¿Ñ‡|ìœN§766š™™ùûûs’ìä}ýúu^^ž‰‰ O' %::~>?~„q+ø Ìù-Z”’’-ÿüó ùîÝ;X¡âFKKKðàÈAÙ¹sgéà€"GGÇØØØŽŽ:íè訫«ûõ×_oß¾=gΜýû÷ à{Œ‹‹ÓÒÒš6mO#§@ƒ5ˆoU>¦¥¥eff†„„¨««lذÅb½}ûVKKËÏÏïñãÇZZZgΜù<çgÏžÕÕÕ7ož‹‹Ëž={ -,,öîÝ»fÍSSS ‹~ƒµyžõööVRR²²²š?>ì_ P(Ïž=[°`ÁÉ“'¹/¿pá“'OLLLÌÌÌ¢££¡%>>ÞÌÌlÓ¦MçÎãnL’••=þüæÍ›ÍÌÌbccû͈¡¡áµk×-ZtæÌ™óçÏ÷;+--}ãÆãÇ›šš:u p÷î] ++«Í›7‡„„||| ¬­­MMMøáصvíÚ#GŽ,X° ''%åO%000&&¦¾¾Ç›˜˜°X,X¿‡Ê JÉ¡ ¤¤´bÅ ŽŽ?}ú´™LÖÒÒ²²²êèèJø¿ß·oßþûï¿?®¡¡“4“É\¸páªU«tuuçÎK¥R/^üÙëàìÙ³gúôé***»víŠŠŠ’——Ç0lÇŽ,kÆŒööögÏž•’’ú$c¿Ev0 ‰ŽŽf³Ù«W¯îííÕ…{bkk»jÕ*SSS ÃàL}ø³åˆá#´c»ghØY½ 7p½FOž\–––à¬W‚@ $D‰"@ ãP>Â}]GƒÑóŒ˜ÈŒ`º›®ëò1""b”ÊøQòŒ˜àÚq¤ÒÕØt…@ „`8Š~Mù½ÕÇ庈¯Î¦«±é @ ~pïhÿ5å#@ ¾i*++;::Z[[QTð„D"III qÛRbb‚ä#@Œ7(@UVVâp8==½‰i÷îÝ[±bÅ Áòóó_½z…$ä#@Œ+íˆÃᬭ­ ªªªY³fõ³wtt¸j"0”%ú |`0ý®E}ÖØÐ³;å cÔúˆ@ ßt:½­­mÐV´¶¶6:...Žb¬Ÿ|äþYVV€{>!ˆ¯#KKK}}} MLLn޼ɱ_¹råøñã ƒD"Ý»wOLLL€2™¼iÓ&ŽeÞ¼yÇ?sæÌ† ¾ÿþ{îÀ~~~–––£G¾¾¾÷ïßÿ¤«444DEEñx¼Ð¶mÛ†¸ÔŸ¬¬,ªòŽ_Ê‘#G™™™NNN999ÚÚÚWWW[[Ûõë×ótÅb±BCCcbbúúúðx¼ÝîÝ»ñxü0ïðîÓŠS?onëD/ !€¾î®Pêàr§§§g<ìÇÝÜÜòòòDDDlmmÏž=+&&±e˸%:…BùóÏ?3fÌèé餧§kii *ËËËKKKáñœ9s8öOÚ;TCCCXX¸¨¨þuddäÖ­[:äéé9Fâ°½½}ûöíyyyãÇO›6 `mm]__/""رcÇÆùˆÑ•$)88øÅ‹±±±cffæ‰'UUUkjj`¢ÀÚµk;Æ‘¹¹¹,ËÊÊjêÔ©òòò_Esœ={ö3.¼qㆎŽÎóçÏmmmÉd²¢¢"Jp_~/ÅÒÒÒÛÛž¢ÑhFFF4M[[ðÜÜÜ}ûöñó³}ûö¦¦¦ôôt999ƒqþüùÎÎN™aÞ^XZ!~îâ¹â8€¡w…àKoÇ^e ß8Ã0ww÷„„„¾¾>;;»cÇŽíÞ½°zõj¨¹ÉËËt£KN¼•——æGØöa·‚ü$äåå³²²lll`&£¯¯?¦âÍf;::^¼xQTT4 ÀÏÏ/** žŠ‰‰100èž§ùXYYI¥RïÞ½;cÆŒÐÐТ¢¢+W®((((((ÔÔÔp‡êèèܹsGGG‡çãŽ,8ŽJ¥&$$$%%¥¥¥qäã‹/<<<:;;EDD8› ,:UUUcbb¾@4îÚµKDD„Óˆsùòeeee&“yøðáõë×§§§ó3"#)™LfYY‘HlllLIIÉÁÁ@ 2™\PP0¨|ÔÒÒš>}zzzzddäÀq»"""œŠµ¨¨(ÌY0 ‹çž”“ššÚ¯þÍý³_………effJKKgddÀý€ÿó ØXhffÆó)âââttt===%$$xÞ$g¾Ç3bôè÷R¦L™‡?JIIYXXÌÍÍsrrrss8Àωžž^MMMSSÓˆ7@.ÑW]¢V*F BkkkAA›ÍÜÎ4è@óo Ã6oÞ¬¬¬¼gÏhãFŽŽŽ¾¾¾/_¾œ7ožŠŠ €D"¹¹¹%$$ðhjjzòäI¿S¦¦¦ŸýQ»ººR( Îh ÃÜÜÜ’’’tuu œ­Â³èœ}šÍfãp8žFôÑ!úW™†sñ¾}û455oß¾ Çóñ æä䔑‘Ûó8ÓZ‡ò)†††–••ýðÃÜöï¾ûNMMíáÇ€ÚÚÚââb€„„„™™YHHÌ^¿~ÝÒÒbll\TTT^^¸~ýº¦¦¦””Ǥ¤¤ªªjrr2 °°°¨¨ðáÃyyy8›O@îÓÔÔÔ?ò;ëèèH¡PBCCùÝäóçÏÛÚÚ)))(E~8/`ddTWW—œœ çï›››_ºtILLLÀ†***^^^MMM:~âĉ÷ïߣˆE|&MšÄ›ñ«ÞKJJNš4i<ï¶mÛDDDŽ;Ʊ”––ÂÚûýû÷ÛÚÚfÍšõáÇúúzø=&&& ØV¶ÚÂe.nsÑÒÒ"++ËY÷ñSoRMM- ÀßߟûtwwÃ!ÔÜÊÀ¢óãÇ©©©£‡»víªªªºví§OŸN§Ã‰ l6ûÊ•+ÚÚÚ8ާ}qˆ|~Ý4---33óÞ½{âââ6lHIIijj²µµíîî¦ÓéZZZ[¶lÙ²eËO?ý´cÇCCC*• AŠ““Óž={ÜÜÜŽ_ ß±c‡œœÜwß}Ç¡üçŸîÚµËÔÔ ##sáÂeeåóçÏoÞ¼¹··WNNîâÅ‹ýlݺõرc:::zzz’’’ÚÚÚ***NNNÒÒÒS§N ‰¹ñðð0öhiiéããÃó&CBBV¯^=cÆ eee~óo#ç¥(**š˜˜¼~ýŽ‘ÐÓÓ{÷îݲeË_~úôé£G’Éd&“)..îàà !!bñe—‘‘yþü9uÓ¯›Ã0&“YXX(//?},--=sæÌ´iÓîܹ°µµˆˆ¸téRdd¤°°°œœ\ll,‘H¬¨¨X¾|yGG‡[ºti@@€ùÈi¤hkkã¬ûèêê †×µÝo/<èàà ¦¦6sæL˜½ó,:«««=<1‰ç^<˜Á`À^???îü‡Ã¥¦¦ÚÚÚ¢d†øÖ)))177‡c]0 ã>€•%x€Ãáh4lÞâWxA­X_û&üì™ ½ëLvvöáÇ…„„0 CÚ@|C¨©©ñ[[ !î1£. F %E ÜLhùH¡P( Jbâ&›Èô랆Ëqpq8›Íþ.Ä8 ‰E ˆ „””T~~þDŽ¡Á`³ÙÅÅÅœUÞÄ@DP ÄÄAUUµªªêþýû­­­3222‘‘‘’’°ö@ò@ &<§Ô ÄhÉG¸‘Ñh0zž™LWcÓ@ c]>FDDŒR?Jž\;ŽTº›®Œººú×—€Ñ[¯­„‡ãéjlºB ‚œÍÖ¿²|D Ä7MeeeGGÇ„:3($ MA |D ˆ‰¥ ÊÊJ'`Kèñͽ{÷V¬X1h°üüüW¯^!‰@ ùˆ@ ãJ;âp8kkk¨ªªjà$뎎WM†²«µ¡¡áƒP2C ø– G ˆo ƒÑÖÖf``€ñÇÐÐðÇ £ßµ¨Ï---(¥!ü@­ñA§ÓÛÚÚmEkkk£Óéâââ(ÆúÉGîŸeeeMMM3ÄW“¥¥¥¾¾¾………&&&7oÞ„ÆÊÊÊ_~ùåýû÷L&“J¥îÙ³GHHH€2™¼iÓ&ŽeÞ¼yÇ?sæÌ† ¾ÿþ{îÀ~~~–––£G¾¾¾÷ïßÿ¤«˜LæüËd2ÅÅÅuuuwîÜ©¦¦†ÒÜWDCCCTTÇ mÛ¶mݺuGŽihh dff:99åäähkk\]]mmmׯ_ÏÓ‹Å ‰‰éëëÃãñvvv»wïÆãñüûO+Nýý¼¹­½,„úº»B©ƒËžžžqð°?~tssËË˱µµ={ö¬˜˜XDDÄ–-[¤¥¥ åÏ?ÿ̘1£§§GXXžž®¥¥5¨|,///--…ÇsæÌáØR3aaᢢ"ø×‘‘‘[·n=tè§§ç‰ÃöööíÛ·çååtttŽ?>mÚ4€µµu}}½ˆˆ`ÇŽ7nägD FW>’H¤ààà/^ÄÆÆrŒAAAd2ÙÛÛ»££cþüù666æææœ¬]»öرcù˜››Ëb±¬¬¬¦N*//ÿU4ÇÙ³g?õª­[·¶´´¤¦¦*((°X¬øøøÂÂBnùØ××óÄ—äÆ:::ÏŸ?·µµ%“É–––ÞÞÞðF322¢ÑhÚÚÚ†åææîÛ·ŸŸíÛ·755¥§§ËÉÉ1ŒóçÏwvvÊÈÈ óöÂÒ ñsÏÇ ½+_z;>ðz(cøÆ†¹»»'$$ôõõÙÙÙ;vl÷îÝ€Õ«WCÕÈM^^ÞôéÓuÈÑŽ°é¶}`Æ­ ? yyù¬¬,˜Éèëë©8d³ÙŽŽŽ/^ ðóó‹ŠŠ‚§bbb ú…çiD FF>VVVR©Ô»wïΘ1#44´¨¨èÊ•+ 555Ü!…„„èt: »» '''Ø3…Bñõõ---…uÇÈÈHWWW!!¡={öÀÖÇ—/_zyy±ÙlUUUèÐØØèïï_WW×ÛÛ»fÍ///Øž´ÿ~‹E"‘Ž;Ö¯ñ¯¢¢bëÖ­ÝÝÝúúú•••–––žžžåååL&SYYùôéÓ222œÖGYYÙ€€€ÒÒÒªª*{{{X9žd2™úúúÿùÏÄÄÄ´µµ›ššjkkÍÌÌ‚‚‚PÚzzzÒÒÒoß¾566®««kllTPP ÑhþþþW¯^õðð(..ÆãñüZ‹««« abçhÐaÒÚÞ¡/%ñ¶“…ÞB,¦(Úq€”””££#ÌHçÍ›×ÐÐ0|=ÚO;_AºººFEEÙØØTWW3 NWxxxx\\“É$¡¡¡zzz<‹Î¾¾¾®®.IIÉQŠCiii*• -ZŒ>"ÄW“jjjû÷ïß°aCPPPttô½{÷ø…<|ø°‹‹ËÕ«WÛÚÚöîÝ;è袢¢ÎÎΑ‘‘¤ÓéÉÉÉ=âðóÏ?{zz:;;?{öŒL&sŒ;vì°²²êéé¡R©FFF3gÎüùçŸSRRfÏž}ýúõM›6eeeõó³cÇ{{ûÂÂÂÅ‹Ccpp0‰Dœ|˜óµZ[[³Ùl{{û @>jhhhhhð;û©X[[Ÿ;w®½½=**jÕªUÐîäääááxö왯¯off&Ï¢³´´ÔÎήººz´ãð‹/._¾œc{¨íß¿_QQQ€ùX±bEvv¶‹‹KJJŠ€jSDD„½½ý®]»¿ÿþ{SSSÁž×®]K¥R÷îÝ{óæM###îÎˆŽŽŽŠŠ '''€¡¡!¦F§Ó=zÄb±BBB•••ïß¿×ÖÖž={6¬úùùµµµ‰DŽŸªª*¨ÿtuuuuu¡ýÎ;±±±l6»««‹§>€‚UQQ±£££»»[LL,&&¦ßò`pâ<.//ÿñÇ»»»mmm;°±±¤¥¥½yó.B†aØÇ©©©P¾º»»97ÿ‡Ã©««¿yóÉÇÏÃÙÙ™Íf·´´\¹r¾++«‡‰DSSS§¡¡QRRB£Ñ–,Y" ¥†Šþñ´[­mèM!Ð×ݨš£—Ç l6ÛÝÝÝÝÝ}Á‚€~øÁÙÙyÒ¤IIII¯_¿–””ÌÎÎVQQimm]¹reHHÈï¿ÿ.@>Ž,8ŽJ¥&$$$%%¥¥¥qäã‹/<<<:;;EDD8› ,:UUUcbb¾@4îÚµKDD„Ó[rùòeeee&“yøðáõë×§§§ó3"#)™LfYY‘HlllìÏ?ÿÌÌÌ(((XXXº;v<|ø011‘W1¦M›†߸qã¡C‡¸\.‰D2:0ð’éC>¼sçNmmí‹/âI‡Ãm¦¦¦våÊ„P[[[iié×GðððÀÓ/^ÌŸ.##£©©yýúu„Г'OîÞ½‹’––ž3gNDD>/²²²™™™¡ÊÊʪª*¼‡ÊÊÊøn>gŸ²³³qÇ!ººútƒ³é IDAT’%K|||xÓtÚÚÚF£%''ã 6›ãKvðàÁžž„PGGǃ š~tNNN4-22!D¥R›››333ñýûæææñññ8¡¦¦æèè¸~ýúÖÖV„“ÉÜ¿ÿëׯ¡`Á?c„ üg³á.ïeee'L˜ðüÞM›6‰ˆˆàѬ¦¦_½´··ùå—mmmOŸ>ÅÇcFF†€Çêà^[EEEƒq‘ƒÁPTTä­ûø®;©©©Àÿ/èííÅS¨ù”ÁMggggvvö¨–áöíÛycúL&ߨÀårOž<©§§G"‘†L„# öþצ999yyyùùù’’’^^^YYY­­­¶¶¶½½½L&SGGgÆ 6l8tè¿¿ÿ‰'¸\®³³3FIþÎÎÎAAAžžžƒç¯ÄÆÆnÛ¶MIIIFF†Œ?~|ûöí¸_S^^þرcªªªGýñÇûúú”””âââç³qãÆ¨¨(}}}CCCYYY===555ggg …2yòd11?ooïsB111‘‘‘‹-êëë#“É:::þþþ>haaêîîÎáp‚X±b…‘‘‘ŸŸ_oo¯µµµ¨¨è/¿üòÖÙ¢à=[ZZúùù©¨¨˜šš>zôÏ‘044|ñâÅ7ß|#øã‡úõ×_íììðÂLŽŽŽÒÒÒPªàŸ!)))//_QQ'· f!‚ÍfWVV*++‹>ÖÔÔ>|ø‹/¾¸téBÈÖÖ6!!!>>>))IXXXII)55•L&×ÕÕ-]º´««‹D"-Z´(00P@øÈë¤hooç­ûèáá>lh{À:_bbbÁÁÁŽŽŽšššêêêøöÊ!›ÎÆÆFooïÑ›ûXWW«¬¬Œï§VRR***êîîvwwg0$IWWO*2€Á„¶ùúDˆa1{B)©iŽŽŽÃmZVVöüùs¼72™œ09 Æb±ð¹µ¡¡ÁÁÁ¡¼¼Ö×ýœ|Äz56³ã\}}ýË—/‡ìöVRRRPPr†ô_ý…çŽOéééü‹³X,< áïïÏþ'‘HÙÙÙ¶¶¶PÍÀ§®ººÚÜÜÏu!‚ÿ¾XÂ/H$N0·L&ãXñé“DZ1‡ÇõSgŠŠŠöíÛ'$$DÄ v|B455áIïΨ¸¸8^åM\\\ð\R¿q>Òh´ޤÀç/L6ž žÆËqð'’H$.—ûáOà3Sb`‘““»uëÖx.¡·ár¹wïÞå­òLŠÆ †††‚‚‚W¯^ϸzõªà äåååä䬽€ðÆxèà ñƒŒFÃèå Æ³X¯ÆfVÀXF©¥œÁ8?V½›Y‚ÒÒÑïÀøŠ@õõõ$IÀ#¡?oùùù#yèέ[·>|$>Àg;’H$kkkPCCÃà›¬»ºº|j<ÉS­‹ŠŠ š0X6>1,«½½ÝÈȈž±±q[[‹ÅðY³!ƒ…Àp ÷>1L&³½½ý­½híííL&SRRJŒß€r«­­EikkCÉð¯…555[·n­¬¬455=þüûe²|ùr;;»~ø—2{öìèèèÇ{yy}ýõ×ü;::úûû[ZZŽ^ݹsgëÖ­ïô)---QQQ1116›=wîܨ¨(qqñßÿ½µµu÷îÝPóþ¼ŠÐ¦M›¾ÿþûðððçÏŸ8p!”——çìì\\\¬§§‡òðð°µµ]½zõYq8œÈÈÈ”””þþ~111{{û;vˆ‰‰}à^¾Y÷û•Š—íÝðÏô÷öD:¼=ÜyóæÍgðc;;;===ËËËEDDlmmcbb$$$6lØ@¡PB4íøñã¡iÓ¦½yóFXX!”››«££óÖÌkkky÷¥¾w©¥¥%,,\UU…¿:))iãÆ{÷îõññ#eØÑÑáëë[^^ŽÒ×׎Žþâ‹/BÖÖÖOŸ>AmÛ¶mÍš5Ã%0ºá£‚‚BXXØýû÷SSSß;“•+WFEEñÂÇÒÒR‡cee5yòdeeå%戉‰yž>}Z__ÿÍ›74-##cÅŠPáþuøŸRQQakkkgggii¹eËüN§R©t:]OO ˆÒÒÒ;w—¯¯okkknn®’’‹Å:zôhww·¼¼üîÞœJ1ݺ’$DÀÿ «¯« ¡G#™Ã÷ bÕªUgÏžíïï···ŠŠÚ±cBhÅŠ8jäW^^>eÊ”·fÈ‹kjjðëêêj‚ Þ;‚TVV.,,´±±Á'™Y³f©2är¹NNNqqq¢¢¢þþþÉÉÉø­””##£Û™ÀÇ ëëë._¾>>÷îÝc³Ùªªª‡’——¯««ãõ>***ÖÔÔ444øùù-Y²_KIIáëÎ!»©Øl6™LæO þâ‹/ðµixx¸ˆˆˆ¿¿__ßîÝ»¯_¿Îf³gÍšõßÿþWBBêèh044¤P(Ïž=311innnii™8q"NøóÏ?½½½ïÞ½+&&6 Âð466fddTVV*))!„$%%y1èzÕÑ5KNúY7þG@[ìÏ€œœœ““BHDDdöìÙÏŸ?ÿ(ÙòÇŽþóý"Hääd›ÆÆF‹ÅËdpó7dÓÙßßßÓÓ#++;JeH¡Pðëùó燅…ÁAþµðQSSs×®]^^^¿üòË™3gòóó‡ÛÒÙÙÙÛÛ!tûöí­[·æåå ÎYTTÔÅÅ%))iÏž=L&333³¤¤„ƒuëÖùøø¸¸¸Ü¾}ÛÎÎŽ—¸mÛ6++«7oÞ888P©TuuõuëÖeee͘1ãÔ©S?üðCaaá€|¶mÛ¶dÉ’ÊÊÊ àݰ0„ÐÁƒ80¸ÿéË/¿ôóó{úô©õõõ/]º¤¯¯?`Ë•+WŠ‹‹755ÙÙÙÑh´·éÁƒ¥¤¤pIÇÄÄlݺêèh¸ví™LÖ××711¡Óé4­££ÃÖÖöçŸ&‚N§[YY ÷ñÊÊJUUÕÑè WV ·qDU(âô>‚áõ‘zt¤ &$$ô™ýêžžž³gÏÆÇÇã?Ï;wõêÕ©S§îÛ·w´Z[[s¹Ü%K–DDDˆ‹‹™.´™3gΜ9s¸wß•µµõ‘#G:::’““ÝÜÜîܹ3\ó7dÓYSScooߨØ8ÚeHD\\ÜÒ¥Ky)øªT*u×®]***ø8á#BhÙ²eEEEË—/ÏÊÊpÙtÿþ}ooïîîn‘®~¾råJ‡ÐÐÐóçÏS©TþÁˆ®®®ºº:¼p—±±1ž¦Æd2KJJ8NDDB¨»»»¾¾þõë×zzz3fÌÀ—†þþþííí¼^À®®®††ÿàôK—.¥¦¦r¹Üžžž!ã°ª¨¨tuuõööJHH¤¤¤ ¹<Ø©S§ôõõ{{{W¯^ýûï¿ûúú þÕÙÙÙ8pAõööòv |D...\.—Á`œzôHVV¶¨¨HMMíÕ«W®®®!!!ÿØî‘H$‡³gÏž;w.''‡>Ùü n:544RRRþýܾ}»ˆˆo´äĉªªªl6{ß¾}«W¯ÎÍÍ.€>²ÙìÚÚZ2™ÜÒÒ" ¡õôô_ô÷÷#„æÌ™#à·HHHà¹üᣈˆoúúúð$e.—Ìë£!--M__?##ÃÇÇÇÄÄdÒ¤Ixú£œœœ……BÈÜܼ¸¸¸´´TÀN†††MMM­­­½rá,…³`¥bð¯^½ºsç—ËÜÏ„O,Ÿ‚ ~üñGUUÕ   œ‚ç „œœœ¶nÝúàÁƒÙ³g«©©!„<==Ïž=+ 7„PKKKYYÙ€·ÌÌÌ&NœˆÞ«ïÖÃÃF£YXXðæ@×ü n:¥¤¤·#ÅŽ;>|˜˜˜È«Ó¦MC‰‹‹oܸñСC\.—D" ™xÉô!Þ¹s§¶¶öÅ‹ñ¤ÃáBÌÞÞ^<‡LÀñ<ä¡Y[[»xñbþtMMÍëׯ#„ž ãC.555ÞÚü n:;;;³³³Gµ ·oßÞÐИ˜ÈÓg2™øF.—{òäI===‰4d"q`°÷¿6ÍÉÉÉËËËÏÏ—”” ôòòÊÊÊjmmµµµíííe2™:::6lذaCpp°£££¦¦¦ººúp÷— æììäéé9xþJllì¶mÛ”””dddx3”?¾}ûv333„¼¼ü±cÇTUU=úã?öõõ)))ÅÅÅ ÎgãÆQQQúúú†††²²²zzzjjjÎÎÎ eòäÉÃÅÄx{{9÷ÑÅÅELLŒËåR©ÔÀÀ@þ·\]]³³³]]]Éd2ï±~~~½½½ÖÖÖBBB¢¢¢¿üòËôéÓ¡ŽŽ’àà`KKK???SSÓGá9†††/^¼øæ›oüСC¿þú«›Í–””ttt”––†Rÿ IIIyyùŠŠ <Åe@WAl6»²²RYYù3Xô±¦¦æðáÃ_|ñÅ¥K—B¶¶¶ ñññIIIÂÂÂJJJ©©©d2¹®®néÒ¥]]]$iÑ¢EN¹Ê¿ðôôlkkÃwÌèèèxzz¢»!iÀ:_bbbƒ›¿!›ÎÆÆFooïÑ›ûXWW«¬¬Œï§VRR***êîîvwwg0$IWWO*2€Á„¶ùúDˆa1{B)©iŽŽŽÃmZVVöüùs¼72™œ09 Æb±ð¹µ¡¡ÁÁÁ¡¼¼Ö×ýœ|Äz56³ã\}}ýË—/‡ìöVRRRPPüÄB„Ð_ý5’‡>®ÒÓÓùoa±Xááᡟþ™ÿü/$$táÂ[[[¨fàSW]]mnnŽçºÁÿ_,á$‰N§ã>¸á/+>}ò86æð¸~êLQQѾ}û„„„‚8pàÄŽ€Oˆ¦¦æpkKøû%$$ð¬t þtÖ>@ q>Òh´‘¬§Ÿ ¼0ànµ((€)±0ŽÈÉÉݺu Êa8x9¤ÿ÷ÿþß[oN`<"€ñCCC£¡¡¡  àÕ«Wã³.^¼(x999k/ |€ñeÈ[j`´ÂGü £Ñ0z9ƒñì#Ö«±™0ÖÃÇ„„„QjãG)g0ÎcÇU¯ÆfV€`£´€ô;^Þzu°ãõjlf ‡÷°õ î¼>„ÂGáãH\¹reÒ¤I::::::ÆÆÆ8ñ—_~122ÒÖÖ¶¶¶.))aV“&M °MjjêÇñëßÿ=88øŸ/ÁÈÈH‡3Âÿ­˜–––žžž±±ñìÙ³ùWϹqãÆ¢E‹´µµgΜéííÍ`0F’•¥¥%AøOÚÚZ„‡Ã 722200 R©¡¡¡}}}ﺟ˗/?~ü8ÊìÙ³¯]»6ä–W®\ùð’a±XkÖ¬100˜={vVVÖ;}öÞ½{sçÎ]°`A~~>Ô1€ðñ}Ì›7¯¦¦¦¦¦æöíÛ8EOO¯   ¶¶vÛ¶m+W®ìïïI>iiiT*õܹsoÞ¼>>zô¿vuu]·nÝ GøÁ?ïôéÓ·oßþã?ž>}ŠzüøñòåË}}}kkk«ªª(Ê·ß~Ëf³ßšUgggzzú€D__ß›7oæææVVV“ÉäîîîwÝÉ•+W&%%ñþ,--åp8VVV£W,$‘H•••gΜñõõíììùg/\¸°téÒüüü @©¯¯×ÕÕ}üø1¡V­Z5Ü–...d2!dmmÝÞÞ>ÂÖ4))iëÖ­³fͺ|ù2NyöìÙÊ•+ÍÍÍ-,,8páÂ…[·n…„„ØÛÛÿý÷ß©©©GíííÕÔÔlmmÅ ݳgBèæÍ›öööóçÏ_°`Aaaá€ï3B¨§§gÆ æææ_}õUTTÞLQQ1::zíÚµ ,ÀOM ëëësrr²··ïé鉌Œ\³fÍš5k¾ýöÛ7oÞ8p૯¾277÷ññyŒCCC …òìÙ3„Ðþýû]]]-Z„ݽ{wWWWvvö[3Ù±cÇÞ½{ùÍÆÆÆŒŒŒ˜˜%%%„¤¤ä–-[äååßu÷h4ZsssMM ïXððð¸~ýúÂ… çÍ›gaa‘––6à#ÖÖÖUUUø5>"B---ß}÷Ý‚ ,--cbbð»L&sð%ÙÙ³g׬Yƒš>}º±±qNNNooïܹs333B%%%T*µ³³³¯¯/88xÁ‚VVV›6mêííMIIILLLJJ²··§ Àx 555wíÚåååUTTtæÌ™ßÿ×Sbhh8wîÜÄÄĉ‹‹›;w®œœÜ[3¯©©yùòåüùóÝÝÝO:…×®]kffVRRrýúõ•+W:88Ìž={×®]—.]š3gÞFBBbÉ’%¸qíïïOMMuwwïèèØ¼ys|||aaaRRÒ¦M›X,ÿ× È!ôßÿþ!týúõÜÜÜ´´´œœ¼å—_~—˜˜øÓO?!„‚‚‚ÄÄÄ222.]º$%%…ª®®>|øpfffqqqJJÊÕ«W¯_¿Ž ‡Ú6v\»vL&ëëëã™™™ï-ccãŠŠŠ·fbjj:sæÌ“'OòR*++UUU•••?p÷DEE]\\p$“ÉÌÌÌtww×××ÏÊÊ***º|ùò¾}ûÚÚÚޚϺuëÖ®]›ŸŸŸ———™™yãÆ \Ûÿøã[>yòdêÔ©øµªªjss³„„Äü±cÇŽ[·n­_¿>..NVVöàÁƒRRRùùù¸c5&&fùòå...^^^—.]’••…ªãȇ|xÙ²eEEEË—/ÏÊÊÂ-‡©©iEE…B©­­uvvVQQág?>))éÒ¥K#ÉùÔ©Sîîî$iñâÅÍÍÍ åæÍ›.\À((( ÷Ywww??¿ 6¨«««««_½zµ¥¥w®à³¹¹™÷ŸžžžÁ9†‡‡ ÉÈȸººÒh4„BHEE¥«««··WBBbÀ·ÛØØàÄÂÂB'''iii„———ŸŸÔ¶±ÀÅÅ…Ëå2Œ“'Oâÿoþâ{ qrròððÀñ!¹ñÃH¡¡¡çÏŸ§R©S¦Linnö÷÷oll{ýúuCC•J“É,))áp8¡îîîúúzSSÓ   Á—p¼Ÿ ©©òõ×_ïÚµËÈÈ!”MNGõöö@ß ›Í®­­%“É---8…B¡àÚÚÚ‹-*//Çáã… öìÙsîܹ‰'Ž$Û´´4QQÑ3gÎ „úúú’““7lØ0½211éë뫬¬LNNvwwGq¹\ F®¼THHˆ÷'ﵨ¨(~A"‘†œà()))8ðïJKKÓ××ÏÈÈðññ111™4i’žž^YY™““Þ€Ãáܾ}{„ÔÖÖž?þ‘#G🆆†MMM­­­Þ©££3eÊ”ÜÜܤ¤$|åóÓO?Í;7.._¥ôööþŸ#YD„öá›u¸\.Aééé.r´µµÝ”)SšššTTTBOž<áuÇVTT(((àQ~œ'¼†ŠãÙÝ:³sçNmmí‹/âB„P}}=ž ÖÔÔô×_"„Ο?vîܹ)S¦Œ$Ûœœ šššÊÊÊÊÊÊ .$''O˜0ÁÔÔ”7ëåË—!YYÙŽŽŽÁ9¬X±âÈ‘#EEE8055}ôèÑÕ«Wñ»åååüKII ÎÙÚÚúĉAtuu¥¦¦ÎŸ?¸½•••rÊ—µµuzzzWWAüñ‡€À?ÏÉɉF£EFF"„6oÞœ’’‚ç'°Ùì)))<r$vìØËd2BjjjŽŽŽëׯdzo™Læþýû_¿~ý~;éááY[[»xñb„P[[›––BèÁƒ¼iŽ<Ó¦M»wïBèéÓ§ø §ÒÒÒsæÌ‰ˆˆÀaå£Gðåååå¼õ ø $>>ž ˆܾ}û믿Feggþý÷߸|h4ÚÁƒ{zzB<€º>¾ƒœœœ¼¼¼ˆˆˆéÓ§zyyq8œÌÌLCCCo¿ývíÚµxÀ7 àåË— .Ä úðî•NRR’³³3ïOcccQQÑâââcÇŽ•••™ššÎ™3wL®\¹2<<|îܹÅÅÅü9¸¹¹¥¥¥}ýõ×x>"…B9}úttt´™™•JåMÓäœs@@€°°°™™™‹‹ nM‡´~ýz{{{++«7ÇØÚÚº¹¹ÙØØ˜™™çJ‚±#888%%åéÓ§êêê§OŸÞ¿ÿÌ™3õôô ÆùóçyÝÌo5uêÔeË–ñ.c:ddddgg§££ceeÕÕÕ…'0¼ggçÚÚÚeË–‰‹‹ã85,,ìÇŒ‰‰>>8ÆÝ¿ÿàµ~6oÞÜß߯««ëêê-''‡ÇÊOœ8A¡PNœ8áïïßÜÜìççgdddmmmff¶xñb|ç€ñFh›¯Oä³!”’š&`Ì®¬¬ìùóç#Ô{'d29!!a4rãÙG¬Wc3+@°êêjsss.—‹"‚ÿ›Â/H$Nç¿‘tpã…cŧOÇÆ†§Î€wá#€ð@ø |Ÿ’w[6üûï¿¥ý½œÁxöëÕØÌ ëácBBÂ(µñ£”3ç±ãǪWc3+@0Þ#šÿÍð!4zëÕÁJx`Œ×«±™0ü²?|Œ†¦¦&&“ÙÖÖEñ P(RRRS§N…¢øTcG‰$`¹ðÑݽ{÷É“'AÀ{€;¯ø÷1™L]]](‡’žž^OO”@øÀ' Ƭ¡ØÂGáãÈ”••-X°`úôé³fͺyó&BˆÅb­Y³ÆÀÀ`öìÙYYY#ÉDKK«ªªêÃw&22’Ãá H$",,ÌØØØÈÈÈØØøÐ¡CPÆ ---===ccãÙ³gãÕsÂÃÃ7oÞŒßÍËË£P(wïÞÅzxxœ8qB@V–––Aà?uttjkkB'<<ÜÈÈÈÀÀ€J¥†††öõõdßÂÂÂÔÕÕÕÕÕCCCy)Ó¦M›:uª¶¶vRR12nnnÊÊÊ3f̘2eʼyóΜ9CDyyù_|Áf³y›%&&Λ7 ˆÉ“'ß¹sg@&ÉÉɳfÍ #>epDÀ˜ †‡‡G``àƒ®]»6mÚ4„ÐÁƒI$Reeå™3g|}};;èz{ IDAT;ÿ±Ÿ7dø˜‘‘qõêÕ¢¢¢;wî[ZZ¾_æýýýP>9§OŸ¾}ûöüðôéSKKËëׯã·èt:•J¥Óé8˜+--µ²²Ugggzzú€D__ß›7oæææVVV“ÉäîîîÜ碢¢S§NUTTܽ{7###??!ôý÷ß?xð ©©)##ãÇ|ñâÅsÛ±cG]]Ý“'OvíÚõÓO?9r„J¥*))]¹r…·MBBÂêÕ«‡ËÁÀÀàÔ©S°ø9@øøÎêëëuuu?~Œ£´U«VáVgÁ‚666!YYYEEE„ÐÙ³g׬Yƒš>}º±±qNNÎÈ¿EQQ1::zíÚµ ,¸xñ"/qÏž=ÞÞÞ4-33!ÔÓÓ£¦¦Æÿ)„PXXX__Ÿ“““½½=ÿùgÏžMš4IFF!$%%5kÖ,œ~àÀ¯¾úÊÜÜÜÇÇ7ùÁÁÁGŽÁ‡GFFâ»fÍš5kÖ|ûí·oÞ¼ùóÏ?-,,,--mll B(99ÙÆÆfþüùNNNPÉÆ CCC …òìÙ3“æææ––>àðñîÝ»bbbššš‚ã°½{÷²Ùl^JcccFFFLLŒ’’BHRRrË–-òòò#ß±û÷ï«©©=|ø!´gÏ„Й3gV®\)##3aÂOOÏÓ§O#„TTTDDDB\.WHHè=úÒæÎƒQ^Wkccã­[·œ‡û ®®®®®.‰4§¾0 ÿÕÿ—¿¿?>6üËᣦ¦æ®]»¼¼¼ŠŠŠÎœ9óûï¿#„îÝ»7a„¥K—šššnÞ¼¹«« !Ä¿:†ªªjssó;}Ñ—_~—˜˜øÓO?ñ'ÆÆÆž9sfÇŽ­­­C~0((HLL,##ãÒ¥KRRR¼tWWׯÆFSSÓ-[¶dddàîÉ¿þú+%%åêÕ«¸/*<<\À.UWW>|833óÆû÷ï?wîN¿pႌŒLiiéÙ³g³²² ×­[ççç•l ºví™LÖ××711¡Óé===¶¶¶555AÐétÁ]!SSÓ™3gžpà€ºº:•J‰‰™4iÒ‡kùÿ411yòäIGG‡‡‡GnnîË—/ ‚HHHpvvž0a/$IVc„‚‚ÂO?ý¤  À+X^ ^À¿>"„–-[¦§§·|ùòcÇŽÉÊÊ"„8NQQÑñãǯ_¿ÞÝݽ{÷îÁmä»~‹îkéêêêííʼn‹-B‘Édccã²²²wÊpâĉ%%%GŽ™>}úo¿ýæææ†*,,trr’––òòò*,,ƒ„„B(77O&CIKK‹‹‹çää<~üxÙ²eööö|ùò%T²1ÅÅÅeÆŒŽŽŽÁÁÁøŸheeuýúõ¿ÿþÛÌÌŒD"iiiUWWÓéô‘Ìj ùí·ßX,˜õ{èææfhh¸téÒÄÄD999G¯¯ïÇ‹ŠŠöîÝ‹;Pß#fÅ/íìì’““ñÄG#×cŸ¢¢"/‚ı#Ž0&ÂG6›][[K&“yM×Ô©SçÏŸ¯¬¬,**êìì|ç΄Д)SšššðOž<™2eÊ;}‹¨¨èÿì+‰Ä›nÈ1d³ÙBBB¼†p$w*H¤Ù³goذ!333//wº ñ6À¯EDD†ÌVRRr¸œ¹\®ƒƒÃ¥K—.]ºtùòåââb¨dcJZZÚýû÷?îããƒç ZZZÒét:naa277/..~ëÄGL[[{þüù¼†††MMMÃu‡ü°º{÷.…Byþü9NQUUųDB¸'’{*•:iÒ¤<ÞÞÞZZZ8ð]7nÜPUUÅ×~«W¯NHH(**ûꫯø7«®®Æ¹y{{B¤––ÄŽ0æÂÇ;wjkk_¼x1 I;;;—””tuuqåÊ===„““S||}Šâ¿@VVvð:7nܨ««Ã¯KKKeee)еµuzz:Þó?þøcþüù¡iӦݻw·èƒwƒF£9s‡ oÞ¼¡ÑhÉÉÉxÊ#›ÍÆ4kœœœh4žÌJ¥R›››333qw£¹¹y||¼„„„††ÆH²Ú±cGll,“ÉD©©©9::®_¿W &“¹ÿþׯ_¿Ó¾íرCOOïêÕ«¾¾¾øºkùòåÉÉÉ===‰‰‰Ë—/Gýý÷ß\.!tûö튊 |¬ñÄÆÆÖÕÕÕÕÕ ·9AEEEÛ·oçÍ ¡Ñh/_¾ü駟ߣ««‹s‹ýTþÅ8‚„ØFÃû?´0'''///??_RR200ÐËË+++ËÐÐðû￟;w®°°°¾¾~TTBhóæÍ6lÐÕÕŽŽ<÷>a/‰dgg×ÞÞ…ÇŽ#""<==ÕÕÕùÛÑõë×ÛÛÛ‹‹‹gggKKKãÄîîîÀÀÀ/^ˆ‰‰ÉËË'%%‰ˆˆØÚÚVWWã›~Œq›êêêšíêêJ&“¿üòËÁ»aaaáçç·téR„Є ÒÒÒ,,,BCCÝÝÝ9A+V¬022‚z6[ZZúùù©¨¨˜šš>zô÷‹¾xñâ›o¾a>S§N]¶l/®:tèЯ¿þjggÇf³%%%yO0ÜÏ}éÒ¥+W®”––N˜0W¤‚‚‚yóæ¹¹¹ „¾ûî» qèС¢¢"‰$//øðaŽ›‡……}ò86æ0Û'%%íÝ»·­­MQQñ·ß~³³³C¥¦¦†……‘H$iiéøøx--­·†™™™8|D-]º”—þNÏÕÒÒ®ªªÆû¶qãÆ½{÷úøøŒ‘ìèèðõõ-//GéëëGGGñÅ!kkë§OŸâökÛ¶mkÖ¬.€Ñ  †‡‡ÇÑ£Gmll:;;ûúúÞ#“•+WFEEñÂÇÒÒR‡cee5yòdeeeøŸ vúôi}}ýŠŠ [[[;;;(“–•¥¥å–-[ð[t:J¥Òét===‚ JKKwîÜ9\>¾¾¾­­­¹¹¹JJJ,ëèÑ£ÝÝÝÞTÈ©Ó] +IBü¯þG_WBF2_MSS“B¡@‰ñÉÌš5kL —ËurrŠ‹‹ ô÷÷ONNÆo¥¤¤ Ø~ÈD>NøX__ïààpùòåiÓ¦EFFVUU{öì?ÿùÏÇ…„„\]]7oÞ,8g¶uëÖšš|%çáá!$$„{bbb2 …7 õÕW_1™Ì®®.YYYaaáîîn„Pww·€«h\—øcÇ =<<’““mllY,–¶¶öpíÈMgOO¯Ñüè( ot~þüùaaapt€-|ÔÔÔܵk———×/¿üræÌ™üü|„н{÷¤¥¥—.]úâÅ‹¯¾ú*,,LFFfíÚµ4íÔ©Shd³¶EEE]\\’’’öìÙÃd2333KJJø7X·n‹‹ËíÛ·ñ˜Nܶm›••Õ›7o¨Tªººúºuë²²²f̘qêÔ©~ø¡°°pppîÜ96›½xñâìììE‹ñÞrvvöööFݾ}{ëÖ­yyy¯_¿þî»ï’’’LLLúûûñy !Äb±Ö®]«««<ä/*--={ölVV–¸¸ø•+Wüüü222–,Y’––¶aÆþþþÔÔÔË—/wttlÞ¼9##câĉϟ?_¸pá7øóY»v­¥¥åp"×®]#“ÉúúúÃ•ÆæÍ›sss544:Ôßß?žë=¯¬ÄÅÅMLLèt:Fëèè°µµýùçŸ ‚ ÓéVVVÃ}¼²²RUUu4ú•ÈmQŠ8½ÿ«Ô; Óh0<Ô(&&á#¿ñ0”òäIkkkEEEÜí7þ|IIÉI“& —,Y²dÉ’áÞ}WÖÖÖGŽéèèHNNvss»sçÎpíÈMgMM½½}ccãhAqqqü!2žïD¥RwíÚÅ‹¹‡Làã„¡eË–-_¾<++ _6q8œ¢¢¢+W®P(ooïÝ»wÿòË/7oÞäM.QPPIÎ+W®tpp =þ<•J2e ÿõt]]³³3BÈØØOSc2™%%%'""_zÖ×׿~ýZOOoÆŒøÒÐßß¿½½L&ó‘›››°°°°°°³³saa!øxÿþ}ooïîîn¼h{yyùÌ™3ñu°°°°œœÞréÒ¥îîîk×®îçäää<~ü/6FDgg'BÈÝÝÝÏÏoÆ êêêêêêW¯^miiáM4‘hnnæÏ'((ˆ÷¥ü\\\¸\.ƒÁ8yò¤„„Ä¥ñêÕ+###¼ŒÙªU«†‹t?{Ê !deeuýúu2™lffF"‘´´´ª««étúÂ… œ‚‰Ñ‰ïüh³¢s.ÜyÕç&žþÞä =’2¿sçÌ}ä‘••Åg¿ÏXiiéþýûóòòBl6;<<¨=</|8\‰999Ñh´ÈÈÈáJ£¢¢¢½½!”••5Îë=¯¬BT*µ¹¹933ßÑinn/!!!àjjjŽŽŽëׯommE1™Ìýû÷¿~ýN(£a„ Cvº¸”•••0a×8QSSãææ–––ÆëaC wÛ5úßѼúÄE> CQQ‘·îã»î’¦¦f```@@€àvdȦ³³³3;;{TKlûöí ‰‰‰¼ L&³©© ÷\œâ†ÑËŒg±^ͬ€±>÷ ¨oMG)g0ÎcÇU¯ÆfV€`Ó§Oÿ÷ÃG„Ðè­W+á1^¯ÆfVÀpx[ÿ—ÃGŸ´úúú®®®q{ëÌ[)((À­3@øøœ#hìßµ$I$’¡¡áøüùùùùË–-{ëf·nÝzøð!T* ||Úµµµ€Æ¾¡¡n(‰®®.%9Œä©ÖÆÆÆ×®]ƒÚÀp`ÙpÀ˜Æb±ÚÛÛŒŒˆá·µµ±X,(®·‚1kbd Ô†½€1Éd¶··¿µÇ¨½½ÉdJJJB‰·†ü^¸p!äàà%À¿>–••mß¾ýÉ“'RRRǧR©ïšÃòåËíìì~øá^ÊìÙ³£££>ìååõõ×_óoìèèèïïoiiù»êèè¸eË–ùóçó'ª¨¨Ü¿_JJj„™(**¾xñBDdˆ’¼sçÎÖ­[ >¤<ßš ›Íþí·ßRSSÙl¶¤¤¤ÁÏ?ÿ¬©© •{0---QQQ111!!¡M›6}ÿý÷áááÏŸ??pàB(//ÏÙÙ¹¸¸XOO!äááakk»zõê!³âp8‘‘‘)))ýýýbbbööö;vìûÀ=¼|³î÷+/Û»áŸÅÓßÛé ýÖÍÞ¼ysíÚ5(1LZZzÆŒŸÇƒ›£¢¢bbbŠ‹‹ñÙ>))iïÞ½mmmŠŠŠ¿ýö›B(555,,ŒD"IKKÇÇÇkii½5|ÌÌÌÄá#BhéÒ¥¼t!!¡w:± WUU ã}Û¸qãÞ½{}||ÆHvttøúú–——#„ôõõ£££¿øâ „µµõÓ§OqûµmÛ¶5kÖ —Àè† ÃÃÃãèÑ£666}}}ï‘ÉÊ•+£¢¢xácii)‡Ã±²²š­¯¯_QQakkkgggii¹eËüN§R©t:]OO ˆÒÒÒ;w—¯¯okkknn®’’‹Å:zôhww÷‡7Õr*ÅtèJ’ÿ«ÿÑ×ՆУ‘ÌWÓÔÔ¤P(Pb<<033û ~ˆ•••££ã7ß|ÃÝž••¥¦¦–ŸŸïààÀ`0„„„V­ZU]]­¡¡±wïÞ   ´´4Áácfffff&~}á‚ ø#Èw¢¬¬\XXhccƒO2³fÍSÈårœœâââDEEýýý“““ñ[)))FFF¶2|x—Fü/ÞézéCÃÇúúz‡Ë—/O›6-22²ªªêäÉ“ ,À‡¬¬,Þ²¥¥%  ¹¹¹¯¯ÏÝÝ}ýúõ‚s¦Ñh[·n­©©ÑÑÑÁWrBBBAAA¸÷ñÁƒëׯçr¹L&SÀ·äååíÚµ‹Ãá(((DEE î“»råJTTÔ‹/ìííCBBøßŠMKKc³Ùâââ‘‘‘øFÅ¿ÿþ;$$¤§§GHHhÏž=óæÍã…hþþþ½½½ü£’““ãããûûûåå壣£'Nœ¨§§WRR‚âÐÐP|Tß¼y344´»»›D"…„„ èe2™ÂÂÂââ⼔ǟ?¾ªª ç#""âææ†ßŠŒŒ¬­­E½|ù2--íìÙ³ü; ¦¦6x¯ÔÔÔð§ÄÄÄ^¿~JHHø,G )ʳgÏLLLš››[ZZ&NœH§ÓþüóOooï»w‰ ×‰ÛØØ˜‘‘QYY©¤¤„’””äÅ èUG×,9égÝ8ÇñpØ¢hd·;ˆ‹‹ó ««ëóø!&&&RxÃP_}õ“Éìêê’••îîîFuww«¨¨ —®Kü±ã‡GÉÉÉ666,K[[{¸vdȦ³¿¿¿§§‡×h~t …7:?þü°°08:ƃñ×_ îEÂó}ÿ¡ðQSSs×®]^^^¿üòË™3gòóóB÷îÝ“––^ºté‹/¾úê«°°0™uëÖmÛ¶ÍÊÊêÍ›7T*ÕÔÔT@ÎÁñ‹ IDAT¢¢¢...III{öìa2™™™™%%%ü¬[·ÎÇÇÇÅÅåöíÛxÌ'øuuõuëÖeee͘1ãÔ©S?üðCaaáà8àܹsl6{ñâÅÙÙÙ‹-â½åìììííº}ûöÖ­[óòò^¿~ýÝwß%%%™˜˜ô÷÷ãóBˆÅb­]»VWW788xÈ_TZZzöìÙ¬¬,qqñ+W®øùùedd,Y²$--mÆ ýýý©©©—/_îèèØ¼ysFFÆÄ‰Ÿ?¾páÂ7nðç³víZKKKþ‘ªª*55µá:e««« %$$†Ü!B ¹¹¹bbb›6mJMM]µjÕçw8]»vL&ëëë‹‹‹›˜˜ÐétÖÑÑakkûóÏ?A§Ó­¬¬†ûxee¥ªªêhô…++Û8¢*qzy½¤ÞFÃ]O‹‰‰AøÈo< åŸräHGGGrr²››Û;w†kG†l:kjjìííG»¸‚ˆ‹‹ã‘ñ3T©Tê®]»x1÷‰à%--­®®.¸'ˆËår¹Üššš"|D-[¶¬¨¨hùòåYYYø²‰Ãá]¹r…B¡x{{ïÞ½;44´¤¤„ÃáDDDà‹ÂúúzÁá#BhåÊ•¡¡¡çÏŸ§R©S¦L῞®««svvFãijL&sð·¼~ýZOOoÆŒøÒÐßß¿½½L&ó‘›››°°°°°°³³saa!øxÿþ}ooïîîn¼h{yyùÌ™3ñu°°°°œœÞréÒ¥îîîk×®îçäää<~ü/6FDgg'BÈÝÝÝÏÏoÆ êêêêêêW¯^miiáM4‘hnnæÏ'((ˆ÷¥ƒ¯îÝ»÷ÝwßõööÚÚÚFEE!„lll$$$†Û!BóæÍÃsøfΜùøñãÏì@rqqár¹ ãäÉ“¸p¬¬¬®_¿N&“ÍÌÌH$’––Vuu5N_¸páG¼P!?Ú¬èœ w^µÃ)§¿·9h¤ÌïܹsydeeñÙï3VZZºÿþ¼¼<„›ÍÏËË322 ܸqãpOƒ—D"988œ={öܹs999¼ðqp;2dÓ©¡¡‘’’ò”ØöíÛEDDx£%'NœPUUe³Ùûöí[½zunnîp‰|Ìð‘Íf×ÖÖ’Éä––œ2uêT …‚{eœ£¢¢¸\.Aéé鸩!)S¦äææ&%% ž·+""§Ç#ÅC~Kvvö€á|Á£ûüïáééyîÜ9‹…gÇÊÊ*77×ÓÓs¸ßÈår Ž›˜˜ôõõUVV&''»»»ãÍ444.]º4 E使 ˆðèëë755µ¶¶*++Ïœ9óÆGŽá}„wµ1ä ™È+R|Bäp>·QÔ´´4}}ýŒŒ “I“&áérrr!ssóâââÒÒÒÝ»w—‰¡¡!¯Ø?îî-œ¥±p¬Tü¼zõêÎ;\.WpŸŠˆˆÈœ9s ÄÆ‰ŠŠ //¯ÌÌLÜ=vãÆW¯^á{ÎÎÎöööj B¨µµµ¬¬lÀ[fffï}P{xxÐh4 ÞèáÚ‘ÁM§””Ôœ9sF»ÄvìØñðáÃÄÄDÞ½žÓ¦MC‰‹‹oܸñСC\.—D" ™õ ¼dúïܹS[[ûâÅ‹xÒ!>hKJJººº‚¸r办žž´´ôœ9s"""ðûèÑ£.¦åááçá-^¼˜?]FFFSSóúõë¡'OžÜ½{!4ä·˜˜˜TUUÝ»w!têÔ)mmí]w¡3gÎô÷÷³X¬ôôtþ‰†l6»··O};{ö,N455­««Ãʧ­­ §‡„„˜˜˜¸ººöôô ù[h4Zrr2˜`³Ù¼ðnÅŠGŽ)**ÂO@655}ôèÑÕ«Wñ»ø.9~ååå>äOQWW_²d‰ÏóçÏq o¯ÞºÃíÕxàääD£Ñ"##BT*µ¹¹933ßÑinn/!!!àjjjŽŽŽëׯommE1™Ìýû÷ã٢ࣛ0aÂà#w𥬬¬ì„  ¸Æ‰šš77·´´4^ëäÉ“›ššð²  `¸Û®ÑÿŽ(**2Œ‹| †¢¢"oÝÇwÝ%MMÍÀÀÀ€€ÁíÈMggggvvö¨–ØöíÛy<˜LfSSîJ8yò¤žž‰D2êìý{srròòòòóó%%%½¼¼²²² ¿ÿþû¹sç ëëëã!ÔãÇoß¾ß(//ìØ±‘äïììäéé9x2Sllì¶mÛ”””dddxrƒ¿EUUõèÑ£?þøc__Ÿ’’R\\ÜàoÑÖÖ^²dIKK‹ƒƒF㥋‰‰;::jjjª««ã9§ %11100°³³SXX8<<|îܹxûÿüç?NNNiiiƒ§?[XX„††º»»s8‚ V¬X/‘ÝÜÜôõõ]]]ñ:A åôéÓ!!!AAAýýý:::þù'>û÷ï0÷!¹hÑ¢¾¾>2™¬££ãïï?’n¯Æ‰àà`KKK???¸ã9†††/^¼à¿ÇsH‡úõ×_íììðzIŽŽŽÒÒÒpB ’’’òòòhÐAl6»²²RYY}ü\íÛ·ïðáÃ---NNNjjjååå¡¡¡ÍÍͼ“vVV–ATTÔ¢E‹DDD44¼ÐÐÃã½½ßb¨­­íáá>lh{À:_C¶#C6ÞÞÞ£7÷±®®.66VYYŸä•””ŠŠŠº»»ÝÝÝ ‰DÒÕÕG ™À`BÛ|}"ݘ=¡”Ô4Ü 6¤²²²çÏŸ Øà½‘Éä„„„ÑÈŒg±^ͬƕúúú—/_ÙÅ«¤¤¤  O,¡¿þú ÏŸÒÓÓùf±XxÂßߟÿòƒD"eggÛÚÚB…Ÿº[·nüÖK}‘Éd+>}ò86æ0³ÎÚÏzö:ÏÞëYÏzÖÞÀßê>âc'ø‘E»Ÿ¢`¼»Ã½êÛGÓ1’ üà¾ãhÙÕø¬™9sæ?ï>"„Æîyuð$<`œÛÕøÃ1F[å ÷àÇâÅ‹ííí?ìÖ™Ï2uêTØ:à>ð={<0ØiO²³³+**þ˜§Ÿ••µbÅŠÏV+..~õê€ûÀ¿ÛãÑ××g1Ø¿|ù6„ööv=ù#0’·Z+++çææ‚µÀpÀcÃ×twwúôIII‰1<ÊÊÊ---ÝÝÝÐ]ŸÖ¬#£©© ¬†¢Œkººº>}úôوѧOŸºººxxx Ç€ÏºÌ_ÿýw„¹¹9ô ücîã¾}ûâãã‰9îæÍ›ýýý»»»7mÚTTTÄÁÁ±gÏž%K–°bcccdd´aâdÁ‚Çwttüå—_˜+[XXøøøhii}…¶žžžzzzÌ…"""ÏŸ?çåå¡AAÁÿþ÷¿dò=YZZêííý-]úY!RRRœœœT*UGGçСC\\\Gmllܳg˜ø}ÅÆÆ¶yóæuëÖ…††¾ÿþðááÌÌL++«¼¼<999„­­íâŋׯ_?¤(~ùòåþþ~NNNSSÓ]»vqrr~£†·?;zûɇOðgô÷t†›Ë|¶Zooonnîĉ¡Ç0|||’’’ßÇ‹›:õòå˼¼<|·ß¿KK‹  àþó###„Е+WöîÝËÎÎÎÇÇ#%%õY÷ñÆØ}D-[¶Œ(gccû¢ ‰D*//'‘HX·M›6íß¿ßÍÍmœt`kk«‡‡GQQBH^^>""âçŸFéëë×××ãñkëÖ­NNNÃÀغ~~~~~~¡žžiiiœ¡|äÈvvö²²²êêj--­I“&±bggwèÐ!Â}|øð!FÓÖÖž>}º°°0ügƒILL”——ïíí¥P()))«W¯†>aÝWOžyòdGGÇ·Õ‡3Ê8çÌãaG ø¯þ‡¾ö„^$_M\\\@@zŒ ººZ]]ý;8mmm æÐƒ  `ZZÚ¬Y³²²²ÌÍÍ›ššØØØÖ®][QQ1gΜýû÷ûûû'%%±voܸqãÆ üù÷ßg0Ìä!,,|ïÞ=CCC|“™?þ¸ê@:niiyúôi???Ÿ„„üÓåË—•””Ô²FÇ}|ñâ…¹¹ù­[·fÏž^^^~þüyâ×ÔÔT „ÐÕ«W9‚’PVVÎÈȰ¶¶f!™B¡x{{WVVÊÊÊ♜­­-›¿¿?Ž>VWW»»»Óéô9sætuuá£|}}ëêêúúúÖ¬YãîîŽãI!!!4mêÔ©‡ÐÖíÛ·:ôßÿþ×ÔÔ400ù§èè褤$*•ÊÅÅŽ7*vvv²±±íÛ·OWW÷$ýý>>>===GŽáàà|R 111ýýýS¦L‰ˆˆ˜6mšœœÜƒ°C„¯êÇutt°³³ˆŒvuu‘H$..®áâaT*•ŸŸÀ ^¸p‡„óóóÃÃï_¿>XŸY³fýPv¯¨¨( ðîÝ;UUÕººº†††iÓ¦åççûúú^¸pÁÕÕõ¯¿þâääl0˜ššš”””²²2!!!„áƒ~#[ÛçOæ{×Aƒ{Óÿ6•l»×pWÇI{{û÷q"ªªªJˆe¨… vuuµ··Oš4‰D"utt „:::DDD†“†m‰ÙwüvÒÖÖ6!!ÁÐদ¦»»}CŽ#Cýýý¬+ß‚€€±:¯§§·wï^¸:€Ì} qttܽ{÷¥K—²²²˜½xñ¢þüöí[â¡ç¢¢¢uuu¬%spp¬\¹2>>~ß¾}]]]7nÜxðàs77·•+W–””à5 \¸uëVmmíÞÞ^sss111—´´4IIÉ‹/nذáÞ½{ƒý€k×®Q©Ô¥K—¦§§›˜˜?YYY¹ºº"„JJJ¼½½333›››âããUUUûûûñ} !ÔÝÝíììþ/}ì=‚FƒÁKœœœà>2ó#,åŸ?^___PP‡ýôôôxxx~úé§œœÖ™™™™Ùp¿~)úúú'NœhmmMHHXµjUiiépãÈCgee¥©©iMMÍXwƒÁ8}ú4³‹Œß¡ª¢¢BøÜCÀ踡+VäääØØØ¤¥¥1O›jjjŠ‹‹‰$ȯ¸2íììÌÍ̓‚‚®_¿®¢¢2cÆ æùô³gϬ¬¬BÊÊÊ8M­««ëÁƒ4-,, O=_¼xÑÜÜ,'''))‰§†>>>Ÿ>}œ[µj‰D"‘HVVV÷îÝcvŸ?îêêÚÑÑA&“+**BEEEÒÒÒxL"‘&OžŒk.[¶lÍš5ÎÎÎÃNFFÆ›7oðR>ƒÁhkkC­Y³ÆËËë×_ÍÎλ{÷nCC‘hÂÍÍ=ÀÕö÷÷'à¬ËËË÷ôô¬_¿þèÑ£¬»wH}~V®\I§Ó›ššÎŸ?ÏÍÍÒÖÖ¾ÿ>??¿ºº:;;»””TEEE~~¾±±1‹[0clü;/ÊüˆŒßK?~‚{AO'2—IŸ—––Bî#Á¤I“ðÝï;æáÇ‘‘‘™™™!*•š™™©¤¤äçç·iÓ¦áÞ:/;;»¹¹ùÕ«W¯]»–‘‘A¸ƒÇ‘!‡Î9sæ\¾|ùoè±;w’Édbµ$66VTT”J¥8p`ýúõwîÜ®FÓ}¤R©UUUüüü Ìåñññæææ|||øëŒ3jkkñ æíÛ·#ÉÅ‘••1cÆ;wâããçí’Éd"¯¯Óétƒ‘œœŒLzzú€ôgÖÙÐÌ¿2 {{ûk×®)((twwã,ãáÐÖÖ¾s玽½=sëÌÐétssó‹ãªªª}}}eee kÖ¬ÁÕæÌ™sóæÍ#"ñ™XnnnœûÈì>’Édâ^Ù××ÇBŸ„¤¤$yyù””777UUÕŸ~ú §?Nž~üXZZJ§ÓYÇTÈd²††ÆÔ©S¡Ç~ž>> °°0|_xýúuSS“ªªjyyùÓ§OB/^”‘‘º»téRwwwrr2s¢!•JíééÁ©oW¯^Å…jjjÏž=à Ê4­¥¥—ªªªZ[[wvvy. %!!/LP©TÂ#\½zõ‰'rrrðÕÔÔ^¿~}÷î]ü+Þ%ÇLQQÑ«W¯†ë1–= ]oöìÙÕÕÕxè%&‘Ãéóã`iiI¡PÂÃÃB***uuu7nÜÀ;:-ZÃÍÍÍâ…³fͲ°°pwwollDuuuEFF677à e,˜0aÂA÷SÙI“&M˜0ºë¡²²rÕªUIIID„uúôéµµµø™=ܶkô¿«‚‚‚MMM©L455 Ï}üR•ÄÅÅýüü|}}Y#CmmmééécÚc;wî|ùòe\\‘àÑÕÕU[[‹GíóçÏËÉɱ³³Yö æë£™™™YYY<<<~~~ŽŽŽiiid29;;{„ Ì©-[¶üúë¯óæÍãâ⊈ˆøìH€±²²ò÷÷···œÌ½uëV!!¡‰'¹3gÎìܹ‡6§L™rêÔ)QQÑ“'Onܸ±¯¯OHHèôéÓƒ[‘‘‘133khh077gÎäää °°°Ãcˆ‹‹óóókkk#‘H¡¡¡:::¸þ¶mÛ¸¹¹---“’’§?kjj­Y³†F£1ŒÕ«Wã)òªU«äåå­­­ñs‚ýýýûûûeee/\¸À,'22rÈÜÇ•+WrrrÒét¼ó`îܹfffK–,!æ¾ÃéóC ¥¥ååå%""‚wœ#¡¨¨øßÿþ÷³—:vìØÁƒŒŒ¨T*……nFž)S¦}úTUU…Ç[[[ômKÛžó5ä82äÐYSSãêê:v¹Ïž=‹ŽŽÆ·z!!¡œœœŽŽŽ5kÖ455±³³Ï›7/&&!4d! †m«‡[øá¨î®N„Ðå+I8 6$=zÿþ=‹ _ ??ÿ¹sçÆB2ð#3Šv5>EýP¼xñâÇC†x…„„¦N o,!üñÎÿ1INNf^ëîîÆ«>>>ÌÓvvöôôôÅ‹ƒÁÿvŠ‹‹ÅÄÄXÏ®ét:N¯¬¬d‘^ÈÏÏ}Åú·o¢£ŽÃ[gø ..>Üs”à‹`ΣåââÂOyãââb_ 3à>ü@Àî¢ËÓøqÌ…ìììt:ýûxaŒ ð1yòäâââ¹Ø>Nÿ믿<å f úð1gΜ—/_fggüøñÇìâéÃ1eʔɓ'³xöà>üXÀ6#þV÷¿Èh,;ÉÀÌ(ÚÕøãÝ}îPß>šŽ‘dà÷GˮƧ(`ÍÌ™3ÿy÷!4vÏ«ƒ'áãܮƧ(Ž1Ú*;¯pppppÿN¤¤¤ÊËˉ¯ ¥¥¥#9ðèÑ£ߨzxx8FcQADD¤³³“¹¤§§ÇÜÜ\__?""¬jÜ"%%%''§¬¬¼`Áæ§çš˜˜ÈÈÈHKK»ºº655}VF URRRPPPQQ êëëEUƒ‚‚æÏŸ/ PPP@†……©©©©¨¨üúë¯Dsïß¿·µµ;w®¬¬lLL ³Õ«W  naaqïÞ=°à»r¿Žþþ~kkk—±vS\\ÌÆÆ–íååÅìa€…7KJJΞ=ëëë[__z󿇇GUUUyy¹€€ÀòåË©T*k9?¾sçNYYY^^??GGÇ(êibbróæM ¢äæÍ›7nÜÈÎÎ.**"“É'OžÄåk×®UTT|þüyYY™‘‘Q?>>^PPþq`¹/^¼˜7oÞ›7o°¿µvíZ„P~~¾±±±®®®¦¦fRR®YPP`ll¬©©©¥¥•““ó-ê¾zõÊÂÂBSSSGG¿·´  @WW×ÛÛ{õêÕ………W®\ÁÃêºuë( …BY°`®®îÇ"„#""œ RSSB{÷îíëë³´´455íì쌎Ž644ÔÑÑ122zòäÉZUVVnÛ¶­¬¬ÌÔÔôþýû~~~[·níëë 000ÐÖÖÞ¼ysOOB¨ººÚÈÈÈÐÐÐÙÙÙØØ8??!¤¯¯O\MMMqÌ©¡¡ÁÁÁÁÀÀ@KK+**j8wòñãǽ½½ñOMMMÂ¥?8ŠŠŠïÞ½CEFFZ[[›˜˜ „888öìÙÓÞÞžžžÎâðššš”””¨¨(!!!„§§ç”)SFQCuuõ3f0—üõ×_ .äååecc[¼x1¾¾ Þ¿ïããC"‘Èd²¨¨(®\__»sçÎáäçää,^¼XQQ188!ÔØØHù_$$$üüüÀH€áøúw^‹‹‹‡„„8::îÞ½ûÒ¥KYYY!yyù´´42™üéÓ'ƒÅ‹3 ‡øøxUUÕþþþ‘GhV®\ÉÉɉ?ãa!´qãÆõë×ÛÚÚ>{ölÉ’%>D=}ú466¿ÞþñãǸ&^šlii¡P(þþþC+,,Œš;w®——W}}½‘‘‘™™™¿¿ÿ±cÇRRR¸¹¹BVVV®®®¡’’ooïÌÌÌÁªÊÊʆ„„œ:uêòåË¡ß~û­­­íÂ… رæååÅåíííââ²iÓ&KKË?ÿüsñâÅ,:ÁÅÅeëÖ­ÚÚÚ½½½æææ***jjjƒunnnÐÉJJJªªªÁÁÁ'NŒ‹‹[¾|9///˜;Ann.??¿¼¼й¨¨hp'›šš&&&:99ÅÆÆ&''ƒ­Ó:ÞÔÔtþüyü_3Œ/Â`0¾â¨o„B¡TWW[ZZrqqéèèppp „h4ÚÇoÞ¼©®®~úôéµk×>xðàìÙ³ÒÒÒjjj?~Nšµµ5‰Dš0a‚œœÜ›7oæÎ‹ª««srrЉ‰£—\à>"*•ZUUÅÏÏßÐЀK¶oß®££súôi„¡¡!^«-Ølll!ž!ë{zzΛ7oãÆ,ŽEáa!ÄÎÎÞßß? E{{ûk×®)((twwÿüóÏ#T•P‰N§ãÅkâ§ööv¢éÿïŸ “ %ñ®:Î`0’““x´¬u&pqqqpp“””[gž–¤¤¤¸¹¹©ªªþôÓOrrr=Â=vÈJJJX¿TPQQ±¶¶¶±±ño@nÞ¼yóæÍ¡ÄÄDüŸÎœ9söìÙêêê¡U«VmÛ¶­§§çÁƒ©©©t:Ͼnݺ5À#$“$ 'é¶··¯Zµ*88xÁ‚`' ¾iëLpp°ŒŒLjjª¯¯o]]B¨¥¥EJJ !T]]3ùÔÔÔž={VXXˆæ–––¯nnâĉòòòñññ¡§OŸþùçŸ8Þ6$áááMMMû÷ïÿŠc'MšÔÖÖ†ýãžžqqq„ÐÕ«W¿Bg …räÈœwØÚÚZ]]=qâDIIÉ””„Pii)‘ï8{öì§OŸ"„êëëq˜“OCC#,, »•¯_¿nGð,))9}úômÛ¶mذ }––– %<<!´eË–Ë—/ã¥[*•ÈËË‹S!‡cÖ¬Yîîî¡®®®ÈÈÈæææ1Õ™N§×ÔÔ „jkkÿóŸÿ`?RWW·«« [NFF†¸¸877wLLLEEEYYN5.++ûl4±¿¿ýúõVVVæææ`k¾>ú˜‘‘‘™™™••ÅÃÃãçççè蘖–¶k×®   „„^^^¼â, ççç×ÖÖF"‘BCCutt¾ºÑS§Nyyy?~œL&Ÿ8qBXXøÕ«WCŽ…û÷ï—““[ºt)BhîܹÇ|ìp­¸»»›ššrqq¥§§XXXˆ‹‹‹‰‰‘H¤/UØËË«§§G__Ÿƒƒc÷îÝÑÑÑîîî‡VPPÀ‹Ñ!__ßM›6ݼySXX˜ž9sfçÎ8¶4eÊ”S§N ÙÊplooïïïÏÚúa ÐÒÒòòòKLL öôôd0ººº×¯_'â»ÃqìØ±ƒQ©T >>¾QTÏÏÏïÚµk>|°··çàਬ¬ìïï_½zõÇ999·lÙòË/¿ „¸¹¹Oœ8áèèH¥R§L™ûuÍÝ¿ÿÞ½{Ø^¾|ù·?Áø^aÛêá~8ª»«!tùJ‹5»G½ÿžõ¢Þ×ÁÏÏîܹ±<þ±°°ðññÑÒÒ áÞÞÞ3gÎd~–ÐÅ(ÚÕø¬)...ÍC§Óétzee%W 7xa_±þí›è¨ãðÖ™ï“>¨©©UVVâÔO€Ñ‚ ]ðÏrýúõ±+$$„S!Fˆ>à>à>ÿ8_–û¸nݺ1Òcì$?2£hWãSŒw÷¿Hz,Æø1’ üà¾ãhÙÕø¬£—Ð~ñÎë±{^< çv5>EÀp…XÈ}À}À}À}À}À}üÛ°±±9sæ sÉ‚ rssYõîÝ» .0 ¹}ûöÈéììd.ééé177××׈ˆCù>’’’““SVV^°`óÓs MLLddd¤¥¥]]]›šš>+ŠF£…††*)))((¨¨¨õõõ¢ªT*uçÎRRRÒÒÒnnn¸ðöíÛ*** ëÖ­ëêêpHww·“““‚‚‚ ÒÒÒXP(0 à_ï>ÚÙÙÅÇÇ_>|H£Ñ´µµYåïÞ½‹‹‹#JöîÝ«¡¡ñ-j³±±egg{yy17Fó¯&11±¤¤äìÙ³¾¾¾õõõ¡7oÞØØØxxxTUU•—— ,_¾œJ¥²–ãááñøñã;w•åååñóówttŒ¢žû÷ïùòeqqñÓ§O}}}Bîîîqqqeee|||ƒg5GŽagg/++»té’‡‡G[[Ûp…ðϸ/^¼˜7oÞ›7oBááák×®Eåççëêêjjj&%%áš?655ÕÓÓ300¸wïÞg%S(”ºººÊÊJü5>>ÞÖÖ–J¥hkkoÞ¼¹§§!daaáçççàà°uëÖÀÀÀ§OŸšššzxx „üýý BïÞ½³³³[´h‘¦¦æáÇBÑÑц††:::FFFOž<R‡ÊÊÊmÛ¶•••™ššÞ¿Ÿ¹¡¾¾¾Ášttt¬_¿^SSÓÊÊÊÕÕ544!¤¯¯_^^Žšššb} ´´´¢¢¢ð¯‚‚‚ÎÎΩ©©¸°  ÀØØXSSSKK+''çøñãÞÞÞø§¦¦& ‰áR`ä(** ¼{÷!immmbb‚âààØ³gO{{{zz:‹ÃkjjRRR¢¢¢„„„B<<<žžžS¦L-õúúú¢££CCCùøøBsæÌAݹsG^^^FF!äèèxõêÕG]½zÕÉÉ !$!!¡¬¬œ‘‘1\á€©×æÍ›544tttž?Ž:tè…B¡P(úúúííí`0Àè¸âââ!!!ŽŽŽ999—.]:zô(BH^^>---''çÖ­[hiiimmݲeKLL̽{÷âãã7oÞÜÝÝÍZ2ÇÊ•+q²««ëÆkÖ¬9rä//oVVŽôŽW[[Û… >"--}óæÍ#GŽ0KsvvVWWðàÁýû÷íììBVVV™™™¹¹¹aaa„C6YYÙUUÕ›7ojjj274¤&¸ÿþ™3g°›8...ÎÎÎYYY™™™7nÜ(,,ÄåsçÎ=}út\\ÜöíÛBÍÍÍûöí»ÿ~NNÎüùóíííoݺ…Çò¸¸¸åË—óòò‚¹¹¹üüüòòò¡ŠŠ uuuâ'2™¬¬¬<ܼSVV&***,,~üø÷ßÇ_§NŠzþü¹««kGG™L®¨¨áÉ ©INNNdd$BˆŸŸßÌÌl8!]]]< Ñhaaa¡ŽŽŽ/^¨©©!„ŒŒŒB"""ííí===EEEÒÒÒªªª!‰4yòd„©©ibb¢““Slllrr2˜ïW°råJ:ÞÔÔtþüynnn„Ð'l$0Œ¯8jäÐh´¶¶6>>¾û÷ï—––ZXX ˜“|¶õ!+ Y(++‹mX]]Ù¨BBB F`` Ø 0šî#•J­ªªâççohhÀ%Û·o×ÑÑ9}ú4BÈÐа§§‡N§Ï™3çæÍ›_$YVVvÆŒwî܉Ǯ'NÇKÆjòðð|éÀoooíÚ5…îîîŸþy„ § ÛÀÎ%“‰ï« Óé #99;.ÌpppàìììýýýCêàâââàà """&&&)) æû$%%ÉË˧¤¤¸¹¹©ªªþôÓOrrr=²´´$\·’’Ö/TTT¬­­mll£¤ˆˆ;;» BHIIiöìÙ•••3gÎÌÎÎÆÞ¾}+""2Àäf̘Q[[+""‚+àê…Ìpqqá$‰HíÏÏÏOMMlÕðM[g‚ƒƒeddRSS}}}ñ¢XKK‹””B¨ºº§ý©©©½~ýúîÝ»ø¢¢¢ ·µµ ¯ªªZºt)BˆB¡9rgûµ¶¶VWW¨?iÒ¤ÖÖÖ…¼¼¼jjjÄJ÷‡¨TjOO¸¸8BhpöØHR===¼ï»¥¥…H^œ={öÓ§OBõõõ8ÌÉÇǧ¡¡†ÝÊׯ_·ÉWMMíÙ³gxi›F£µ´´ „$%%§OŸ¾mÛ¶ 6€í~ ––– %<<!´eË–Ë—/ã¤@*•ÈËË‹S!‡cÖ¬Yîîî¡®®®ÈÈÈæææÑRoâÄ‰ÆÆÆX¥/^ÔÔÔHII———ãœà˜˜ìïR©ÔßÿON,--cbb FuuuIIÉ/¿ü2\!kòòò:?x’ßä>fdddff†……IHHøùù9::Òh´]»víÝ»wãÆQQQxEL@@ 111""B]]]EE§HŽ++«ªªª+Và舗——’’’¾¾¾ººúÒ¥Kñ–fÄÅÅ%%%-ZäèèÈ\~êÔ©G©©©ihh\ºt‰““3 ýïß¿'‘H_zâCjâëëÛÜܬ¡¡áì쬯¯kúúúž9sÆÁÁ!""‚ž9s¦¦¦F]]]MMÍÍÍmðãW0qqq~~~êêê:::Ä{{{ƒÁÚ¹FB@@ÀåË—ëëëÅÄÄ###¥¥¥åääššš®_¿Nƒ‡ãرcJJJFFF²²²ÚÚÚíííx›ËhñÛo¿%''+++ÛÛÛGDD̘1câĉÇ·³³›7o^{{;~ @WW׺uëpFì–-[úûûçÍ›gmm†,dÍúûûðØ¡ €m«‡[øá¨î®N„Ðå+I,Öì=zôþý{Ö‹z_??ÿ¹sçÆBò?Bxx8FÛ±cÇX÷ööž9s&󳄀¿Á®Æ§(`Mqq±˜˜ëL?:N§Ó+++'81^ØW¬û&:ê8¼uæ_ÇÔÔÔ*++7nܽÀ?º`Ôñññ ±BBBÄS~þ) ú€û€ûüã|YîãºuëÆH±“ üÈŒ¢]OQ0ÞÝÇsçÎÑ?F’Üw-»Ÿ¢€53gÎüçÝG„ÐØ=¯ž„Œs»Ÿ¢`8Š‹‹ÇB,ä>à>à>à>à>à>Ž„ððð½{÷(ܽ{·’’’ŒŒŒ¾¾þƒF"GJJJRRRVVVVVÖÝÝ!dccsûömíÒh´¿¡¿X«ñ¥=3êÍ ®_ZZª¯¯?]ñîÝ» .ü»Ì]JJJNNNYYyÁ‚ÌOÏ),,411‘‘‘‘––vuumjj‰(---ƒ¿ÊÊÊVUU!„h4Zhh¨’’’‚‚‚ŠŠJPPP__ß(ªÊ‚‚‚SSSâ«··wZZ¶+++)))555==½Ó§OEßâæbccEDD”•••••555333ñ¯"""çÍ|OøöëhÈÞ¾wïÞèÞ%0=rrrò§£G|VÂíÛ·UTTÖ­[×ÕÕ5\µîîn'''… `SA%''kii …‡‡5===ïÞ½ ã%cå>‰œœ\vvvUUÕÖ­[íììúûûGrÔÕ«W++++++£¢¢¾h¨øžØ»w¯††ÆøÔíÝ»wqqqÿº.MLL,))9{ö¬¯¯o}}=BèÍ›7666UUUåååË—/§R©ŸÕÖÖ–œœ< ÐÃÃãñãÇwîÜ)++ËËËãççïèè-UGƒÁ¸wïž¾¾~UUÕòåË׬YSUUUXXWYY9 ò·_;Ds!==½’’’’’’íÛ·{{{ÿý1¾Ã0߯â:*((ÈÉɲõol.$$ÄËËë«ïèèpww‹‹+++ãã㋈ˆ®æ‘#GØÙÙËÊÊ.]ºäááÑÖÖ†o×gΜ±µµe®éååµgÏ/÷ñÅ‹óæÍ{óæ ¾S¯]»—¿~ýÚÊÊJKKËÁÁßV®\ÉÏÏÒ××ÿôéÓW¦˜èèhCCC##£'Ožà±¡¯¯ÏÒÒÒÔÔ”9ÂQPP ¥¥ååååäädfföìÙ3„Ї–-[¦§§·páBbîäääææfcccccÓÝÝêëë 000ÐÖÖÞ¼ysOOÏú¼yóÆÄÄD___KKëàÁƒ¡€€€'Nà_CCC‰IüàžaÆÂÂbëÖ­...æææ!!!¸Ðßß¿  ß¾·oߎjjjRTTüóÏ?G¨3nnnXÏ5kÖ477÷ööJKK¿{÷ÿêçç‡õÏÌÌÔÕÕÕÔÔ\¶lÙ‹/p0ƒNòóóñ3 Ÿ>}jjjêááñ¯³{EEE|î‘‘‘ÖÖÖ&&&!Ž={ö´··§§§VÈ®]»öïßÏìhÖÔÔ¤¤¤DEE !„xxx<==§L™2Zª>~üØÔÔTOOÏÀÀ€}íß¿_UUÕÌÌŒ !„Š‹‹eddxxxŽ9²jÕ*KKKvvv„ÐÌ™3 BPP0<<|ݺu111 ZZZÄ„mps:::;vìX»v­±±ñóçÏ4ǬyWW¾ð :;;gÍšE|®!‚¢¢¢E‹_/^Œ¶„„CCC===KKËššâ*vrrZ¾|ypp0ó=¸Žz{{ýüü.\¨¥¥…ßý“ŸŸollŒ >))i¸aÀeþêÕ«sçÎ%%%™ššž>}º  @WW×ÛÛ{õêÕ………DsC^ÔCv5ÁË—/?|ø ''7ä½e$ܹsG^^^FF!äèèxõêU„PJJŠA__ƒÁX±bŽ@_½z‡9%$$”••322BÒÒÒÒÒÒØZfÍšÅÅÅURRC&òW)..âèè¸{÷îK—.eeeáòœœœ)S¦øúú†……íÛ·8äôéÓ:::“'O‰ü•+Wrrr"„8°téR¢ÜÊÊÊÕÕ!TRRâíí™™éïïìØ±””nnîBž={'&&öàÁƒ7æääLš4)!!¯¿¿ßÎÎîîÝ»FFFø®}çÎNNÎÍ›7_¹reíÚµGŽáååÅç5d(åܹsK–,Ù¼y3G±8#=ƒééé9yò$N_±bEzz:vh0022ºqãÆ… ÜÝÝçÏŸ>õÄ2§NŠ£‡¶³³‹õóóëîîNJJÊËËûð჋‹KZZš¤¤äÅ‹7lØ0Ü ]HHÈÎ;oÞ¼ùo´ûÜÜ\~~~yyy„PEE…››Ûÿ]d²²²ò“'O–-[ÆZˆššš´´ôùóç7lØ€KÊÊÊDEE………ÇBÕÖÖÖ-[¶¤¤¤L›6íýû÷ÆÆÆ………yyyééé999ÜÜÜöööÄQ·nÝZ²d ViëÖ­Ã Ÿ1c†áèhkk÷ööš››«¨¨HII nÏEDD._¾üÛo¿aG„h!”““£¦¦ÖÙÙÙÞÞ~ùòåÏžàçEx¢ªªª4íÉ“'ŠŠŠÕÕÕ:::>¼zõjZZ×íÛ·½¼¼RRRð_yïÞ=|8qâÄà{¡C‡jkksrr899?~üˆ’——OKK#“ÉŸ>}200X¼x±€€Àg/óI“&­[·®µµu÷îÝØ«~úôillìœ9sð„„ÅEíââ2 «ÕÔÔˆúùùù***Ÿ½·deeyzzPÒÎÎnÛ¶mµµµÄK&DEEëëë †¥¥e^^^`` °°ð„ œBoß¾e®YWWÇÚÚsss•••aÔà›ÜG„Њ+rrrlllÒÒÒ&Mš„ MLLp¸ÅÁÁûy˜ëׯÇÇÇÜÛHJJ£ûž?îêêÚÑÑA&“+**X ‘––C-Z´èíÛ·---¼¼¼aaa………$©¾¾¾¢¢»ºººØ[•––Æ!Õôôtƒ‘ŸŸÇ…!›ÐÐÐØ¹sç§OŸ´´´tuuY(3\Ïà˜ÝÄÄäÞ½{Ìî#77wll¬žžž®®®‹‹ËÈÕcææÍ›W®\¡ÓéØÅÙ°aÃâÅ‹·mÛ–””¤­­=mÚ´ŒŒ 999III„­­­Ï§OŸ¾'‹_¹r%Nojj:þ<ö-ˆüů 00ÐÒÒ’Í2Œo‘ÆZÕ¼¼¼††"+Ž››»®®.''ÇÊÊj„ Ø{8~ü8þõöíÛ›6m ’··w~~~KKËü£€xbÖÕÕõàÁ†êèèxñâEkkëàæB222"""øJ9sæÌ€æð¥zøð¡££cQQëiÕà†$$$ˆ «W¯NHHPTTŒ_½z5FÆ›7oV¬XOp­ Ï!DæöíÛ‡¯t<•joo÷ññ©©©áäälnn~ùò%á½}Ñe.--}GÖµ®®îà®fvß½{GL?X4j``PVVöYb¶Ætww9!ü¬Ý ³ö/÷q¤P©Ôªª*~~þ†††!+°±±á¿ÿþû¾}û®]»6mÚ´oi‘Á`ØÛÛ_»vMAA¡»»ûçŸþ¬†ÌŸÙØØbbbêëëSSS999wïÞM¬ùrppàììì8eŠN§ãÕaÖMP(eeåìììS§NÅÆÆ^¸pL&÷â¾¾>2™<\ÏhiiuuuM˜0{„¶XÕÁ~3_cc#•Jåàà¡zååå‡ÎÌ̸{÷îáÇB?ýô“ººzjjê™3gðxÆ`04ÍÆÆ6àŒþÕ§%)))nnnªªª?ýô“œœÜ£G,--qVRR2— ÊÈÈèéé¹ ŠŠŠµµµ£€ *NŸ3gÎà v†˜møåË—Ø=RPP(**ž֡C‡B³fÍ"òqN§3ŒäädfßëöíÛƒ›ûøñãà+…¹9f.\ˆ @‘H¤Á†4Üy¬ZµJWW788øÊ•+xžN§›››¨9`õ|$lß¾]GGÇP ‡K|™°éõ]=@NkkëgÍÌÌÄQIfvìØ1sæÌììl\òöí[|EøðûÙmmmx hÆŒµµµx2ðöí[uuuÕÛÛûÝ À÷Ê7m –‘‘IMMõõõ%&¦éééÍÍÍ¡ .èééá¸ãÞ½{¯]»6cÆŒoT—J¥öôôˆ‹‹#„pNfÒ¤IC.?þ¼¨¨!”’’2wî\~~þ–––9sæprrvww³Îo£P(GŽÁÉ”­­­ÕÕÕCV{õêÕÔ©SmllvïÞsƒfÏžýôéS¬-q²gòóóKJJ°ïˆJLLìïïÇëȸA]]ݶmÛRSS¥¥¥qÕÕ#hiiÆ sÌ]·qãÆ€€€þþ~<Æ«ªª–——cý/^¼(##3yòäÙ³gWWWÓét¿!úœçþuXZZR(œ–ºeË–Ë—/ãÄ/*•ÈËËËúeÍ®]»¢££ñþÖY³fYXX¸»»766â¨^dd$þÓ¿]U55µ×¯_`±aëééedd࿆È}d^JÞ¼ysbbâÕ«Wq¶¶¶Á{×øøø444°o÷úõ릦¦!›ææ˜ùóÏ?[ZZfÏžM”pssóññám@ÄÞäÏ64}útyyù;vÌ™3K£P( 8å‘J¥–––n}È{…B9qâDoo/v§ðu!%%…ª®®.//î_æ#´ÿõ]Í\_VV'Ù(¡¡aå vìØ266.//Ǥbbbð¼ˆJ¥:::8::b§ÖÒÒ2&&†Á`TWW—””üòË/,NäÙ³g8#à›¢™™™YYY<<<~~~ŽŽŽxôÒÑÑÙ¸q#^~ÂKi¾¾¾T*ÕØØ˜lð‚òWÀÉÉ`aa!...&&F"‘p¹»»»©©)Wzz:óJ™²²r\\œ¯¯/‰D:yò$BÈÑÑÑÉÉiýúõ$iþüù,ÚòòòêééÑ××gccãààØ´[… IDAT½{7ó‚óØÏÁÁÁÆÆ†xÖÖÖéééÖÖÖüüüsçÎ%jî™ÈÉÉ™™™544˜››S(¢œF£­_¿Þßß_BBâàÁƒ†††ššš#T@KKkÖ¬YVVVÓ§O'Ü}uuu^^^"{OPPðäÉ“7nìëëÂQ™¹sçš™™-Y²DDD„ˆøŠ‹‹KJJ.Z´HZZúìÙ³ÿ:ÓÀ;«ÄÄăƒƒ=== †®®îõë׉Ûg™9sæŠ+¢££ñ×cÇŽ"""_q"ïÞ½»pá—%((H£Ñ¾®ëJKKõõõGñ¿¸råÊ«W¯ÀÄÛ•²²ò‚ ˜ŸžSXXhbb"###--íêêÚÔÔ4QZZZ •••­ªªBÑh´ÐÐP%%%•   ¾¾¾¯Sµ¼¼œ¹dHÉÕÕÕS§NUVVVTTTRRòöönhh,­­­M__¿··÷ëìÿ«¯£Q7]š$'' ùÓ£Gœœœ†üéèÑ£ŸUéöíÛ*** ëÖ­ëêê®ÚË—/ŒŒæÏŸohhX]] W¯^-+++++kllüçŸ"„úûûŒŒá’ÜÇaÉÌÌŒŒŒLIIyöìÙ¥K—Èä=-(11±´´´¬¬ŒB¡˜››—••!„öîÝ«¡¡ñ7èüîÝ»¸¸¸õ_{åʕׯ_ƒ‰¶«’’’³gÏúúúÖ××#„Þ¼ycccãááQUUU^^. °|ùr*•úYQmmmÉÉÉ =<<?~|çβ²²¼¼<~~þŽŽŽQÑ|8É|||%%%Ož<ÉÍÍ%“É¿üòË`ÿæøñã666\\\_gÿ©©©<<<ÿ¬éö÷÷³ÖdÅŠiiiCúd!!!^^^_­OGG‡»»{\\\YY_DDÄp5===mmmÿüóOggg\xðàÁÊÊÊÊÊʵk׺ºº"„H$Òúõë:×#?œûøâÅ‹yóæ½yó!¾víZ\þúõk+++---‡¶¶6<¿÷òòš3gBHTTt„î#†D"ÙÙÙY[[?~!äïï_PP€º{÷®ŽŽŽ¾¾¾¦¦æüÜ·oŸ««+…B¹qãÆ9ÑÑц††:::FFFOž<Á!””ükzzú²e˘ë>}úÔÔÔ ZZZQQQ¸NAA±±±¦¦¦––VNN1Nkkk+))¥¦¦âAAÁˆˆggg¢033SWWWSSsÙ²e/^¼ íáÇ.\¸hÑ"777ì"´µµ988,\¸ÐÒÒÒËË+44´¬¬LMM8DOOïÁƒÄ×ßÿ½¸¸800ÐÔÔ´  `È“µ°°Øºu«‹‹‹¹¹yHHþuÈ3ýþPTTx÷îB(22ÒÚÚÚÄÄ!ÄÁÁ±gÏžöööôôôÏ Ùµk×þýû™Íššš”””¨¨(!!!„§§ç”)S¾]á‘Hž8qbhh(×Õ«Wgii‰?»¹¹éëëkii­Y³¦¹¹^¸p[²¡¡aSSÓû733ëîˆØ¶m®ßÚÚ:gÎœŽŽŽ¾¾¾€€mmíÍ›7X[(((044twwWSS344|ö왃ƒƒªªêŠ+°›ŸŸollŒ¯…¤¤¤Á¦îäääää´|ùòÞÞ^¬É766¶¥K—^ºtipDðÇrrrxª`bb‚OÿàÁƒ#ìü;wîÈËËËÈÈ „q÷zyymß¾!ÔÔÔ¤¨¨øçŸ644¯Y³!´råÊÊÊJl`Ä3{ûûûÙØØðgssóäää‘ÌR¾+÷Q\\<$$ÄÑÑ1''çÒ¥KGÅå………§NÊÏÏŸ6mZXXBèéÓ§oß¾544\´hQddäW´µ`Á‚§OŸ2—„……>|8;;;//ˆGÎ;7::úÒ¥K»ví„°²²ÊÌÌÌÍÍ óööF¹¸¸œ>}ÿzæÌ™ 6 WHKKß¼yóÈ‘#¸²³³sVVVffæ7 ›››öíÛwÿþýœœœùóçãyyyóòò.^¼H ´X±Ó§OÇÅÅáñæÃ‡¸õû÷ï[[[hú?þ¸|ùòÝ»wïß¿ ÅŒéÓ§?|ø066öÞ½{!…)S¦`·µ¨¨¨¯¯oÑ¢E„ssó „„„ܼySCCc¸“íéé9yòäµk×JKK±Ã4øL¿K»ÏÍÍåçç———GUTT¨««?‘Édeee<Ç`ššš´´ôùó牒²²2QQQaaáQWx„’ÙÙÙ•••\,/_¾$“Éı{÷îÍÎÎÎÏÏ×ÐÐ8|ø0B(///22òÚµkùùù¿ÿþûĉØ?fÕªUׯ_ÇkñW¯^566æãã;rä//oVVˆžrüõ×_›6m*,,TUUµ´´---''çÖ­[hii`ºø:~üø7ˆèép755µÜÜÜ äç竨¨àÏçÎ[²d >}$ÈÊÊRv1kkk PTT´¾¾žÁ`8pàÁƒ7nÜpuuuwwŸ?þÛ·o§M›ÆÉɉç½Ó§O¯««ÃG9;;KHHìß¿ÿÔ©SÄBDDd$f0!ËÁ+V¬ÈÉɱ±±IKK›4i.411ÁA|ƒ¦ÑhOŸ>MKKkoo_²dÉœ9s„ú> ‘aF ­­½uëV WÀM#„øùù•••=zdffFÔþü¹««kGG™L®¨¨Àáº;wVVVrqq=}útÉ’%õÞÕÕõàÁ†½áŽŽŽ/^´´´HKK«ªªâ¡bòäɸòêÕ«BóæÍkooïééáææF!„DDDpaqq±œœœ¤¤$BÈÖÖÖÇÇçÓ§ODs÷îݳ´´äããá¼è–——‡GúÉ“'çåâ⣫«{úôiggg8ÜÉâììì&&&÷îÝÓÕÕ|¦Ì1Î+WÒéô¦¦¦óçÏãg°uœÀÀ@KKK[[[ÂP¿EëK`„’W{÷î³ßyóæÍ+W®ÐéôÎÎN\~çÎU«VáÏØð†dúôéòòò·oß633KHHؽ{7B(==Á`äççãÙˆ‚‚€£pÚž¾}ûVDDÆËÓííí>>>555œœœÍÍÍ/_¾$\=CCCüO}öæ#,,Œ†;} ;w~úôIKKKWW—¹šÎa÷rssÇÆÆêéééê꺸¸°þ#NŸ>Í`0Î;pýúufmŸ/Àwî>R©Ôªª*~~þ!³õBx¥fæÌ™\\\\\\FFF¥¥¥_ê>ãˆ`÷îÝÏž=ËÍÍuuuuppظq#Ö‡PŒX$Â÷q{{ûk×®)((twwÿüóϸ|ãÆgÎœáææ^·n‹%u:Î`0’““™Ç°ávð‰„³µBDp¨¿¿ŸÁ`0«Gt¡-óWü™¹–ÌÌÌ‚‚‚ÊÊʲ³³Yäc±8Ù=6ä™~g$%%ÉË˧¤¤¸¹¹©ªªþôÓOrrr="Övi4ZIIÉ_*(##£§§wâÄ üUQQ±¶¶¶±±qÔ#”L§ÓKKK‰¬; ±¦\^^~øðáÌÌL»wïâ9ÉÈY³fMbb¢””Ô‡´´´p‹xñz¸C˜¯®H$Þd¶}ûv744r_ÝÉŽCÞ|z{{WæááimmÅŸ)в²rvvö©S§bcc™·effnÞ¼yÀ±;vì˜9sfvv6.Á0¾Ÿ?ÎÇÇרØH¥R988fΜÙÐÐÐ××ÇÉÉI£ÑÞ¿?cÆ æ ÙÁÁÁÇLJø‡Ôà_Á7m –‘‘IMMõõõ%–iÒÓÓqBÕ… ôôôBVVVwïÞÅÑŽ¼¼<"X8B5...))ÉÝݹ¼ººZJJÊÙÙyݺu%%%¸ðâÅ‹¡×¯_1Ç̨TjOO¸¸8Bˆ9- ïãNJJ"7 &MšD 9|||aaaØo{ýúuSS“ššÚ³gÏðÚ.FkiiùI©ªª–——ãÆ‹/ÊÈÈÁK„¾¾~rrr{{;ƒÁ8{ö,îCmmí„„„ЧOŸnÞ¼ù?¾?™ìàà°zõjKKK^^^§0ÜÉ&&&ö÷÷www'%%ééé y¦ß¥Ý[ZZR(”ððp„Ж-[._¾œ‘‘M%00——G²G®]»¢££q&߬Y³,,,ÜÝÝqîDWWWdd$‘_ø-ŒDrkkëöíÛûúú–/_Î\.%%U[[‹'3---ÂÂÂÌ×…B¹té–ÜÖÖÖÛÛ;Àx–.]ZXXxøðáÕ«WcŠB¡9rï†nmm%¶––)))|E;͇ký³7ŸgÏž ¾½ÈÊÊéů^½š:uªÍîÝ»‰ûã¬ÄŽ;BÆÆÆååå•••¡˜˜<Ó¨««Û¶m[jjª´´4Nž6mš’’R||<ž¥ÈÊÊþüóÏíííø@„P||¼      þúüùó/º|ÑÇŒŒŒÌÌ̬¬,???GGÇ´´4„ŽŽÎÆëêê$$$ð~ggç­[·*++“Édsss"ÌÚ•+WrppÐh4•ÔÔTœ¦FZQQÁÉÉÉËËK¤g±³³}úôéСCÌANN΀€ qqq111‰„Ë'L˜ðË/¿´¶¶Žèˆ‹‹KJJ.Z´HZZúìÙ³gΜٹs'Λ2eÊ©S§DEEãââüüüÚÚÚH$Rhh¨ŽŽÎ»NPPðäÉ“7nìëë"²1‹/®¨¨044D)++ãtÉmÛ¶ýúë¯3gÎ\¸p!±Zgoo¿oß¾Ù“;;»;vDFFîÛ·O[[{È“•““333khh077§P(¡Ágú½š~@@€–––———˜˜Xbbbpp°§§'ƒÁÐÕÕ½~ý:0þ,3gÎ\±bEtt4þzìØ±ƒQ©T ËÁ¬Y±b'~ðàÁ’?~üØÞÞ®  @£Ñ899 nß¾=aÂf9'NTUU-((À›cfÍšeee% @$çijjzyyá5 &$%% °B77÷²eËÎ;WZZŠK¼¼¼zzzôõõÙØØ888vïÞ-!!1òsܵkWPPPBB///±ðÍlº#¿ùÉ䬬¬ÁSAmmmooï®®® &ܺu+>>žƒƒƒ ghŒ„‰'?~ÜÎή··wÁ‚¤Ñhëׯ÷÷÷—8xð ¡¡¡¦¦&…B‰ŒŒtssûÏþ#,,ŒM¢§§gË–-µµµ$I\\üÊ•+ììì¡ŠŠŠ3f+!ÿ.ضz¸…ŽêîêD]¾’ÄbÍîÑ£Gïß¿á¢ÞÁÏÏîܹo”,((øßÿþ÷‹¶u÷÷÷kkk>|§0Žgð*3GggçÒ¥Kûí7¬sJJJ||üà¶#9Y OOOÝü.»Ï¢FNnnîùóçcbb¾ã{Y}}½½½}ffæ€Ì„Ðþýû§OŸ¾~ýúñ£­···žžÞ—¦ñ|)ÅÅÅbbb¬Seèt:N¯¬¬dÞH:xð¾býÛ7ÑQÇÜ·Îܽ{wþüùšššãßwD}øðÁØØX__ñâÅ–––Xgkkë={öìÙ³ç;;Y`ÔÑÑÑÑÒÒùcÃÿÔÖÖFDD öBžžžÄšÃx€N§ËÈÈ€ïÀ¿òws&_š¥÷ÿÚ»ï¸&’þqàCG)‚zz'¢'‚)ÒK(!1”& Xh‚HñÑSDôT<¾ ö³!@)žâQE)@ŠÂ#ÅJçÏéÅä÷Ç|ŸýåKÏçü¼ÿà&›ÙÉîìÎggf74mЯz|Íf̘ALÞ'\»vís¾,q(ø|U}oãA__¨·&Nœèììüõ•——wøG%ÀW~ó@ø |»‘Í}tuu§rŒ_Îà[6†õêëÌ øÚÃÇ .ŒS?N9ƒoþ|GGGâ¾!‡ôôtî×.%%ÕÙÙùõï†üüüììlüº´´ÔÔÔªæxÀõJCCCSS“õé9………fffŠŠŠ ^^^Üü~úÀÀÀÔÕÕUUUµ´´BBBúúúƪœ===’’’mmmDÊÔ©S›šš¾L ÛÇÎήªª !dmmͺŠ1ôñãGöæÍ›Ñ}üçŸVúéÓ§ïÝ»!”žžþý÷ßãD ¼dEENŸ1cÆ çÃÃÃUUUUUU80üFàþ|˜žž®¥¥¥ªªêêêÚÕÕ5TâÀÀ€¬¬ìÔ©S‡Ú³æææ¡ÎÎÎÉ“'ß´¬¬ /ÐÜܼzõê¹sç*));w!”2Š-9uêÔñhvîÜi``àââÒÓÓceeejjzøðáÑín.‘OîÓAôš£8"¸,UHHÈ‚ $%%óóó‡ÚSܯôèÑ£AAAŸ\Œce4{öl\ ===‰ôèèè ÈËËôôô@ká#:rä//oYYY\\œ¯¯ï‡¸ü`llliiiYYN·²²Â'»½{÷êééýóvC~~~NNâœ8qªæ8‰-))9þü–-[B555¾¾¾•••ååå’’’Ë–-ëïï>__ߢ¢¢ŒŒŒ²²²¼¼< ‰ŽŽŽF D%''O˜0áó³ÍËËVPPÛ`qP ßš5k:4º +*****JJJ&L˜`kk‹ÓMLLˆtœ2eÊ”½{÷†‡‡³~üþýûW¯^}ðàAAAÁÍ›7Y7#ûFàò|ØÑÑáããséÒ¥²²2QQQ*qLäåå]¿~=—Wæ&L¨øUUUœèâ⢦¦öìÙ³²²2†²µµMIIu8>æ­ÃÇÏŸ?Ÿ——]\\ÌÃÃs÷î]??¿ñ+Ø'÷){ÁX_ÿ½¥B™™™ÝºuKNNî‹@8VΡàJøë¯¿â”¬¬¬ˆˆˆ¤¤¤êê길8~~~þÁáã‹/æÏŸ_SSƒ/‰ð%WSS“£££‰DŠŒŒD%&&º»»#„äää444ÒÒÒF´>>>GGG{{ûãÇãË;|9•™™illljjJ"‘nß¾/§~þùg///:~óæÍAùœ:uŠJ¥Óh´'Ož „V®\™””„ßMMMµ´´t!µzõjüúÞ½{¸³¡¦¦ÆÌÌÌÔÔÔÐÐðàÁƒø­E‹™˜˜H¤øøx¼|uu5F322Ú°aƒ™™Ù½{÷B---ÎÎÎ ÅÐÐpPtøêÕ« .ÄÇÇ›››Ÿ9s¦ººÚÇÇ·èT*ÕÇÇGGG‡J¥VWW;;;kkkÛÚÚâk»¾¾¾   …‚×WlÜSSS“””Äýyöööfff!={ö´··§¦¦óñÚÚÚ¤¤¤'N|÷Ýw¸UÞ´iÓäɓǻؽ½½k×®544$“É+V¬@µ¶¶ZZZ’Éd}}}¢‡àÇÎÎÎúúú666~~~¸£‚ûˆ²°°èîîÆ‡ÕáÇŒŒÔÕÕïß¿l`` ¯¯ÿìÙ3üÙ˜˜*•J&“mlljkkøâÅ‹666Ä¿999 .TSSÛ½{7±jkkk‰dllœ™™‰;ÉfÏž=¨›$??ßÄÄÄßßåÊ•………d2ÙÄĤ¥¥!dee•ðÉ xÉÉÉrrrŠŠŠC-0}út---aaaÖÄÄÄDQQÑ &¬X±"11q˜À~>ìéé166Ƨ¬hii}øð!##CEE—ÄÍÍ çÉ1‘——×ÔÔTBBbÐJ÷íÛ§­­maa1|d™ŸŸßÜÜÀÇÇÇÏÏ?kÖ,„ÏÒ¥KãââØ»¾<==—-[¦¦¦æááñøñã%K–¨©©Ë?~×–äääOnp.·†µµuoo¯••UHHÈÖ­[ËÊÊÌÍÍïß¿?TÿÜ' ÉMÁíÓá vêÔ)Ö×ódo³8#*BÈÏÏï§Ÿ~B½}ûVMMíñãÇ!]]Ý™3gúøï¿ÿ®««kff6|Ï%{3Ç Ž•3))‰B¡ôõõ1™L[[[|nªƒÓÏÏOFF!4kÖ,ÿ+Œ~'ÉÊʆ††º¹¹íÚµ+..îÎ;!:~ùòe„Пþ‰ª¯¯'žx>kÖ¬†††Q¬KSSóôéÓ¬)aaa‘‘‘êêê ƒè'Ÿ;wn``àû÷ï õôô¦M›F,oggçåå…*))ñ÷÷ÏÊÊòôô çõ³gÏ®]»ö“ŸpáÂ’%K6lØ€[h„ŠŠJJJ ??ÿû÷ï)ÊÂ… %%%===7oÞlaaQVVF¡Pðgq¢‘‘>Åhiiéèèà·ddd\]]ÛÚÚvíÚ…*--%ÖøïÿûèÑ£JJJÛ¶m³±±ÉÈÈ’’rrrJHHpvv>r䈈ˆÞòAAA'Nœð÷÷‡:ÍÜÜ\ „ÐÓ§O½½½ÿÿ!Áϯ¡¡ñäÉ“AW¬ÊÊÊfÍšÅZÁ¾Œ¼¼¼ööv|A‚k ¸¸xLLŒ¨¨èÇ333i4ÚÁƒøá‡‹/¶µµ‘Éd‡ÕÀA$$$òòònݺeoozêÔ©ðððÓ§O?|ø0111%%EHH(==ÝÏϸ$#.½X‡½êêêÒÓÓ{{{uttçλnݺ5kÖ¬^½ºººzÉ’%>áøÝ«ªª¢¢¢dddº»»+++{zzxyyB"""RRROž<ÑÒÒ">ÒÞÞN"‘å#//O\é rùòeGGGâ߇ª©©Mš4ÉÃÃÃÉÉi¨RWW§««Kœâ؇#Y7ûùPXXøüùóÖÖÖRRR>>>QQQâââuuu¬‹5662™Lމ<<<ÛòÔÔÔœœaaaÖ’÷ôôhiiñð𘙙 UUUÍ™3gݺuååå³fÍÚ·oî²ÒÑÑ9w¯ï œKKKoß¾=qâÄ… îÝ»7))‰Édjjjº¸¸Ì;¼¼§OŸÚÙÙYXX „–/_^]]ÍÞ‘&&&ÆåÖˆŸ;wî­[·BFFF§OŸ¾zõê0‡É' ‰ýdÁ\]]‰×ql³Øˆ• !´ÿ~vóæÍ‹/úøø,X°€ãÚ[[[7nܘ‘‘!##sìØ1ö.üaš9VµNû IDATÂ;w6mÚ4hyGGÇ­[·r¬œ666yyyÁÁÁÓ¦M›8q¢‡‡^àØ±cgΜ™={v`` N¬ªªª¯¯§R©ÝÝÝöööìkÿ¨ðqäää888¤¤¤ˆ‹‹wvvݸqƒè´<“ÉÝŠØ?hdd´yófkkk …¢¬¬LôØãÖNCC£  Ÿ¼°gÏžyyyuttðóó?}ú!D&“·oß^QQÏ¡K–,ùd1ôôô¶oߎÃSÜ>ÔÖÖ ¾{÷îåË—òòò/_¾Ä«Æ“TB]]]< Ãýü/^¼ ïaà "8€®¯¯—’’¯_¿~;M™L&&zzzˆÑ(0ŒåË—3Œ·oßFGGãn¤QTK&“9êÊÌ Ž1¢¢bee¥¿¿¿‘‘Ñ¢E‹pbXXXaa!_ccãÓ§Oi4Z^^îûŸ4i®Š£®!{{{\ëøùùñJµ´´pïBZZZMM íe2™ƒƒÑÒÒÂdÛÛÛóññMœ8QYY¹¦¦fúôéååå+W®ÄQÝ‚ ‡šø«  €;'„……çÎëîîN¥R/^üÃ?à¦M›ÖØØÈ>Љ‰3ü>©¶¶¶¸¸øÊ•+ø_'OžHJJVVVÚÙÙIII—‚#:S±oö…eeeƒƒƒ/^ª®®ÎÍisøê—““cgg7qâDܺã¡aaáÒÒÒY³f½}ûvݺuaaaÁÁÁ>¼uë–®®î™3g\\\º­ÁOÛºuëÖ­[¿XÁ8¶YƒŽˆ¹s玴TÂÂÂQQQ¸'žu*á EEEêêêørqqf.#{3G P(ÜP¬•sÿþý ¥»»›¸¬òööÞ¹s§  `rròÊ•+‹ŠŠ¦L™200PUU•’’ÒÞÞ¾dÉ™a®ÞÁ?!|ìïﯬ¬”ÀãGÍœ9³®®Ç=õõõÄÅÓˆã(аk×®êêêÜÜ\///ggçuëÖáòcm€™L¦““Óõë×UUU»»»g̘Ó×­[wöìYaaaWW×A½åüüüÄ1@ÜA§Ó544îÞ½{úô騨¨‹/þôÓOÆÆÆ¸OžJ¥öôô :­ã “ÉLHH4ìõIBBBøñY>>>>žý^¹üñùóç áÄW¯^M™2ÅÁÁa×®]x¥ýõ—¼¼<.Oyy9BH\\\FFO‘)++É¢¢¢zzzaaa¸]|ýúõ {{ÅÅÅYo³åN?rä¾C¶­­íùóçP¡¹dccC§Óñ=7n¼zõ*ž•Ûßß,""‚{²‡2{ölkkk|{AWWWDDÄ»wïÆ°„ åÌ™3¸Âœ9sÆÀÀ@HHè?þ`2™t:}Ïž=}}}­­­ýõ—ŒŒŒ  `ww71_ÓÈÈ(&&Çx4müj`LL žòØßßÏ:ï‚è>ñâÅPSQQÁ~UUU?ÖÖÖÅ]_ïíêêjiiÑÓÓÛ²e‹¶¶vEEш:Dþl8ÆŽ #&&†uœ÷Å‹ør´®®îöíÛjjjÃÔ¥k×®µ··wuuÅÅűÎõdßχ©©©ÙÙÙùùùwïÞÅõpÑ¢Eåååø«;wçÉ1‘#2™œ––†O_ÄÜÇææf¼‹;::®]»†¿‘‰‰IWW¾+<--MVVÇ[ÕÕÕƒ6æ¨%&&²ï111î·ÆPš››9N·àÒ¶mÛØ F¥R‡Ú§ŸY0ŽmÖç—ª¡¡aëÖ­ÉÉÉ ¡¡¡Ce«­­ýäÉ“÷ïß³V „Ptt4¿"°7s*•Ê^¶mÛ¶ U9ûûûÝÜÜ‚ƒƒƒ‚‚ÜÜÜð…+B(;;»©© O–°³³ËÌÌd0yyycU÷ÀWÚû˜–––••uçÎ &º¹¹¥¤¤œ>}: @GG‡——wõêÕ6lظqãúõëçÏŸ/$$tøða|ýÁåË—  hii%''ãij¬ŽOŸ>9räq¡O£ÑÞ¿èÐ!Ön!AAÁ   kkkYYÙ9sæðññáô‰'.^¼¸­­½iîܹK–,‘’’"®–~ÿý÷+W®àC„ÐŽ;BBBbbbDDDˆ±ãS§Nýë_ÿ:tèŠŠŠššF9{öìöíÛñåõäÉ“Må¤Óé/^466¶³³322ârùùùõôô˜ššòððìÚµëKÞj÷ß.((ÈÐÐÐÏÏoΜ9±±±»wïÞ´i“É411ùí·ß†¿@G;vìàÁƒ4­¿¿„ ÖÖÖDÇÕ˜øå—_¶mÛ¦©©Éd2Nž<‰õÀÀ@&“É`0\\\~üñG777ww÷5kÖðññÓž¶nݺ~ýz===iii}}ý‘Ö@öoC!‘H!!!«V­Â]‰+W®4¨gaa‘••Å: <ÈéÓ§ýüüŽ?ÎÏÏòäI|$†……999Í™3‡c+ÒÑÑáââÒÙÙÉÃÃ#//ª§OŸÎœ9“8TGêîÝ»'Nd}ªÃÍ›7Ïž=‹{=ñ”n„PSSÓÂ… {zzººº”””Ö¯_¿~ýz###;;;üÙU«V‘ÉäA™³nöóaCCC@@Àõë×%%%£¢¢lll”••gΜyüøqGGÇÞÞ^MMM|ƒ˜˜{"BˆF£Õ××üøQIIIGGçÂ… 4íÑ£GË–-ûᇈSnEEE@@@OOFÛ±cBHXXøäÉ“¸iŸ3ç©S§þñÇ#ºcëãÇFFF‘‘‘ÚÚÚcøuº»»ñ¸ÏË—/­¬¬=z4&Ï@K½úš³¦Ï!$ ÐÙÙ¹téÒ_~ùelk8÷Þ½{giiyçÎbàlœøûû“Éä¯sÀë‹m„±ÒØØèä䔕•5Ìàø×`ÿþýÊÊʬsÜ¡`#ÒÓÓcnnž™™ù•ïh𙊋‹çÌ™3|Â`0 FEEÅ03 %$$p¬ØX_sêÄño÷öøÌÌL:>æ-kNNÎþýûyxx˜Lfdd$ÄŽà kmmÅêééY¹råß;"„&Ož¼k×®úúzÖ[ƃÁPTTüj'K}™0†êêê>üõ‡Û·o‡‚}aaaâBŒÔ?'|äæ—BXÑh4<1qÌÑét<ÔÀßbÆŒÄ4ö¿~õ¸âåå%ž òuúa éëëÃAøÄ‰6€ð@øþn#›ûèêê:N応Á·l ëÕ×™ðµ‡.\§6~œrßxì8VõêëÌ ñsägøˆ¿çÕë“ðÀ7k ëÕ×™0”âââñÈæ>„ÂGá#€ðqÔ¢££,X //o``ÐÓÓÃå§ÚÚÚ¾ÿþû-[¶Œbééé¡£GqÿÁk×®½zõ ¿égǵµuvvöP_jxááá{÷͑¼¼¼²²²†††¦¦&ëÓs ÍÌ̼¼¼¸ùýtyyyCCC&“‰ÿURRª¬¬D 8p@]]]UUUKK+$$¤¯¯oE}ùò%F[°`•J}þüùP‹uww»»»«ªªjjj¦¤¤ “4{öl%%%%%%OOO¨ ¾Þð1+++"""))©ºº:..ŽŸŸÛGÅÇÇkii]¿~½··wÔk···QKyíڵׯ_î³à¿BlllIIÉùóç·lÙÒØØˆª©©qppðõõ­¬¬,//—””\¶lYÿ'³úðáCBB D__ߢ¢¢ŒŒŒ²²²¼¼< ‰ŽŽŽQ”sÓ¦M«W¯~üø±‡‡‡¯¯ïP‹9r„——·¬¬,..Î××÷ÇC%"„******~ýõW¨ þ†ðñÅ‹óçϯ©©A…‡‡»¸¸ „ššš H$Rdd$BèèÑ£~~~222¡Y³fq>^¹rÅßßÁ‚¿ÿþ;N wvvöððprrrqqÁ¢µµõæÍ›===­¬¬BCCÙÃAÜRöööêëëâßü¸wïÞ¢E‹LLLH$R||~üXOO¯°°°¯¯/((ˆB¡mذ¡§§§¬¬LGG‡X’L&?xðà›ª÷jjj’’’MMM¡ˆˆ{{{333„€€Àž={ÚÛÛSSS?™ÉŽ;öíÛÇhÖÖÖ&%%8qâ»ï¾CM˜0aÓ¦M“'OiñZZZŠ‹‹W­Z…Z¾|yEEESSSRR…Béëëc2™¶¶¶gΜA%&&º»»#„äää444ÒÒÒ†JäèÔ©ST*ÕØØ˜F£=yòNˆÆ7|”•• ussËÉɉ‹‹;zô(BÈÃÃCWW÷Áƒ÷ïßwttDUUUÕ××S©Tƒˆˆ.3¯¨¨hmm%“É«V­º|ù2‘^UUuìØ±K—.ÍŸ??,, 'öôôüúë¯×¯_/--ªÕ?tèP]]]NNν{÷þçþ!¤¢¢’’’’““óûï¿ïß¿ÿ¯¿þ²²²ÒÔÔ ½uë–žžñÙ_~ù!tÿþýŒŒŒøøx¢1îëë;}úôï¿ÿžœœüòåKÖÕ=|ø0111%%%;;ÛÓÓÓÏϧ¿|ù222òêÕ«Ó¦M»víÇbÈõë×ssssrr})OOO;wîdeeݼy³°°ýûfff®_¿þòåË:::G޹sçî ;qKªêäÉ“srrB=êëë300ø¦ê}nn®„„„ŠŠ BèéÓ§ºººÄ[üüüÜÄR::: ÑÑÑDJYYÙ¬Y³¦M›ö™Å«¯¯Ÿ>}º   Bˆï‡~hhh°±±QSS >|øðĉ=<<ð’Ä/ Ìš5«¡¡a¨D„бcÇTUU-,,òóóqŠ]VVVnnnXX˜¿¿?œpƒÿs>lkk›““ãàà’’"..ÞÙÙYTTtãÆ üî”)SBUUU)))íííK–,‘‘‘±´´üdΗ/_^µj//ïÒ¥K·lÙÒÐÐ0sæL„•JB™››ãæ!´dÉ„//¯™™Yvv6îF$##ãçŸÆí1.X{{{@@@mm­  à»wï^¾|©¥¥Å±0ÙÙÙàáá³··ÏÎΦÓé!†×+''WSS3wî\â#iii555¶¶¶!&“IŒš˜˜à2(((àŽÛ¡Š±bÅ >>>>>>;;;Ö/ÕÕÕõàÁƒ=wtt¼xñ‚µ+!”žžž––výúuǤ¦¦2™Ì{÷îáP[UUÇ çÎ3119sæ ±%¿Ë—/g0oß¾ŽŽÆ;hÔ¹ÛØØ¬^½ÿËd2?'·¡yîß¿ŸB¡tww³OꋉÞÞÞ;wîLNN^¹reQQÑ”)Sž={æååÕÑÑÁÏÏÿôéS8!÷𱿿¿²²RBB¢¥¥e¨e¤¥¥­­­…„„„„„h4Ziié'ÃÇþþþøøx¸¸8„P___LLÌÖ­[ñ[Ä2<<<ÄköÄOúé§ŸŒñ •Jæž&“Éš-ñZ@@¿àåå`ýƒÁ°²² ”ûG¸)ëÚ “ÉLHHÀ¡GóæÍ++++//§R©ø#xðšu ‹²²²»wï>|øÛ©ññññ***IIIÞÞÞÚÚÚßÿ½²²rAA ^``` ¤¤„ËTTT$“É'OžÄÿª©©ÕÕÕ½yóæ3; ¥¥¥[ZZúúúš››ñåSkk+¾ùðáäI“B3gά««“’’BÕ××ãnTމ3fÌÀ™[ZZîÛ·¯ªªÊÀÀÀÉÉéúõ몪ªÝÝÝÄÀð>ë֙ݻw+**&''ãBb6^kk+BÈÎÎ.33“Á`tvvæåå)++2Û´´4™ŠŠŠ²²²²²²7nÄÄÄàN”ÔÔÔ?ÿü!M&“ñò±±±?~ìîîŽ'¡Óé'OžÄwáà‚ýõ×_òòò¡çÏŸ———ãÅÄÅÅÛÚÚ}ÖÔÔ4**ŠÉd¶··_»vm¨U Z]LL žòØßß_ZZ:Ô’‹Š‹‹Ã_*!!u¢¢¢zzzaaaxƒ¼~ýšý6á9sæ$&&nß¾O¥ÓéGŽéììDµµµáÛxùùùW®\icc#""ò­Õ{:ŽÚ¸qãÕ«Wñœ„þþþàà`Ž}ØíرãÔ©S]]]¡Ù³g[[[ûøø¼yó!ÔÕÕñîÝ»‘oúôéêêêW®\Áñ®’’ÒŒ3úûûÝÜÜ‚ƒƒƒ‚‚ÜÜÜðU“͹sç˜LæóçÏKJJ/^¦¥¥eee………ÉÉɺ¹¹ œ>}º  @GGGOO÷zxxhhh˜˜˜Ðh4¢gW®\±³³#þÕÐÐÈËËC‘ÉdOOO==½ÖÖV܉RVV¶°°044¤P(xX™Ý¦M›¤¥¥ŒŒôõõñwìØ±wïÞuëÖá¹€x1GGÇãÕa[¶láããÓÕÕ¥R©Ë—/ÇñðH$RHHȪU«tuuI$Ç¡F"ø`/îÖÂ_ÊÄÄdЗ:{ölmm­®®®ŽŽŽ··7\™5kÖo¿ý¶wïÞ„„???uuuSSS]]Ý¥K—âAs„““SssóÚµk¿ÍªtõêÕÆÆÆ9sæÄÆÆFDD((((++¿}ûö·ß~#ú‰?IZZÚÖÖ–¸ê8v옺º:FSRR222jooEñ"""®\¹¢¬¬|æÌ™#GŽ „BCCåååíííæÍ›‡ï©Ú¸qãÇçÏŸoooøðaÜ%É1qÏž=òòòJJJ»wïŽŠŠš6mš  `PPŽw›››ùøøà„€<›}½Ã#Otwu"„®^‹fÌ®   ¹¹™ËA½‘¸páÂ'sïééÙ¹s'k¢µµõ¦M›¸éƒ$%%]¹råÜíÄe½úïÍ ^qqñœ9s&L˜0Ì2 ƒÁ`TTT°ÞHÊÞxáX±±¾æÔ‰ãü°e¿MöööÏŸ?ÇãÜûo Øûí7Ø‹£€0Rð›×ÂGá#øÛlî#þµèñ0~9ƒoÙÖ«¯3+àk/\¸0Nmü8å ¾ñØq¬êÕ×™0„ÂÇÑyñâÅÒ¥Kõõõµ´´öìÙÃd2¹ù”¼¼¼²²²ººúüùó‰û†ÒÓÓ¹_»””TggçÞ¦ùùùÙÙÙ£(ä(JÛÔÔtñâE¨Ç\ÂõJCCCSS“õé9………fffŠŠŠ ^^^oß¾å&+CCC¢>+))UVV"„8 ®®®ªªª¥¥Ò××7º¢*))}üøÿ{åÊIIÉ“'O"„ªªªŒ)Ê;w¸Ï0**JRR2** ÿËd2,X0{öì1©Ã¬>|ø`jjÚÛÛËþVii©©©é'sxùò%F[°`•J}þüùP‹uww»»»«ªªjjj¦¤¤àÄ   Ù³g+)))))yzzâÄM›6effŽS¥ºvíÚ«W¯¸\øèÑ£AAAÜoŠñ3uêÔ¯s]÷,GéééZZZªªª®®®]]]Ã$Ž—ÍMxx¸ªªªªªêFZ«¹¬êP:>¢¯ÃåºÒÓÓ¿ÿþ{|ihhé ENNnÁ‚EEEК€qwíÚE£Ñ>|x÷îÝ«W¯>|øËÆÆÆ––––••Ñét++«²²2„ÐÞ½{õôô¾òmšŸŸŸ““Þ>V'k"¤Àáã¥K— s/66¶¤¤äüùó[¶lillDÕÔÔ888øúúVVV–——KJJ.[¶¬¿¿Ÿ›8)!!aP¢¯¯oQQQFFFYYY^^ž„„DGGÇèŠ:mÚ4"†‹]°`~}ãÆ KKË;wîP(”e¨¦¦ƒ_ß»wORRr¤uø“!tüøq!!¡Qï£M›6­^½úñãǾ¾¾C-väÈ^^Þ²²²¸¸8__ß>àô€€€ŠŠŠŠŠŠ_ý§øùùíÙ³güÂÇׯ_r³|þÁþ·ûb…jÏÒÑÑáããséÒ¥²²2QQÑÇ•8~îß¿õêÕܼys˜£†c­æ²ª î×ebb‚ ’’œòöíÛÕ«W>þ<77÷Ç„¦Œ>||ñâÅüùókjjðå—‹‹ Žf H$Rdd$Bˆ‡‡_ÿõôô „¾ûî»­…ÏÑÑÑÞÞþøñã¡;wæçç#„233MMMI$ÒíÛ·ñîÏ?ÿìååE§ÓoÞ¼9(ŸS§NQ©TcccöäÉ„ÐÊ•+“’’𻩩©–––ƒ>rñâE‰dhhH¥RqwTVV–‰‰ ‰D²´´|ñâþâîîîÞÞÞÝÝݯ^½ºpáB||¼¹¹ù™3gpÁÂÃÃ]]]Ï;÷êÕ+kkk‰dll|ÈÈÈPQQÁÇ…››[bb"BˆcâP×HT*ÕÇÇGGG‡J¥VWW;;;kkkÛÚÚrßg™˜˜èàà **:a„+VàÕùùùýôÓOø<¬¦¦öøñc޵šcâPõ“ýPذaƒžžž±±ñ³gÏFqXqlÄ9ºpá…B¡R©!qqñ©S§BðøGýIYYÙÐÐP77·]»vÅÅÅáq4:~ùòe„Пþ‰Ú¿¿ƒƒÃŋ߿"''7Šuijjž>}š5%,,,22R]]Á`‡úܹsß¿ohh¨§§7mÚ4by;;;///„PII‰¿¿VV–§§gXXnçΞ=»víZÖüóòò"""ÒÒÒ¦M›ÖÑÑ! ÐÚÚêéé™’’2o޼˗/¯]»Ÿ^_¾|™‘‘!((¸aÆk×®¹¸¸¸ºº¶µµíÚµ‹ÈmæÌ™¡… ®Y³fõêÕÕÕÕK–,yøð!k!±¶¶¶7&%%MŸ>½¹¹yÑ¢E¸y®ªªŠŠŠ’‘‘a]844tûöí·nÝÂaÚÚÚ»wï»téÒ²eËDDDðóòò„„„<öóÏ?9rDDDï²   'Nqç7"77WBBBEE!ôôéSooïÿHðókhhÍ`0ttt­¬¬.]ºäíí[Öüü|b³´¶¶êë볟1yøðabbbJJŠPzzºŸŸ¾¬}úôivv¶°°ð åÙO8CÕŸÒÒÒÛ·oOœ8qáÂ…{÷îMJJb2™ššš...sçÎE‰ŠŠ¦¦¦ÖÖÖÒh4===!!¡OžyNž<ɱj555edd´¶¶jii­[·îÎ;ÿþ÷¿ííí‰Ç㋈ˆäåå=}úÔÎÎÎÂÂ1ÕÕÕìybbbì{VXXøüùóÖÖÖRRR>>>QQQâââuuu¬‹5662™Lމ<<<7Ñ¿ÿýï£G*))mÛ¶ÍÆÆ&##CJJÊÉÉ)!!ÁÙÙ™XìÎ;›6môYGGÇ­[·ÖÕÕéêê«Ã»xÿþý4íæÍ›/^ôññÁ£½ìµš———=qÆŒìåäx(•——:tèèÑ£¿þúë/¿üræÌ™‘V:::ì8®“jjj“&MÂý¸ˆŠŠZZZþñÇúúú{÷îƒø ÂÇѳµµÍÉÉqppHIIïìì,**ºqã~·7.\°°°Ø¾}{KKËâÅ‹ÕÕÕ‰ƒ{ì3&ŒŒ6oÞlmmM¡P”••q"î@’ÐÐÐ(((À')ìÙ³g^^^üüüOŸ>E‘ÉäíÛ·WTT UUU-Y²„5ÿŒŒŒ+VàVPTT!T\\¬¬¬ŒûoV¯^ðþý{ÜÏI|ÇnéÒ¥xT¥¼¼|åÊ•ø^°`Aaa¡¹¹ù … [ZZðÅ7BHXX·‹ ƒšêAÄÅÅÍÍÍcccÝÝÝ£¢¢ˆqU*•ŠGÍÍÍq»›ššÊd2ñɨ§§GUUõÛ©ñË—/g0oß¾ŽŽÆm3—óq9 ¶±±Y½z5QQ?'·ÁC¼¼VVV‰‰‰×¯_OKKÃáã  ìåË—¸žãÙW8ÝÊÊŠL&uÌ’Éä9sæ,]º”Ÿÿ==½íÛ·ãë.öOݺuëÚµk £³³“Ž9VȦ¦&bEEÅÊÊJ##£E‹±.&&&†§£pìïß¿ŸB¡twws ˆż½½wîÜ)((˜œœ¼råÊ¢¢"|"š6m_²ËÈÈøùçŸñŒ—ÏÎζ±±ÁǾ›››ŸŸ^’F£á]#''WSSƒã0VÄfêŒ1HZZZMM­­-þDp@¥RÙcG.O8ØâÅ‹ÅÅÅq_»‚‚ÎMII‰(6®·³gÏÖÖÖ.((þä™g¨ªekk‹ƒ¡iÓ¦áQYYùÝ»w===x½ø¼7þüöövœ?¢ ++¼xñâÐÐPuuõO¶ÜÚx†¯¯—’’¯ÍF P(ÜTWbuÂÂÂQQQd2ÙÄÄ„˜€û9¥åx()))áC^WWŸíGqX jÄñ…Ö“'O$%%+++íì줤¤(ÊÀÀ@NNNzzº¤¤¤——מ={<ñ„£×ßß_YY)!!ÑÒÒ2Ô2gÏžÍÊÊBMŸ>D"=xð`ácqq1>È »víª®®ÎÍÍõòòrvv^·n.Q0ÖËM&“éäätýúuUUÕîînâònݺugÏžvuu%šÒaŽ·A—°ø_¢±jvã„ 8ž8^3 Ü¡HøóÏ?q&Ãóôôtvv–’’š3gn·8nƒ¯¿Á¯¢¢’””äíí­­­ýý÷ß+++à~h<$TRRÂå ***’ÉdbèPMM­®®îÍ›7cÕ¹zõj:N"‘8Ž€ªQÄ¿3fÌàØ‡¯1444vïÞÍZÁètº††ÆÝ»wOŸ>5èf¬òòòÈÈȬ¬,IIÉÌÌL<)…¨ÕìU˜ !%%•ŸŸŸ››{÷îÝÝ»wß¿Ÿ5ðe?(**&&&JKK·´´ôõõ  477Ïœ9!ÔÚÚŠC«>Lš4 wê×ÕÕá&¿¾¾gH|qKKË}ûöUUUáþ˜ÞÞ^nŽ ¡Žwâõ'wb-C1Øw+++Ö1åa6/Çðó󻾯¯8•ÓOùøøˆH”c±yxx¸9ó Uµ†Z1]’uœhkk‹ï6cUPP &&ÆqÏ"„žøã?˜L&Nß³gO__>!ÇBœùôéÓÕÕÕña¯¤¤4cÆŒþþ~77·ààà   777|EdccsîÜ9&“ùüùó’’’Å‹ã# ¯";;»©©‰˜-S]]‡)š››Y'–ÇûÉ“'ñ,C\NSSÓ„„„ööv&“yþüù¡zs‡9Þ¹aÖÖÖâ&7gžá«Öˆ$&&²×<$ÊqϦ¦¦fggçççß½{­‹-*//¯¨¨@;w_rLÄ=ÍÍÍ£+*•Je/ê¶mÛpQ¯]»ÖÞÞÞÕÕ‡W×ÐаuëÖääd…ÐÐСj5ÇD|¢ÆCC„a¥AM̈+öF!ôâÅ ||ÕÕÕݾ}[MM ‡Œ<À‡Czz:1â |´´´¬¬¬°°099¹ÀÀ@77·Ó§OèèèèééÅÅÅ!„Ž;vãÆ ---*•jggÇý³–/_®¢¢¢ªªš‘‘‘œœŒ§©8€§ '&&nÞ¼™¸§Ñhööö‡bíþ Âízss3NŸ8qââÅ‹ÙûŠH$’ŸŸŸ¥¥¥žžžµµuGGÇÔ©Sýõ×uëÖééé]»v OÞçˆN§—””9rdÐ[§OŸNHHÐÓÓ[»víÉ“'9öQIJJÆÆÆ>|XWWWKKëèѣÇóæÍ300pssÃ)NNNL&“5ú!“Éžžžzzz­­­[·nEùùù©««›ššêêê.]ºtø!°ª   «W¯666Ι3'666""BAAAYYùíÛ·¿ýöÑÇóIÒÒÒ¶¶¶DqìØ1uuu¦¤¤dddÔÞÞŽ@GmÍš5ܬO:I&“Ïœ9£¦¦†‡ŸÒÓÓ#""†é14Ó÷÷ß'‘HFFFëÖ­ T‡ gÏžmggçááñÉ^U111mmm|[uuõâÅ‹I$’‰‰‰‹‹ ÷wkFDD\¹rEYYùÌ™3ø •——···wpp˜7on’7nÜøñãÇùóçÛÛÛ>|g{öìÁÏ<Ú½{wTT.ðÀÀ@aa!w~õêaµiÓ&iii###}}}|Œ,\¸pÅŠT*UWW—Édâ;!8rttÒŸøÖ¬YóU•ÇÁÁª Œ!øÍká#€ðŒÈxL‹ÙÜGâ×`ÇÜøå ¾ecX¯¾Î¬€/odáã… Æ©§œÁ7;ŽU½ú:³†Gü üß>"„Æã¹ã3ø–a½ú:³†’““óêÕ+â§M‡y1¾á#ø¯ **j``À`0p¤ˆƒE&“É`0ðküBhЯeBø>²†’L&“—wd÷RÃ×ÂG0>`ðàîÆ7nÜ ¬ñ_ ‹¥K—Ž"·qï}¬ªªZºt©žž‰DÊÉÉáòSòòòÊÊÊêêêóçÏwtt,..Æééééܯ]JJª³³st%ß¹s§‹‹Kii©©©éWU >ç{m&ÿ]p½ÒÐÐÐÔÔd}zNaa¡™™™¢¢¢‚‚‚——7¿Ÿ.//ohhHܰ¦¤¤TYY‰8pà€ºººªªª––VHHH__ß(в`ÁIIÉüü|öw»»»ÝÝÝUUU555SRRà´`xVVV–––¬)£ËmÜÃǵk×:99åççGGG¯_¿¾§§‡ËÆÆÆ––––••Ñét++«²²2„ÐÞ½{õôô¾ÀVþøñãùóçóòò¢££åååOœ8Á¾Àø­jùø‰-))9þü–-[B555¾¾¾•••ååå’’’Ë–-ëïïÿdV>|HHH”èëë[TT”‘‘QVV–——'!!ÑÑÑ1Šrš™™ÝºuKNNŽã»GŽáåå-++‹‹‹óõõýðáìYÜGŸ;~VøøâÅ‹ùóç×ÔÔ „ÂÃÃ]\\BMMMŽŽŽ$)22òãÇ••• .DÉÊÊNš4éÎ;#Z Ÿ£££½½ýñãÇB;wîÄ1™™™ÆÆÆ¦¦¦$éöíÛ¡©S§þüóÏ^^^t:ýæÍ›ƒò9uê•J566¦ÑhOžxðÀÅÅ%<<!dbb‚ësrr”””Š‹‹[[[ß½{'///..“}ïÞ½/^dffâÌŸ>}züøñ›7o–””$&&¦¤¤dgg{zzúùùqÜ,mmm7n‚üÌL>ëÖ[[Ûœœ‡””qqñÎÎ΢¢¢7nàw§L™‚#³   Ë—/Ï›7OOOO@@`+b$º‘‘ÑæÍ›­­­)в²2NÄH¬‘õ³gϼ¼¼:::øùùŸ>}Š"“ÉÛ·o¯¨¨ªªªZ²d 7%QPP‘‘!þµ··ÇÑ-??ÿ¢E‹BZZZ8\611 ëïﯩ© ÈÎÎnll422Bñðð„……òññ566>}ú”F£!„¨Tª°°0B(--­¦¦ÆÖÖ÷¡†& [ZZp/BHXX¸¡¡aéÒ¥?ýôSkk«  `NNΑ#Gººº>^EE%))ÉÛÛ[[[ûûï¿WVV.((°±±Á ”””pù£‚ŠŠŠd2ùäÉ“ø_55µººº7oÞŒwäÌ™3ëêꤤ¤Bõõõ¬½§Àxû¬[gvïÞ­¨¨˜œœ¼eË–††bj]kk+nÛ Fdd¤„„‰Di„zéÒ¥øøx<ûðüùsyyyWW×’’œxùòe„Ðëׯ=zÄÚ»ÖßßßÓÓ#++‹Â]ƒ¾;>>OÜs&&& “ÉÓ§OoooÏÌÌ411Aýõ×_222‚‚‚ÝÝÝçØÑéô˜˜<屿¿¿´´”cþ:::¯_¿&ƾ=z„_àñkbäZTTTOO/,, wS½~ýš›;‹ÿÙlllèt:žf°qãÆ«W¯âéƒýýýÁÁÁ"""¸'›;vì8uêTWWBhöìÙÖÖÖ>>>xîDWWWDDÄ»wïÆ¤Ìýýý7nÜÀ÷qÛØØœ;wŽÉd>þ¼¤¤dñâÅp.ð_>¦¥¥eee………ÉÉɺ¹¹ œ>}º  @GGGOO/..!tûömUUU99¹û÷ï_ºt‰µSpxË—/WQQQUUÍÈÈHNNÆÓÔÐÓÓ366NLLܼyóÿ~^^fooèÐ!ÖîAAÁ   Ü®777óññáô‰'.^¼ØØØxœúŠŒëëëq£°°0ž¯æææöðáÃ5kÖlذaÁ‚ì$‘H!!!«V­ÒÕÕ%‘Høžv’’’±±±‡ÖÕÕÕÒÒÂÓOBÚÚÚ½½½oß¾%‚õ³gÏÖÖÖêêêêèèx{{ãXçtõêÕÆÆÆ9sæÄÆÆFDD((((++¿}ûö·ß~ã~–…´´´­­m[[þ÷رcêêê4MIIÉÈȨ½½]TTtÅ TRRzýúµ““îzïêêruumooÇ!ïÇçÏŸoooøðáI“&ÁðI<œŒô B<›}½Ã#Otwu"„®^‹fÌ®  €ËÞîînIIIØIÀçxûöíĉa;V¼¼¼\öM]fŸÔÛÛ;ÌT( +6Öל:q|ds) 7‹=xðÀÀÀv0ð9îÞ½«¨¨Û òêÕ+.­œœŽãœì ¸/ÀÈÂG.ïñü[î?øüíÖ„7nܰ²²]  FA‰}Õáã7nÞ¼ÉþüI¾LøÈd2¿dÉÿ9Žyó&~H8k"qo5DÀ¨qÿ¬ðGL&ÇcƒºóƯ ¸÷‘(ëÍ›7‰ßV)2ÿv-À˜Žìîƒüü$ßðqÐëa–cA þXô5úðÿ¢4ðào 1KKK ‹¯=|D™››3™Ìääd¼ø’±#k eaa£²/S€Ï ‰z¾pIc_2vƒð‘ˆ !|ø[ÂÇ/tAø8Ôb>Ÿ"0 Øàk ´FüÜGîŸ!¬ |ãäo ´F>Þ»woÌ—ÀP***`#€Ï ´ þÎðQWWöÀ7Ž6€ð@ø |>„° „`\üŸÇ†»ººÂ܆ïß¿‡- ^Ãà5„ÂGá#€ð@ø„ÂGá#ø’ŠŠŠ!|\100`Oä‡í8êëëcO„ÞGðcÖ0x >³†ÁkðiĘ5 ^€!±YÃà5û˜5 ^€!±YÃà5l˜1k¼ƒ 3f ƒ×©àÀGIDAT`°aƬ9^ÿŸðQHP¶  ^€øßÞÇÆúØà“x6ûzÃV\ú0:qSgÑIEND®B`‚ddcui-0.3.0/screenshots/ddcui_summary.png000066400000000000000000001630411427175135000205270ustar00rootroot00000000000000‰PNG  IHDRjÁ¦åÅÅsBITÛáOàtEXtSoftwareShutterc‚Ð IDATxÚìÝg\GðÙ½ÆÝÑðèMšŠ¨ˆ"JEcAcO0–؈=ÑWƒ5Æ{ïÆ®Á^"*(E@P¥÷ÞŽëe÷ý°z9iÖ˜çÿßÝìÌìÌì<ÌìîažâX¿â›QŠl¨øÅs'+2øË¯ßXœªF£uîênfaU˜Ÿ›”«Ï3ôðöÃÚ{ÝðQ³„J%r9)ªXº$G‡VS&ÉU„ŠÀ™4‚D„Š á„R¦¬$I ¸ç€ Ò’´¤ÄœR1bë± †žæu’lz+"Deé)yÅ5"¢kq í;vwÒGEÉW#óäx×ÁîÖ,D¼|kÜuˆ›·Õƒë'SIDã{ömÏÅZøi%jŸE?’;øø›rp„"Uƒ«cÄÕæÊ£#²j-x†dmñ‹'ù¥µ%ÆÔÖ7±sloÇcaˆ¨Hýûv†ã9v3•¦gUËiºÆNÝ\lPQY¾¬_™ÿJ‘q§~΢ÈÛBŒçÔÍDœ–UTðóójÇà a•3Ⱥ!ökQ¶f˜iYØ=K-‘peéb³.¦Œ:•-l¼­“æx¶S%=¯×—þ>–ô7U[§›ÿDÒ‚øD¢}?Ws†©R’t-®>›«--¸œ't¶ÒÆ"„%/ždä•$JŒ¥khÑ®];Km¼¦Þ¨êãçõ¶¹øYåßÔ8Tåt“GGˆ”•¤?z”]*Bœ6–í-ãr%¸aç/zز1¤¬Í{ü,-¿J$#pSK[Ï´ƒK{SLfÐ 8†×Ÿ¹kV)’l°ø 0QíÒ¹d3Š_:wÂ¯ß „aQwoVV–äùô¨ÅfGß»íáíW¿xýÙÇR•*eP&*¥˜’kª«¨U• I„´ ¹J’ eH¥RÊ$âZ±1ÁRªT4„4;v”dÇGçó:úôñàbâÒ씿¹$!ÉJh|+©ªxùPhâÜ®WW=.SJ„éÏcÕ2³£]™diü_±d'VjžÑ€Ñ®L²$î|Ä3ÿQÞÚdUò•˜ ®G‹Ö+ÉÚì„\C×SŽT‚üä˜gÙrDgjóÍlø†útUiJÔ#¹¹‹‹O]6”×V¥?Œ4óh/Š~¬E­“¦ÆêuóêÊc*kŠSãî]WYú:éã!š¥×`K„ˆ¢¤+ÉÜÞ_Õ&«žÅš¹û¸é)3þŽ|jeP–¡h¨rÕ‰©É×£BõhˆajmþèIZª·íaH#Çñ—Ù”¥)1-jüÃØ§ÖúE¹¦¯ÆóîM¼¾\½YÀ XMV«ÙÍg½:ð^UYI%ϼ Cв¤3…BtŽaS¾¾“9#IUyê½D‰¹sGŸîºl)«)Ï}šx·@«Õ­Û’²âZC½:ãüDÝø˜t/7½án>ëÔݶöÑý<^G¯>Ú˜¸4'%W»Ïè.ÔEY^íñOÅVí<:ò´Y8¡I„‚¢´'ÏHgˆ hÖ<â«®e³8õ»®ùÅ534VœN§# ãp8ž>þ±îzúøs8±X\S]Ù`ñú³ÿ$©”DMµ´¦R¬ÅÕª¬’HE2¥\¡Û†«P©Õr©P¡‹‘R%¯ÑQ¨”,Ђ€,6M»K?§6 D*$H׺[7޽ü¢¦¶’Ò¢Ø8‰Cw+†¹H Elm¾!ýáS ÆR±&~“ VÇ R}ÛŽã¯_C(È/$-»Ð"E±OVž_ø²1¥´¶¬¨@jèd,ˆŽT¶ïëf®…‘r±@ˆkëµ±u3à¥<ˆÉ`“H !„p}§Ú¢J¡T¥¥Í3ïÔMP#«­q ¸LŒ” "9Iˆ”¯ çè®O*$r㪢4•‹“•£ú¿¾4ÖøIyI~m+C[[,"UÛe 6’•Vñ-L¨ë«â‰–5ÞMð÷ý ‚õj ˜Ä˜,E½¾HÎîÐßµÉj5ºIÃ5ÛOâ8F$Bgiëkk‰ &›ÍDJ¦a; RR/sêÓÍ’ƒä‚Š’JÏØÄ©O;úÞ#:£nK„R).b78Îèõ5³úÝ|ð¨㺾<¥˜žu77\}J²RJùú8êc²Ú²BÉbëè·ásŸÅ×(Ú™²à3Àç[µxãõl°ø¥×—°_ÎGjdh¬¸K—nQwoRQ£OŸÃÄbqÔÝ›.]º5X¼nø(—ËÔIb‰¤ª¼R\%ÂiF%éE$AÒ™8!—ªT˜D(“V×’ NW˜R¨£-‰ßxã7àå§µ&#³éaÄ@¤¼$ñj|ž”Æïîãa˦&ËDÙyMmÍL—Ût·ä`HYõôVtš”AWZVŽ]ÍJ+ÔSq„JI4Z‘J¹\.Ã4BeYòƒGÔ£cq]·îö:4[wjª%\k.ŽRT–ÕZ»Ó”29B¸–¹"+S3”6îfZ)+Ž¿šP¨Àt½|Úëè;Úé_L)Õ¦–Ýɪ'‘‘i̬ëÀž&t}CžìQâ-yׯºYЈ’G‘‰\®žÖ« 1iN\ÄÃJÄ`ñ1†‰Ã›*o¨Sr©žèÍÍ)26´°µ63Í9H’–]ÄjcAm•ªìz¶¸ñÊü¢$º‰,ùÖ³Î}ÑbÈYo®öŸnšwïjÇVüóëWÏÔT•QeÚŽ§k×ËÛŽ$äÂê²Âüôô§iz] òÓå¶Ý-8QõâîÔj¦ÝÞ«žY«Ô;nI]5G•Ç—wixœB¤RñÏ@Õí¦"«Æ±ã«óðažŒÁïæ­>e ÛŠ‹#R•ý¨Z…cgØuìdISÈäð!à󈯖e2IóócN…jï;`0õâÖÕ‹šš.n`ddllûà.;$ûà®±±©‘QƒÅ놚S”R¹\PQ)HI¹œ „¨ sHB¥RÉeˆ$htgà†$:t¹BÏ ™”BRÇŒƒ!DT±ì=;T>È«PÚZ0Bˆ” •:Vn•Ô*õ¬¸BDYN&ÙÖ»“T…*¶¤üµ¹7²±‰¹:Ÿt¢<)ºÀÌo¸'C!¢*ùnlz‡ö\¬^YòUaâ AJÏŒ‹!D”q½œjMmE¯¿ ’ n¦!ÕW/cFª” ‚öÏ’÷ë»×ü´’ÙÐR6Aª§ò´¸ZBˆ@z8À¯—’+æY±1¥LXYR,ÓᯗB <–P©h4 a/c$¬nHK’„:|"29K‹Aä?Ë$MV^¿Sˆ|ýrššŒÜj‡v<R–dçŠIýzÁSK_g×uúB6§ÙšÝD$QçN ¡ã°Õ¹Oò’«d¬¶]|ÜLXÚ&fÚi¹2¤C5KP”ž/Ò('£YèÐr_ ¢‰zm#^ÿO_ã’Ñ7uóõÒLÚ;'…ñœ{õqnpúŒŠÍÛó <»™rt-ºö³p%êjIZô fvVZ¡«¹–i·/ô\[O Gªê•<š¢±é+œÉ …$ÒÇMºúøÖJ…¹)‰µu‰¸––XBs+×ìÔë=À¸öèOÿ€éÛw²’%V«7° Pk_' ÖbkÕéËÓG™­iöËÿãâJ‘nw7gKGgjQˆºÊ–‰ ,ºêä$¦´uµÐ¶é5P¯¬R†³µõôµ%.§¨Œë´$ïy MÞô87:ň1$YÙå.mX&Ýõ)èl&N¾š–”>«0ò† ª…b)©ehÄDH%¨±¹Zðç€æÌ>Öÿ.5òìFÍÇpêóõn‹{xùÞ½u•F£µµw2lÃ×ÖÖ¹{ëŠ>ϰ“k7‰D\¿x½ðñõ R*•ŠDb…BŽª®TV•éêêcU×T=}ú”ÇÓGÑé ‡ÍápàT ÙØfÍSâ#_tîjÃ×32R¦&‹Úw±xy#±V“[émœÛ ÝŽ­u¶·2Ñçêr•ai…BOÏ´­qþÓ˜LvWkC6›UŸ˜ÈêìjÎl`¶ŒléZǶ³}zÒ›%mÛY™ñu©§Õ–e0¬­ÌùªÜGÇ׺ØYëéèrAYnÚ‹ç•F.¶’ä¬×fé4uêZ³ ’Ò »Zisô Ùx "ê7’Éwvªm^å¯uŠ$IÍÛÏIœmÞ±«1ht¼¢\#®ÛÞ©öq‹_'äâšÛ±Ÿ¼Ö’®#Oiy³_Ò1µ­(~ü„055Ô×Öb±hJ™¸¦¤ íI×ÅE_ ×i'Lø;NÐÑÞÊDo†R‰¨8»8Wabna†IŸ¾Ö%¡ÇhjœÉº3©˜&ÆÕñ‘Ï;»Ùò¹t$È}˜ÇêÒÍ‚…B…3ô ˜ÕEEU|ž.OLjŽ’ª¼üÔ'ÕæÎÎZ$\ @3f_[>vïéÝXNâµù?Œ|9}ø.‹kÖ@¨T<C7÷^!‘°¶N›ëüÊÂ6®]>ï§ÊòÒ×vIJ¥ŠúMLF{õ'©R©pÇ0 ! Ç1:§-BÊ*r_¼(®’L]#+>‘“V*Ãô<;š³Þ¸‘Ҫ܌ü’ ¡T‰h,¶ž…³µ†HYYvê‹’9¦¥Ï·6”§§•)0ƒv>ŒEÙqóŘ®]ÏN–ìV6XQSš—[R^-–*H“ÅÑ30µ¶0Ñ¥#„qyNFAi¥H¦ÂèCs«¶º ‘5¯í—¬ÎŠ/¼z+¯ÈN}^R-Qqm:»•?l¨‘ͬ¼.IA⃬’iæÚÝÑ@s–({ó´T…9öì̧·ªñòº»®Ó—nvÚdëšM‘×”–WÔˆ$r¹‚@t–6ÏÈÒÎÒˆórÆ€Tæfä—TŠdJDc²Ø:z†ffVmØXC-Q49ÎwÓ™OŠJ_¼È©”©H„a #7oo.ªÍˆø»ÚÚÖUžž[%ÉäJ¢±¸¼6VVFl¸ì€æà¶Ù³uóøIÓª*Ë›“_!—_¿>yæÜªŠ²^œ íÛù2|¬(+# !R”—«ëãaMÖT W߈§E#eE±÷S˜ŽÍ´`„x :ºztsï¶ß<<½ Ú4¹¢¼,:êÞw3æ(òZAÍG/Ž"Iòо Üy à¿>Ò¸ú¸ ¸Jj¡gdÆÀUrQYAþó´\•U'+—7ðVÕU\Ý i³÷ïü£9ùƒ¦Í–I%¢ZÁ§P¡—s|9ûXZ\Gà0⛼úÕ7 ¢¼´øÓ)Žãø?³:ºzp,>™TÒüÌõƒ´Xœº«æeøX+¨†c š€ã4„½°¨$üÌq*É»ï@Pǽ[/¿Ø¦°¨„ŽòÕ‰X„’É0: ÿCByÙwîÞƒ/˜-á#€ð|Êá£R©äñxiiiÿŠ>0`ÿþýÿêÃöïê¿ëôÀ»  …““Ó4%‰µµõÙ³gi4Ú¯¿þÊçó?dÓ>|Èãñ¾ÿþû7æìׯߡC‡ÔogΜٳgÏ5â………3gÎtrrâóù®®®¡¡¡R©´é"R©”Çãeff~ ]øúë¯.\X'– …Ïáãk Ƹqã4ƒ0„ÐÙ³g ÆàÁƒ1 ›2eŠžÞ}öøx<Þùó竪ªZTpÈ!íÚµû(Ã]TTÔ§OŸŠŠŠóçÏgeemٲ寿þ5j”R©ü·t>6×7ß|óèÑ£äädÍnܸqL&Ssu’$Éýû÷{xxXYYùúúÞ½{!T]]mhh˜ŸŸŠŠŠâñxD©T*›¸¸¸–¶[ œ={víÚµºººþù§:=;;{âĉNNNÖÖÖ ¨©©Y¶lÙãÇW­ZÕµk×ñãÇ£×W~Ÿ®®®³gÏV(!…B1oÞ<ªòN:8q¢¥Í^»v­žžÞÑ£GÛ·oÏår===O:{úôij¿...+W®0`@Ïž=,X@ML6ŒúÙµk×ß~û­NΟ?ïééiiiéååõ×_Q‰ï¯ MËÍÍ0a‚££c»ví,X ‹ëdh¬ø ÃGkkk???*ìC={ö,>>~âĉu²íÛ·/,,l÷îÝÙÙÙ‹/7n\^^ž¾¾~çÎ#""BvvvÔëÄÄD‚ \]][Úî'N°X¬áÇ5J½¤.‰†jff—‘‘±råJ:¾jÕ*—eË–%$$9rD³’êêêáÇûøø<þüäɓǎûã—ß ž——Çápþþûï$$$;vŒÚiLLLLLLNNÎÍ›7»téÒÒf_¿~}äÈ‘4MsT===oܸA½ÍÏÏ×ÕÕ½zõê;w233ùå„Ð… ¨Ÿ sæÌѬðÁƒßÿýŠ+²²²~þùç)S¦ÄÆÆ¾×.4A"‘ 2ÄÁÁ!))éÁƒÙÙÙË–-«Ÿ­Á>à3 Bß~ûí©S§$ BhÿþýÞÞÞvvvuòìܹsÑ¢E...8ŽxzzRSb½{÷V‡K–,¹{÷.AwîÜñòò¢Óé-m÷ÁƒY,Ö„ ^¼xñàÁ„Е+W”JåêÕ«uuuétº»»;—Ëm¢’«W¯r8œ °X,GGÇ~øA½:Ïår©«*µ´´üüüB,«¶¶öñãÇr¹œÏç;99µ´ÙfffuÍÌÌÊÊʨ×L&sƌԋ™3g=z´é =:|øp:Þ¿ÿÁƒ>|ø½v!tøða; ñññTú•+WB?ÿü3›ÍæñxK—.=yòdýâ-í#þÅáãÀÙlöÙ³g¥RéÉ“'¿ýöÛúyrrrÖ®]ëþJrrree%BÈ××÷Þ½{àÅ‹ƒæóùIII¾¾¾-mt\\\JJ µíääÔ­[7j%777×ÖÖVsn¯iÖÖÖ†Qommm ©×êt---¡Pˆúꫯ¦NºlÙ2[[ÛÑ£G?þ¼¥-744,**ª“XTTdddD½Ö××g2™Ôkccãòòr™LÖtlmmÕommm Þk¨JîièÔ©“úЗ••©ýäÉ“™L¦@ ¨S¼¥}À'¥eÓ~t:}üøñÄqœÁ` 4¨~KKË%K–Œ1¢Nº‡‡‡@ عs§»»;“Éôóó»råJ\\ÜÆ[Úh*X5jõ–šN[·n••Uvv6A8þZX¬Ž¢ê077ÏÍÍ%I’Ê]jðµXÇgÍš5kÖ¬ššš3fܺu«E-÷÷÷?uêÔœ9sÔ1n^^^ddä¦M›¨·µµµ:::¡ÌÌL###‹%—Ë«ÐÜÜ<''Gý6;;ÛÜÜü½v!Äáp4ŠÁ`¨½………zõ\­ÎA ö>ŠÀ¿E‹ŸûøÍ7ßÄÇǯ[·Žºi¦~†iÓ¦­^½šº¨Q*•FEEeee!„X,–‡‡ÇüAM7úúúîØ±ƒÇã9::¶¨555çÏŸÿå—_Ô³_qqqÚÚÚÇ8p †aË–-«­­U*•qqq"‘!dbb’žž^¿ª…°°0¹\ž––6a„&v•œœ¬R©¸\®žž^ó§9Õ/^\UUõÍ7ߤ¦¦ŠD¢û÷ï9ÒÍÍM #„–.]*•J‹ŠŠÖ¯_?fÌ„“Éäñx vaìØ±çλ}û¶J¥ºyóæÅ‹©IÙ÷×…& 8P&“…††ÖÖÖ’$YPPpõêÕsÖï#>ÛðÑÊÊÊÏÏ/77·þM3”É“'ÿðófͲ±±qqq SO>ùúúÖÖÖRᣧ§§T*mÅÊõ‰'´µµ¿ùæþ+æææ“&M:pà—Ëý믿²²²\]]íììBBB¨]_»vÍÆÆfÈ!šUéëëŸ={öæÍ›ŽŽŽ_}õÕ¨Q£fÏžÝÄ®KJJ¦Njccãä䔜œ¼eË––6ÞÜÜüÖ­[:::C‡µµµ1cÆ_|qæÌõÕŸfffööö®®®^^^Ý»w_²d •2gΛիWkVØ«W¯­[·.Y²ÄÆÆæçŸÞ¾}{=ÞkšÀ7ŸW‹ IDATårÃÃ󲲺wïnmm=bĈÔÔÔúÙë#þ°ùÁÓ7„m“ˆE!™\#ò]»vmáÂ…šF‚>àSÀb2ByÙ;¶mmîµ<¯±M-}j7xß;Xp¤ðöš>Bäñ/ ïCðéøìWuÿ } |ÂGÐr¯]ûXÿ Q°±¶j8|´··‡Ñu(ò†ÃG‚ `t@àÚGá#x?^[¼&IòóîmFF†P(¬¬¬„ßR:::mÛ¶…¡ |ü¯ÈÈÈ I²GpÔ[çÉ“'™™™A>þW…Bww÷Ï~†õýqvvŽ…q |üÇçZÁšõ;Cˆ¿€ÿ¸¦n‰ŽŽ¦Ñhš/„òôô¬óüÇ5µx­T*뼯€ÿ LãuS³111t:]óE3ùûûïÙ³§¥Íº}û¶­­íû}ÀÛ€Z¹xýÕW_q¹\.—khhØ¡C‡   ‡ª·Îž=û_±Þ=dÈF£Ñ¸\®Ýøñã5ï,VoU»ví•>{öì:Umܸ±S§NMì+??ŸF£=zôH’žžN£ÑRSSB—/_îÞ½;ÇÓÓÓóôô¼qã†:[BBB¯^½8޽½ý¾}ûÔéK—.íÚµ«––VŸ>}4wtâÄ ===¸\:|T*•Ô²µú…¦©S§ÖÔÔäåå={ÖÄĤOŸ>çΣ6 6¬}ûöÿŠþOŸ>]&“•••…‡‡›ššzyy9sF½uÚ´i" ýúõ{OͰ··ßµk׋/ÒÒÒ&Nœ8lذ¢¢"„@ 4h¯¯oqqqXXØìÙ³oݺ¥.²jÕªo¾ù¦NU<oæÌ™ëÖ­ƒ“ïCS×>ÆÆÆöêÕK©Tª_Ô)L£ÑØl¶““Óš5kjkkçÏŸ?tèPÇýýýG=yòä¼¼¼àààøøx•JeffvàÀggç%K–dffjiiåääˆD¢)S¦L™2E½wêç®]»vîÜ™ŸŸ¯¯¯?bĈ+V0™Ìýû÷oÛ¶-..ŽÚ{nn®‹‹Ë£G"""¸\î¨Q£ZÑ Ãèt:NïСÃúõëAppð—_~‰ã8ÕA--­pÕ¯œœd2Yvv¶©©é¹sçT*ÕÊ•+étú Aƒ¾üòË;wöíÛ!ôí·ß"„"##ëTÕ¿„5QÚåååQQQõÓ===ŒŒê§Ã6ð„i\üØÔìc¯^½ê¼hÂèÑ£KJJ¨¥Xµ•+Wš˜˜¤§§ççç;vLŽ\¾|ùûï¿¿}ûö… Ö­[wýúõ:µñùüS§N_¼xñÊ•+;vì@5*///&&†ÊsèÐ!ooo[[ÛK—.©çäÞÒ¸q㊋‹Ÿ>}úáJQQ‘™™ÇëÛ·ïàÁƒ©oÇIJJêܹ³úÂÓnݺ%''¿ÛýRåüëÔéu´~ñºsssTïÑÜ,«°°ðÅ‹!cccu<êáá255;vìáÇëÔ6|øð¶mÛbæààðý÷ßGDD „¸\î×_}èÐ!„AGŽ B>}zçÎÍémƒ7‚h¦XXX „***¨­ûöíãk())i°T‹î;©“¢~Íçóãã㣢¢–-[æïïaI’@OOOGOOO 4VCýÝ5³aC‡6l˜z”† 6tèP¸u jåâµæB3%??!Äãñ4㤕+WþòË/£G®­­6lØÊ•+õôôB&&&êlÆÆÆ‘‘‘šBèúõëaaaÙÙÙ$IŠÅbkkk*=((( `ݺuQQQ‰dðàÁï6¦¡zahhH½ýúë¯W¬X¡Þú6r !¤P(Ô)r¹\ŽÂqÜÄÄÄÄÄ$$$ÄÎÎÎÖÖvРAººº999ê"ÕÕÕºººïã< ÂÇ . 6L3”l0‡ 🣱zýίOœ8allÜ®];ÍD·nݺÇß¹s'))iýúõTzff¦:Off&5s©VUU5zôè™3g>~üøéÓ§‹/V‡,;wn׮ݙ3g:4vìX&“ùnGæØ±c&&&êû~¸\®…ê‚ÈÖáóù\.7--M’‘‘A§Ó­¬¬êg&"==!Ô©S§ääd•JE¥'&&6}÷[F‹-j:vhýâ5I’J¥R"‘<þ|Ù²e‡Z·n]ëÂ… ¹¹¹!CCC6›­¾†/99ùÈ‘#AÄÄÄ=ztܸqš¥„B¡R©tqqÁq¼ªªêÀš[ƒ‚‚¶lÙråÊõMLJÖ¼]ºEÔ½xöìÙâÅ‹÷íÛ·iÓ&u/T*•Tƒ:Œ«“®ŽnÌü*dÇ&Nœ¸víÚÄÄD‰DòäÉ“åË—3†š}ܹsglllUUUvvö¼yóJJJ¨ÇñP7ñ„††ŠÅâ7nœ={vêÔ©T… …‚Ú AR©”šËT·šæ¤ZÒüѨýÔ×Ôâu\\\¯^½ …ú…æÖÝ»wïÞ½›Åbñùü=z\¿~½{÷îu®ðKHHøé§Ÿª««9Ž¿¿ÿ‚ ¨ôáÇ߽{÷§Ÿ~ÒÑÑùùçŸû÷ﯹxmaa±zõê!C†ééé}ñÅׯ_W׸xñb777GGG*ñÂ… †††#FŒhEÿ·oß¾}ûv‹ebbâááq÷î]êžÊÎ;5¯ªÜ¹sçwß}W?=>>!ôôéSmmmuâÆøáÍ}ýúë¯kÖ¬=ztAA©©é—_~ùóÏ?S›ÊËË'L˜ŸŸ¯­­íââò×_¹¸¸ „tuu/^¼8sæÌ_ýÕÄÄ$,,Œºí!4mÚ4ê2P„¶¶¶““SJJ BèÈ‘#T#©t„P~~¾‰‰É»:c`ñøOúgñ›<}CØ6‰X„RªÍ\êËõê_·÷6þ÷¿ÿUTTP7S·N—.]~üñÇ1cÆ´¨Tddäû{pãÄ7¼¼¼`€ÿ: GäeïØ¶µ©¯"TÇ‹uǦïÞïµõ§OŸ …­›koJ6±­±Åë÷ 6ÁÁÁ ˆ­[·²X,8x9|¬sY[Ïž=©KÕ/ÞÉ.CCCQk/¡£!‰à ¼F€ð±Q-^?š4­CÂÇ|ÞÑ—Ë}öìõHpLó{¿Á›P'õd"Áÿ+¬¬¬rssãã㫪ªàÀ·ÇÓÖÖ¶´´„¡ |üið@+ÃGX—-£££aD@½}¼}||`t@=dÃáãÉ“'al€¦o¿ýV"5>"„†cƒÃ„ÂGá#€ð@øC |ï½ùYcbb`¼>K=zôx÷á#B( à3síÚµæg†ÅkÐ>€O |‹-ªªª‚!þÀH’$ÆŸ\øÎårœœœÇŽ­¹U¡P¬_¿^&“µºþ'Ož¸¸¸_¿~ý8±Xìïïÿ ^ ºuëV–——'7Þz«K2ÄËËëàÁƒ&&&•••‹-b±X®®®ÔVCCC’$ߦe;v|üøñ–-[>Íãp8Ç?~ü'Õª¬¬¬ˆˆˆAƒÁ™ €÷äÝ,^,\¸pëÖ­ÔÛ£G:;;s¹ÜÂÂBÍlÑÑÑsçÎuqq4hЬY³BgΜ166Þºuë÷ßïææœ™™Ùô¾nݺ5qâDggç &¤¤¤P‰üñ†a6l@=~üØÒÒÒßß_.—7XƒB¡˜={öÏ?ÿbÄ77· ¨{tçζmÛÎ;÷ï¿ÿ1bÄ”)Srrr¨M"‘hÔ¨Q‹-z›˜›$ÉÕ«W‡„„p¹\8³ðI‡![[ÛË—/SñÓ¸qãRRRê,ìÊd²Áƒ'''ÿòË/ùùù¡¯¾újÑ¢E;vìX¼xñÇgΜ9mÚ´òòò&väìì¼aÆÇ‡„„|÷ÝwTâÌ™3¿üòËaÆ!„:vìØ¯_¿íÛ·3™Ìk`0#FŒØ³gÏäÉ“ccc÷ïß2dÈ’%K¨œ––fcc£~’9Žã ,ؾ}û¦M›Œšh ›Íž6mš³³3B¨S§N‡j"3—Ëõööf³ÙÆÆÆîîº•••ê 9((Çq&“9}úô>}úŒ7îäÉ“)))çΣò”––>xð`øðáÔÛ¡C‡®Y³Çq§Þ…¾¾~dd$FÃñVôB¡pýúõLJsÿŽð1;;{àÀMD?$IΙ3G.—%$$Þ¼ySKK !¤9å¦R©Ølvc•$%%>|xÉ’%fffB¡š5¤ôìÙsÛ¶m)))aaa+V¬h~¼ûÆÀ· êéCªê­ƒƒCpp°¯¯oƒEŒŒŒ% ÃÞ¦%ÉÉÉùùùÞÞÞÔ±055ýí·ßàüÀ;÷n¯«ªªÖ­[7cÆŒ&òœÜxZ?ûxéÒ¥ÈÈÈ~ýú1™Lj¾ÍÍÍ ˜FŽYSS“‘‘Àd27lØàççÇf³sss¿øâ‹êêê®]»þùçŸêÕÛŸ~úiÏž=ñññ½zõÚ¹s§ŽŽBhêÔ©ñññ¥¥¥ZZZºººãÇŸ;wn@@À“'OÜÝÝMMMGEeÛµkU«««B¡˜44´C‡6lÐÑÑéÝ»7BhãÆ¡¡¡©©©Ç?xð`‡$ µÔ>iÒ¤ÀÀ@„P»víBCCCBB’““»uëæëëkooZ¿~ý¾}û*++ïܹC§Ó=J¥#„ètº………©©i«¯)R©400022ÒÜÜ|Ó¦Mp~àÃæOß¶M"!„Nœ<¥¾D¯¾˜˜˜÷ñ˜Ã7º¹¹5¶ÔÛ"‘‘‘K—.…ã Ð|×®]kbùW__ŸŠ ò²wlÛJÿ¸m=þüƹ\îÀÿý÷V×süøñ 6ééé}ùå—Ô=1àûÈáãðáÛ˜ïl¾1cÆŒ3'Àû†Ã„ÂGá#ouóæÍ÷TyAAÁ¶mÛ4S6lØðèÑ#vàsmllŒŒŒœÕï‘J¥¿ÿþ»——ר±c“’’ÔùKKKCBBzôè1bĈ£GÖùîM©©©7n„Ãü©Q*•Ë—/oß¾}ôØØXKK˃¾eýû÷ï¯ó¥çš)¥¥¥‹-rss[°`Aqqq«÷•““3yòd//¯½{÷j~ý&áãûâêêš’’rìØ±y󿥤¤SéÛ·o×ÑѹuëÖÚµkgÍšEý‹Å'N8p`TTÔŽ;bbb«¹]»v»wï†cü Šˆˆðöö677¯“îîîþö_–SXXø÷ß×yýÅ‹ûöí«~KÄ÷ß?bĈèèèáÇO:•$ÉÖÅÁ“'Ož9sæõë×B'Ož„ƒ ÂÇÆßßÿ›o¾a±XÖÖÖ½{÷ÎËËCݺukøðát:Ïç/^¼xÀ€M×SUUµ~ýzooï1cÆDGG#„ÒÒÒœœœÖ­[‡º}ûvÛ¶mçÍ›Ge‰D[·n0`€‡‡G@@@bb¢ºžçÏŸ÷îÝûĉpÒ¼%‚ ~ÿý÷ &¨SRSS§Nêáá±téÒÂÂB*‘$Éððð#FP„™™™ThèââbddD­MÏž=›ËåÈd2umÇŸ;w.ƒÁ Þ&%%9;;SžºòU«Vyxx0 OOÏœœ¡PHmJOOvuuýúë¯üñGÍ™ïúÊÊÊH’tuuåp8#GŽ„©n>~L...Ô@?zôèéÓ§...¡gÏž999©ó}ñÅM׳zõjOOÏ;wî„……mÛ¶-99ÙÁÁaÏž=ÔV??¿ .¨3Ÿ9s¦ºº:<<üÎ;ݺuêMb±8--­¬¬ Nš·tÿþýöíÛÛÚÚRoóóóúé§eË–Ý¿ôèÑsæÌ¡ÒOœ8‘””´{÷˜iӦ͙3§¤¤ÄÌÌìÖ­[íÛ·Ÿ2e BhÅŠ®®®/^d±Xêxîüùóýû÷Wï®sçÎ)))Ë–-ÓlFS5ѱcÇFŽI}Ózqqñ?þ8þü„„„°°°gÏž•——7Ñ—6mÚÐh´¸¸¸ÚÚÚ-[¶<|øPóœ>KôO¼}QQQ›6mÚ±c‡––BÇq•JÕ¢,XЫW/„ŸÏŸ5kÖùóç;uêÔXæ^½zÍš5K ØØØ xð`øðá|>ß××÷þýû½{÷¾råÊÔ©SÕ¡S§N«£É76f÷îÝ™™™+W®¤Rnݺ5nÜ8kkk„‰‰ÉÞ½{©#¾gϞ͛7k–ýý÷ßûöíK§Ó÷ìÙ³nݺ¢¢¢o¿ýÖÓÓS[[Ž2?šóçÏŸ>}zïÞ½úúúTJçΓ’’üýýÕyD"—Ëm¢j “‚a˜æÛú,--/_¾\RRRXX¸yóæ’’ÍïTlº,hއiN!SÇEýšÍfS/‚ƒƒë\ÂH=zô¯¿þêéé¹k×®3gΨӫ««:tëÖ­æ´D¡P¬Y³†Åb…††Òé/?J¥Ró(·iÓ†z1yòäÉ“'7vÎlÙ²…êZ÷îÝá$ðÙûDÿÔ±mÛ¶;wîìÚµK__?11155!äçç÷ìÙ³«W¯* ‰D²ÿþ¥K—6]Õ¯¿þK’dEEÅöíÛ‡ †ÒÓÓKKKS*•eee§OŸVg7nÜýû÷ù|¾³³s×®]óóóÕ›’’’ììì¶oß'ÍÛØ¾};µî¬Ö¿ÿPC––¦^¼ úí·ßŠŠŠB;vìxúô)µÉÙÙY.—oß¾ÝÏÏÏÈÈH]ÕÙ³gg̘Ñô¿”ÚÚÚÙ³g[XXüøãt:=<<œZtöóóS7F ìÝ»W3?~ðC‡Qo 1 8p ú‹­ÏŸ?ïçç×¹sç#FTWW·´þªª*ooo''' ÜGMD<“&MÂ0L&“ÁÙð^…‡‡s¹\'''ggç±cÇFGGSéË—/W§;;;›™™:uŠJoÛ¶­‘‘‘‡‡Gii) ð‰øÈÏ}1bBh×®]£Gf2™.\@Óh4„Pnnîž={®^½Êb±”J¥ú‹‰›ÇãÝ»w¯ººú‹/¾¸ÿ~ƒyöíÛ·ÿ~8Þ·!C†xyyܳg‰‰ BèèÑ£ê°rèС§OŸ^³f Œðéøø‹×|>РA‘‘‘b±øÀË—/§ÒÿüóϾ}ûFFFvíÚÕÙÙ9**ŠJOJJ?~¼——׆ &NœèææV\\ÜÒÊåò={öôéÓ'00ðòåËš›D"ѨQ£-ZD’$œï‰ÁÂ… ·nݪ™øäÉ“{÷îõíÛ|Ê>‰o ‰DcÆŒQO1Ž=ÚÕÕ5,,ŒúVbJvvöŠ+¶nÝjllü÷ß/\¸0%%…šµj‘ß~ûÍØØøÚµkr¹ü·ß~ÓܤP(rrrp'‚š­íåË— ‚Àq!Ô¯_?‘H´xñboooàSöIÜ:ãààÀáp†:lذ¦sÞ¼y3((ÈÔÔÇqÿ¯¾úª»‹Å‡ž0aƒÁàr¹3fÌÐܪ¯¯yìØ1ˆß+ Ã4ßÞ¸qcß¾}:::!©TZ?¿B¡xúô)ŒáãKÓ§Oß°aƒ­­íš‹ãš÷¾Ô¿¦á “ɬ¿©NpÞ¹ìììRS”Þ½{5*##cÙ²e æß¼y3ŒáãKnnnóçÏc¶þýûïÝ»7++K*•†‡‡Ÿ;w®ûâp8ãÆ;zô¨R©”J¥»wïÖÜZSSããã3aÂõÝß૪ªZ·n]y_ Ãp—Éd"‘†ød}äkwíÚUZZêççwòäÉ6mÚ„††îܹ³mÛ¶>>>»víÚ³gOIIILL N?tè“““……źuëÖ¯_Ÿ™™9lذ   ¦ë¯®® ,++KOOwssëСÃÁƒqŸ;wîÁƒû÷ïo``@UtäÈÇétº……µ>çÇ;téÒ¥ÈÈÈ~ýú1™L‡àà`777„ЪU«Ôé!±XìççG¥;v¬²²òÚµk!©TÚ«W/Fà£ÃæOß¶M"!„Nœ<5|øðƲÆÄÄ|:M¯ªª:tè™3gø|>H€V»víZ=Ûª¯¯OÅŠyÙ;¶m¥ÿëº'‰‹‹‹ÍÌÌÖ¯_±#À‡ôï ¹\î•+WàÈ|py€ð@ø |>ð™*++«ŸH’dEE ?„ãÇcvèÐ!êmaa!†alÎ7¾ÄÆÆZZZ}Ã0—ôôô;wîPcbbBYYYóçÏwuu8qbJJŠºHuuõO?ýäáá±qãF™LF%ªTª“'OŽ3fÀ€šõWWWoݺÕ××wëÖ­pˆ@øø!Œ1!´k×.¹\ŽºpáB(88˜F£½±¬»»û¦M›Þ˜mãÆT¸>®!C†xyyݹs'%%eË–-{öìILL¤ÂA???*=%%Рa IDATeýúõê0ñôéÓS§NŽŽÖ|ºgcé ìÙ³ç½{÷ìíí{÷î}áÂ…‰'REMHH Š_¾|ùøñãÅb±º~ÿû÷ïëêêªÿ9!IÒÄÄdÍš5uêW©Tnnn!!!p|@øøáðùüAƒEFFŠÅâ,_¾œJ‹ÅÛ¶mó÷÷8pà‰'Ôó‘©©©S§NõððXºtiaa¡ºžGM:µsçÎ'NŒŠŠjή׮];tèÐÊÊJ8>0ƒ… Ö™±{òäɽ{÷úöíëëëûÚðÕW_uìØÇqGB¨¢¢">>¾oß¾8Žýõ×üñ•™N§ûøøÖ©ÄÐÐÐÃÃÃáÀ1ðßñI<6<000$$D$3†N§#„H’üßÿþçççwåÊ…B±wïÞ}ûöM™2%??ÿ§Ÿ~úã?ÌÍÍŸ>}êââràÀ„PJJJhhèæÍ›ÍÍÍËÊÊBCC1 kzÁš$Éüüü¬¬,jâ|`¶¶¶—/_&‚únñ~ýú‰D¢Å‹{{{°6H$’ü1&&fùòåÚÚÚ¡²²2 ÃBºººA…Bj>¡ðÑÁÁÃá :433óÒ¥K¡‚‚‚âââ¡C‡"„ ÆôéÓ;wîüí·ß^¿~=((ÈÒÒ!Ô±cǰ°0ª†Û·oÇÄĨ¿°›ú“ßtøˆaØ–-[är9‹Å‚óàãB4µ7n¤¦¦#„¤R©––Vü …"--­C‡ÍLo6›½jÕª„„„Ý»wûøøp¹\8.À}*w^OŸ>}Æ ¶¶¶… ¦³Ùlê…¹¹ùœ9sâ_yþüùÚµk›Õî=ÿ8²³³¨9þ½{÷5jTFFƲeËÌ¿yóææ§«™™™•——S¯KKKë,@ëééùùùõìÙ3..!Ô¦M›Ç“$‰8ŽÃÔ#ð‰†nnnóçÏW¿577766¾xñ¢R©”Éd»wïž5kƒÁèß¿ÿòóóBiiisæÌ¡òûûû_¹r%99™$I±XþÆ»»»S3^àCªªªZ·nÝŒ3êüc€ã¸L&‰Dïp_§OŸV("‘èøñãþþþ!±X|øðá²²2’$322"""ìííB†††]»v½}û6I’§Nš5k, Ž¼x½k×®ÒÒR??¿“'O¶iÓ&44tçÎmÛ¶õññY½zõþýûû÷ïÏb±&Nœ8räH„……ÅêÕ«—/_žššÚ»wïÐÐÐ;;;//¯cÇŽýñÇ3f̰²²òññ5jB(..îûï¿W*•ééénnnl6ûÏ?ÿ´°° önjjjnnÎd2á<ø.]ºÙ¯_?&“éààìææ†Zµj•: ìüüü¨ôcÇŽUVV^»v !$•J©«KoÌÈ‘#9ÀápfÏžMÝvÍf³ù|þܹsSRRºuë¶råJõY±bÅŠ5kÖüüóÏÇŸ={6•X]]=räÈÒÒRêDrrr:räŽã=úî»ï„Bammí… ‚‚‚ âðÙÃæOß¶M"!„Nœ<¥¾|°¾˜˜˜€€2€Ï̵kר–éëëS±bA^öŽm[áÊ?Ð>„ÂGá#€ð€wB¡P‚æç'I’ 7ÂG„JOOwrr266vvvîÞ½ûš5kjkkß²ÎØØXKK˃¶¢lFFÆÙ³g?@Ç'Mš„a˜L&ûOm¡¡¡;vŒŠŠª³I¥R]¼xqôèÑÞÞÞÔ÷ªmݺ•F£ååå©SrrrfΜéêêRUUE%Êd2 Ü]\\žŸŸ’’’’’òøñãŽ;ÂÇø ÃGM,+ àÒ¥KÔÛ°°033³Ã‡ïß¿¿OŸ>!!!‰!TTTô¿ÿý¯GãÇŽŽVOMM:uª‡‡ÇÒ¥K B2™, €ú¼üüüîÝ»c¦ÎçÎ1cƸººÎž={êÔ©"‘(<<|ìØ±¿ÿþ;5ƒõË/¿¼±ÍUUUk×®õòòêׯߚ5kŽ9B¥'%%}÷ÝwnnnóæÍû?{÷Uþ?Žÿ¸5ÖHÓº¥%”ë[F5b$¥È%’"¤TJ%)Ý7Iek£¶)äV«•\RD¹¦I¡‰L¹—H„3 3f~œß{>óÒÖÖóñ—yÍ™×y½^çuÎ<çuÎË«¾¾Mìë닌Œœ?¾]ZZ7“¦¦&"‘¸dÉ’¸¸8‹Å}«²²ÒÈÈ(>>þûèmªªªx<^DDd@zQQQccãÁƒ'OžŒ®|¦s8___,ËݘÃá "...,,,!!Ñßß§1ðƒ†—/_vttD_nÛ¶- `ûöíÂÂÂiiiK–,áp87ntpp¸ÿþ©S§þþûoôFgccãÞ½{}|| ¼¼¼ÐxôòåËhnòòò÷ïßçî+///%%åܹsEEE6lHOOïêê²²²º|ù²§§':‚µwï^þf2™[·n566¾{÷îÕ«WY,Öëׯ¡R©G-**Ú¸qãÖ­[[[[9}ú´ˆˆHffæÅ‹KJJÐL:;;]]]mmmóòò¢££i4ZXXwÝÝÝÕÕÕèÇ¿ceeeÓ§Oÿý÷ßmmm¹¿ÉÉÉQRRÒÖÖæÝXDD„L&+++O™2ÅÙÙÙÇLJûF[»v­ŽŽŽÏû÷ïáô¾áo¡§NúçŸìììÜÝÝyßúã?V­Z… zC3##ÃÂÂ'ddd¼¼¼ÂÂÂfÍš•••åêꪠ € ˆ––™Læ¿ÇØØX///‡ ˆ¶¶öÝ»weeeGZìÊÊÊÉ“'ëéé!"!!±wïÞ·oß"ríÚµ­[·ÊÉÉ!¢®®îäätûöm++«èèèÒÒRAAA‘Í›78pAòòòÂÂÂõë×£y²X,ƒ±iÓ&tNGG§®®NTTôûî…oÞ¼ ÍÊÊ’’’Ú¿¿¬¬ìÌ™3i4Z@@@llì€9ÎáÇ ´´´222‚‚‚Ž9‚þZ(**’’’Âáp7nÜ8vìØç?€o4|ܱcÇž={}kâĉRxo@õ÷O?ýÄ}}}Ü;¤‚(++¢ØýýýBBBÜ—ãÆ“——´`èýVÞôqãÆ¡ÈÈÈH¤””Þòð*ý{¢¤¤¨©©‰ ˆ……EqqñÌ™3ËÊÊ yùò¥œœÜéÓ§ihh˜3g‚ K–,Ù¶m›¯¯¯°°0‚ h‚H¤Ã‡Cø| ÿ±ÐD__ÿÆT*•Ãá¼{÷.((ÈÁÁAE‹EEE566"R]]Þ¼F‹Å666¾ÿžN§'&&róY¾|yxxxgg'‡ÃyýúµÏ³gÏ?~|UUU__F+))¡R©| £¡¡QUUUTTÄápz{{³³³Ña0[[Û³g϶´´ R[[cll,&&æä䃎/FDD ™L›6MSS311‘Åb±X¬¢¢"Þ¡ÓÒÒÒiÓ¦;wîûî…fffIIIÍÍÍ]]]·nÝš>}:z¬©ÿciiéíín,++ÛÑÑñäÉ&“™½dÉ4v¤P(·nÝb2™]]]‰‰‰ÎÎÎpzßaøX[[ëîîN&“uuu###¹é,ËÎÎî÷ßß³g®®®µµ5ƒÁ@DBB",,,&&ÆÀÀ`Ë–-ŽŽŽè½cyyyÿC‡‘H¤¨¨¨£Gúúúæåå‰ŠŠ†„„XZZªªª"‚îeÑ¢EóçÏwuu={¶¯¯ïüùóÑ+--­ùóçÏ›7oÙ²eÉÉÉh\2 šššjhhhiiI¥R7n܈ ÷ööÞ·o‘H<{öìéÓ§eddÙ¾}{ww÷¢E‹œUUUquuåp8GŽéèè°°°°±±¹uë–¹¹9w¢¢¢JJJ?ÿüó÷ÑÛbbbtuuÿøãOOO]]Ý{÷î¡é’’’ؾ}»¥¥¥‘‘zLQ ÃÒÒ233ó¯¿þâ6û?ÿü®§§WXXxìØ14}æÌ™555¦¦¦æææl6{ÐùÝø|Þž›É!=ÝtAâ®ØØØ µiaa¡©©)4Àw&33“H$õ.‡CcÅ× /CC‚aÕ0>„ÂGá#€ðñÛ×ÙÙ¹{÷8®ßsø˜™™¹xñb==½S§N?~Ôù0™Ì€€€ÞÞÞOnÙÕÕ5þ|%%¥?þøãß©ãµk×deeïܹóÃvµÔÔTYYY%%%<ollÍf³)..ÆápFFF]]]8Ž{PÜÜÜTUUñx<G¤¢¢BUUÕØØ˜Á`p8GGG))){{û7oÞ¨«««««777#âîîŽÅbÓÒÒa0gΜ!‘HŽŽŽ¥¥¥Üò¼}ûÖ××—H$ÚÚÚÆÄÄÄÄÄ ÒÑÑahh¨®®. €ÇãÐBVTTLŸ>]VVV@@àÍ›7hW¯^•••E×.onnÖÓÓ ÉÏÏÇb±èZííííÓ§OWWWollLMMÕÔÔDs.((€«€ÿ*oÏM§›Në¦Óþþûeddp¾€òòr33³––ƒéääÄù·äççûûûÿk» ¤P(œØéÓ§oݺÅáp:::vïÞ’’‚¦¯X±âÕ«Wèß«W¯®­­Eÿ^¿~}UUÕ€L( ‚ ÿüóúrûöíeee§¶¶ÖØØ˜F£q8œàà`î§NºpáƒÁxùò%‰Dzóæ ‡Ã¡Ó馦¦÷ïßg2™---;vìØºu+wsæÌù¸ü«V­rqq‰‰‰á=¦‚”––¢/Ñß0'&&fçÎl6›N§›››?yòÝ »»[YY™|c222øÜX±º¢ÜÛsÓ×}liiÑÐБ‘Á`0NNN躂455ùøø‰Ä%K–ÄÅűX,AØl¶½½=‡ËËË;|ø°‘‘ÑÅ‹Ñícbbðx<‹mjjâfÎáp""",--µµµwïÞÝÞÞ>ŠR(2™¼páÂŋ߽{M÷õõÅb±ÍÍÍýýývvv8®²²²  `õêÕ«V­Ò×׉‰Y¹r¥››º7‚ µµµ;vì ‰Û·oohh]M©¬¬422Bäþ‹p8ÜâÅ‹?~<ºïß¿ÿÂ… oß¾åMœ:uª““Sddduuuff¦½½=šnbb²zõj £¨¨hdd„6{NNŽžžž°°°ŒŒÌ¾}ûÌÌÌøï´©©©®®n÷îÝhøÈM8zôh?ïÆ #))鯿þ²³³CWñ¾_?|Ô××ïëëóððˆ‰‰©¬¬400@¤³³ÓÕÕÕÖÖ6///::šF£………!"((ïèè¸iÓ¦ùóçgee¡‹G#âääD¥R,«( °páÂK—.•––„††Ž¢„$éýû÷©©©—/_憡~~~ÆÆÆ‚ %&&:::"2{öìþþþÅ‹'&&nÙ²ÅÇÇÇÎÎ...Íêĉžžž<ذaÆ Þ¿?Šš"ÒÝÝ]]]ÝÚÚúív —/_ž;w.7ÅÜÜ\WWWWW÷Ƽ[}zii©‰‰ w:ŽÅb‡*IMMM^^:ŽÈf³ÅÄÄ6nÜÈ %%%ÝÝÝyŸ.èëëÛµk×Ù³gËÊÊ}}}ÍÖÌÌìÕ«WܘøOøú!ÈÍ›7Ïž=ûþýûÞÞÞŒŒŒyóæ‰ŠŠN›6MSS311‘Åb±X¬¢¢"2™<ŠÌ+++UTTdddZZZЩµcë—_~ihh`2™ùùùŸÜþôéÓ §ªª*55UOOot5---6mÚ¹sç¾ã®Y[[ÓÕÕÅd2ïܹƒÁ`äääx7ÐÔÔÔÖÖ â“ ›Í ÉÍÍ Çáp%%%‚?þ<##ƒÉdöôôüý÷ßèê¡Ü¾};88˜J¥R©ÔçϟϘ1£¤¤„w[[[Þû×ááá$IOOoíÚµ/^¼ÈÌÌ„k €ïÇWŸy}ìØ±;vH¤™3g8p ¥¥Mïéé ]´h‘……űcÇиõõõsæÌ‘””üõ×_ ‚ŸŸºq[[›±±1@˜0a‚––@¸}û6‡ÃillܸqãŒ3\\\Μ9###sþüy‡sá ¦¦&''G V¬XN˜Ô… &L˜°téR&“™ŸŸ/))¹~ýzô­ªª*kkkyyù+V¯ZµêîÝ»’’’›7oîêêBäòåË÷ïß———?{ö¬œœÜÑ£G7lØ@$½¼¼¸sGTSTEE‰DŠ‹‹ûMéºqㆼ¼¼ŠŠ @¸ÿþ€æ]°`Aggç©S§$%%ÍÍÍ ‹ÅJNN^ºtéÌ™3÷ìÙÓÜÜŒ¶Õ‚ äääöíÛ‡wtæ5:S[MMMFFföìÙ555^ƒ¶!@PTT¼zõ*·ÙÏ;gjjºhÑ¢ððp:ŽÎ¹^°`Áo¿ý&&&F œûûûsrrÐñðáC‡¥¨¨¨¦¦–‘‘¡¬¬¬¢¢‚æùàÁA˜L&:ÈmjjÚÓÓÓÐÐðÛo¿IJJ>zôèÆ3fÌ@„ð?‚ ÿøͼðöÜHéé¦#ŸpÅÆÆf¨@³°°pÀÄðÈÌÌ$‰C½‹ÃáÐXñuÃËÐ`X´Œ„ÂGá#€ð@ø |à+‡555êêê²²²x<Çkjj¢K¦¦¦b±Xuuu<ïèèˆþCf”»»;Çb±ªªªD"±©© Aƒb±X<?}út//¯ÆÆF8´_ÂW^óZEE%22²  `Ïž=‚°X,A¬¬¬H$ÒÅ‹'Mšôîݻݻwc0ABCC±µµ šÎü'ÃG2™¬««ëååÕÛÛ;}úô7PVVNKKc³Ùà Ÿ>}Ê}ÙÑÑQQQA£Ñàx|áã¶mÛŠ‹‹—.]*,,Ì`0>Þ} rø8÷¥““Scc#‰D‚ã ð=„¨+W®`0??¿êêêo½|ùrñâÅ‚‚Ã-mMM¶¶öÿSOA˜cð}…BBB‚ÐéôþùçæÍ›‡;FDDX[[sS._¾¬  ŸŸÇà3}å™×µµµîîî hJ}}½››ÛÍ›7óòò.\8nÜ8UUUOOO]]]tƒ­[·ÔÖÖšššâp¸„„99¹‡êêê êéé………Mœ8‘»7mÚ41118ÞÿíðqÚ´iT*õãtmmm:>èGΞ=ûq¢¯¯¯¯¯ïP{177777‡ƒ ðùà‰@á#€ð@ø |>á#ø¯âp8Ã_ðMa³Ù¼KË |cƒÅb…††’H$OOÏ·oßBƒ ,$$ÔÐÐMÁ§/]ºddddaaA¡P AÀ¨egg›™™ÙÙÙ•––~‰ü[[[92æ9ØØØH¤ÈÈÈþþ~8”@øøKMMp¥¾zõjWWWnn®“““··÷ùK½··÷СC§¿xñâÎ;?l‡©®®ŽçM¹yófUUUZZZtttppðóçÏÌ–ùóÏ?;;;á’2jÏŸ?ŒŒ¼zõjHHˆ‡‡GGGǘï‚L&;99y¶/^¼8|øpdddVVV{{{bb"M |üÎÕ××·´´ð¦DGG;:: ‰ÄÞÞÞW¯^ý€ÍÒÓÓ“••5 ‘Ãáøûûûúúb±Ø¶Ã´¶¶ÖÖÖò¦°ÙlqqqQQQqqñöÎ~aa!FãM©©©ñôôÔÑѱ··ß³gÏQûndee­]»‹ÅÊÈÈ8::Œmþ%%%ïÞ½³¶¶ó’s8,‹Á`DDD$$$Æ|ô:>~ë8…B‘••E_ª««Ãýk®œœ%%%mmmh ^–––ÕÕÕ ÒÒÒ:::x<ÚAæææ={öx{{?~ü˜L&?þ¼­­ š…—/_Nž<ý[^^þõë×c˜9“ÉôóóÛ»w¯€€À˜—|êÔ©æææŠŠŠ eÅŠБøB„¡ ¾®ŽŽ++«ŽŽŽ¶¶¶qãÆIHH¨««'$$ ñnö%.µß¸¨¨¨€€‹UUU…FBgΜY°`F ˆýaûÌÆóòòèt:F‹‰‰»víš‚‚½{÷p8\yy9Nß½{·••ÕÔ©Sœf)..vqqA£##£qãÆ¹ººîܹ3''ÇÉÉIQQAI“&?^TT®<Ã4æWžk×®™››O™2¥©©éKüTHJJª©©™0aBpppzzº••Õþj…Ž„ߊ‰'æåå!¤¦¦¶hÑ"î[óæÍ{ûö-: PYY¹nݺªeÖ¬Y³fÍš÷ïß›››óÞ>+++kll444D99¹Ó§OÿP-† HAAÁ;wöïßÏM§P(666ÒÒÒÒÒÒVVV………?Tø¨««K¥R±µµ ⎟±X,AÁÿ»Í"-- —þß¼yƒŽî744(((Œaæ×¯_/--%“Ét:½¯¯ÏÖÖVKKk¬2üø±©©é´iÓYºtiDDĆБà7¯¿]...±±±l6»¨¨HDDdÊ”)Ð&‚èëëSÿÇÒÒÒÛÛÚ„?¥¥¥uvv¶¶¶Þ¼ys ¿•ÿÓŒ£¢¢éìì<þüÕ«W¡Yø055½páBwwwkkk\\œÁf~ùòeôä‹‹swwÛ^ª¡¡‘––ÖÔÔD§ÓÓÓÓ‰D"t$¾}üV¨ªªþòË/¼)Ë–-‹ˆˆ022š1cÆ©S§~ÀûׂüôÓOƒ>bÏ`0ìììòòò~ùå—S§Ný€-#++«©©É›baaÑÙÙimm-&&¶}ûööÙÐyóæ?žûrÊ”)þþþGŽyüøñ”)Sììì~ä ûá©©éêêºlÙ2,{æÌ™‰'Žù.RSSwîÜÙÝݽlÙ²1|HwêÔ©>>>›7onkksqqqppÃ2CG€—€·ç§€ IDAT¦@rHO7Aø„+666CmZXXhjj MðÉÌÌä3fÃáÐXñuÃËÐ`¸y FÂGá#€ð@ø |>Z[[¿³q86›ýùù°Ùl‡óTjL 3h&L&³³³N„ß¹÷ïßïÝ»WOOïäÉ“½½½Üôêêjggg“äädÞí³³³ÍÌÌìììJKK¹‰,+44”D"yzz¾}ûvÌ 9&;½téÒ¬Y³"##étº‡‡‡‘‘QYYÙP777¯X±bñâÅÍÍÍ EOOoß¾}c•y__ß¾}ûôõõ ^¼xaiiiccÃçK÷Ñ£G†††›7of±XAAA³fͺråÊXfLš·¿¿?!!aåÊ•fffÞª#}i¯_¿>tè‰DòòòBã¿ÒÒR)))<ÇãMLLººº†“Opp°PCCÃçÔ¨µµUQQñÈ‘#£«Koo¯€€Zrmmíòòrî[666$)22²¿¿8¹ edd|æï„5ª­­=zô¨––V~~>|sŒ¹¾¾¾³gÏêéémÞ¼ùÍ›7hbjjª¦¦&Ú7¸+—r8œ+V`±Ø‡"rþüy“'O^½zUVVöÀèõMOOO@@ $$Aýû÷««« ?~š€±áí¹‰ÃátÓiÝtÚßÿÝ1´ŒŒ Î7ïøñã>|àMÙ¶m[vvvxxxXXšH§ÓI$R}}=ƒÁذaÃÇÑôgÏž­X±‚F£µ´´H¤wïÞ¡éqqq'Nœ`±X¦Cu¤¡àñøÀÀ@))©ºº:ggç 7ÚöìÙsêÔ)2™ÜÒÒ²aƶ¶6>™tww·µµUTTøúúªªªîرCZZ}+77×ÖÖ¶¹¹ÙÕÕuíÚµBBBücY%%¥‡f¤5b2™~~~gΜijjâMܺu«‡‡Çž={h4ÚéÓ§ÑfçƒF£­]»¶¤¤ÄÒÒÒÛÛ‡Ã!2uêTsss 999‰tùòeþ™¼~ý:))éÊ•+.\à&ÆÇÇ×ÔÔDDDL˜0áÅ‹^^^ÜC?Ì1ÑÙÙéêêzüøñƒvww_¹r%,,lË–-ïß¿—’’êéé±··ß¼yóp²š>}º³³³žž…Báý]7sæÌ¾¾¾ŒŒ Þ© FddäÆÙlvJJŠ‘‘ |üÿ‡L\\\ÐXÁÈÈhܸq®®®;wîÎg‡¸iú˜ø*;ýq|ÑæN&555ÑÑÑÕÕÕJJJÜQœœ'''4x4iÒùóçEEEùd‚>IbffUXX¸cÇŽèèh46ŒŒTRRøë¯¿RRR–.]Ê'\ ˆýÌ]»vÍÜÜ|Ê”)¼ÁVeeåäÉ“õôôПm{÷îåÿt)ƒ)**’’’Âáp7nÜ8vìØŸþ‰ÖIII555&LNOO·²²â“O@@€ƒáMLHH R©IIIèË·oßÞ¿߯ÆfD5c¢¼¼¼°°pýúõèK‹Å`06mÚÄáp„……¥¥¥¹?öURR¢££ƒþÝÜÜ,//ßÒÒ2`›7ÚÙÙÍ;—›òðáCôî‘H\¹rå&Nœ‡€ÏñܼÖÕÕ¥R©T*ÕÔÔ477—J¥¢±£´´ôÓ§Oч`:;;ÅÅÅÑ/éúúzîp‹ŠŠ ú·¢¢"÷©í†††É“'£_¢óæÍã~ÿUVVÊÈÈŒaá¿ÊN_´y‡êHƒ*--ŽŽÞ¿ffæÉ“'¹é,‹÷f½´´ôøñãùä#--­¦¦¶yófqqñùóç?xð%#,,¬­­=~üxqqñ¹sçòŸNTVVÖØØhhhˆÇãoܸÁ-ψj„ Èõë×Éd2wpp Eg½ô÷÷ó|Ž7N^^ž>šššÒÒÒ"""$)++ M|üø±©©é´iÓ¤¤¤–.]ÊM*ªÎÎÎ^³f ?tèБ#GÐfQUU +þŸ††>±ãP5úw 5a|¨tôÎïg¦ÿ›;•‘‘!‘H=BEiiiee¥   ¨¨h[[›¦¦&‰DBþ¡&~™™™¡3 sssŸ?N¡Püýý_¼xÁ»¤¤¤»»ûÅ‹¹)7nܸ{÷.744»wï\€ð‘III@¡P8Ε+WÐÛ©h¸™žžÞØØØ××eii‰¦›šš^¸p¡»»»µµ5..ÎÀÀMwqq‰e³ÙEEE"""S¦LÃB~•þ8¾hóÕ‘õòåKeeeyyyƒÃM766ŽŠŠjllDäœ?þêÕ«|ò7nœ§§gJJJooïýû÷uttÐpóâÅ‹OŸ>e³Ù--- üïÐéëëSÿ½_<Š!rùòe4“¸¸8www---A444ªªªŠŠŠ8Nooovv6ÿIÙ åÖ­[L&³««+11ÑÙÙM×ÐÐHKKkjj¢ÓééééD"‘O&'NäÖèСC>>>h³¸ººž>}ý ÑÞÞúìÙ³‘Öè_ðáÇ ¸ººxno¨ô²²2MMÍðððùÄÇÇ«¨¨pŸñåÚ¾}»Á€±ºy§Ó¦MÓÔÔLLLD§¾‘ÉdA°X¬””Tkkë† Š‹‹›ššøÿ‚jii9pàÀñãÇ'Ož|úôémÛ¶õôôðn`kkËzßÙÙ™ýôéSô°Þ¼y3!!.Œ|®ïlæ5™Lîìì0Go×®] ƒ›^QQ±råJ“«W¯˜ydff¶lÙ²'OžðN¼ !‘H---_bºÓçì”B¡hiiM˜0aÙ²e»wïVTTTTTŒˆˆtãþþ~{{{99955µ?ÿüsöìÙ‚ CqŸŸ9:§[EEE^^þÀ’’’<tãÆÆF11±Ù³g;vLCCCRRrݺuC̓iaÆê˜vtt˜˜˜üöÛobbbaåÊ•èLO>iÐIÁG%èЈ››úVyyù† fΜikk{ùòåONíëë;}ú4‘HܼysSSšX__ðàA"‘hnnž’’2œŽ×ÓÓcaa1a„íÛ·òÔà#%%EMMM^^¾¼¼MyûöíÁƒ LLLþúë/þ-ÜÙÙyîÜ9ccc‰Ä[ýüü|kkkƒ°°0þó÷¹|}}åååI$÷RðôéS777"‘¸eË–+W®ôööŽ¢F—.]"òòò***áîÝ»c{ ÑhË—/÷ööÐù‡J¯¨¨ ‘H±±±ò¹yóæœ9s?~< ÝßßßÜܼ½½ýëî´§§'44tÑ¢EÇŽ«ªªBÓcccýüüº»»rrrÐÄ7n̘1AÂÿ ¿H$’ŒŒ ÚÉO:…þH¨ªªRVVVQQAû-ú`qOOµµµ¤¤$z®µ··Ï›7AÀ4[>gæµ€·ç¦@rHO7Aø„+|nëšššBÀ `lõ÷÷GEE%%%©««;88Ìš5 Ú€Yff&Ÿ›<8_7¼ †öðu ­[·nݺuÐü'À¢…ÂGá#€ð@ø |üq0™ÌÎÎÎÿhá[[[¿ý̇ZÐâ‹ú*;_Å7~¬Ñ@‡i¤†ZØáãØ{ÿþýÞ½{õôôNž<‰®v…ª®®vvv611INNæ&ÖÖÖ=zTKK+??Àe+44”D"yzzò_½w:;;õõõMMMÓÓÓ¹é/^¼ðööÖÑÑqqq¡R©ü3éïïOHHX¹r¥™™ÙÇï¾~ýúСC$ÉËË‹Ífó¿@\Sþ™jÐæåÆ ŠŠŠü—!©¨¨PUUå]Ù—›››ªª*Çãññññà |ìt¤Ç´¬¬ÌÅÅ…H$’ÉdƒÁM/((°±±!‘H‘‘‘–è ½½‹Åâÿ‡ÃUWW£oÕ××oÙ²EGGÇ××·££ã“±Q\\œ™™™žž^PP“É]ÇûäN×®]+ À{Ö  ]ºtÉÈÈÈ‚B¡pÓ/^¼¨  €Ö”»¤ÍçNa¸GDHHˆ»èª¥¥eÛ¶mÓ§O×ÓÓãßg†:KKK¥¤¤Ð™˜˜ µªÿÞûþýûàààyóæ§Ö ãÌ™3$ÉÑѱ´´ôË5ïpZà‹êëë;{ö¬žžÞæÍ›¹«Œòzñâ…««ë×ý6©®®öðð ‰ûöíã^4z{{Ðc¡­­ýÉU.ïß¿ooo¿eË–/úS€/î;[uæøñã>|àMÙ¶m[vvvxxxXXšH§ÓI$R}}=ƒÁذaÃÇÑôªªªòòr2™œ––Æ›I\\܉'X,Öƒœ‡Zet=z”™™Éd2ß½{goo_VV†¦'&&>}ú´¿¿¿¶¶vÆŒt:O&L&377·®®Ž@ x«¡¡D"åçç3ŒO®Û1hMùd>¨¡šõûï¿ïÙ³ÇÏÏ& %00pз֯_Ï]¬b˜>Þ鈎iKKËܹs_½zÕÓÓvêÔ)4½®®ÎÔÔ´µµ•N§?~<..ŽÿR1—.]â/€öU&“i``ðôéÓ¾¾¾›7ozzzò¯KKKËßÿM§Ó{zz¹yŽÈ0wŠF0|òIMMõññ¡ÑhíííË–-{öìš5üEk†é“…A5133óòòp ûúúfee±Ùl6›Í]1hDçã“'OvíÚ5Ì¢Õ{ÛÚÚîß¿Ÿ““óÉþ:uêÔ…  ÆË—/I$Ò›7o¾\ó~²¾¨èèh&“yïÞ½uëÖ}¼Áž={’““¿â—Kmm­µµu]]“É,**²°°@Ï_ƒ!##3ü|-ZD£Ñnß¾}þüyXæüwWùÞF i4ïxOqqñ‚ íííÏž=‹¦›™™M™2ƒÁ¸ººÞ¸qMGÇ´DDDdíèè($$D${{{_½z5†ež9sæ¢E‹„……q8Ü”)S¸7h–-[¦¥¥%((8iÒ¤‰'ò5ž;w®¤¤äÇoíÛ·/44T__ƒÁ âÅZS>™j¨æE¤¤¤äÝ»wÖÖÖÃɧ££# ÀÐÐpåÊ•èd£3èNGtLÇwéÒ%QQÑ… >zôˆ;ö†Åb1Œˆˆˆ„„ÿÑG'''ôo*•jhh(!!f‚ ˆ¸¸¸°°ð'3ADFFfÍš5bbb¢¢¢JJJ}}}hzUU•———ŽŽÎÂ… ÓÒÒ>yÿtÐöõõEFFΟ?ßÎÎî“™ C¡âââ"""¢¢¢âââü{éP>|øpøðaCCC"‘Ä=FZAbccÕÔÔ¸)]]]óçÏ Ú¸q£–––ƒƒÃèÎÇ‘´÷JJJêé鉉‰ 3“Õ«Wc0EEE##£†††á*:V-0|l6ûÌ™3öööÝÝÝííí©©©”'$$,\¸}yþüy?ÿüAÕ«W ðŽ|;vlÉ’%ïÞ½ÛBž9sÆ××WYYYXXXWW×ÍÍ-..nùøùùíÞ½;11ÑÜܼ¸¸ø“w–€›×_Akk«¶¶¶€€‚ l6 .ß¼y£¤¤„n3iÒ$î=Ä¡¾h)Ь¬,úR]]}Ìï_#B&“ÍÍÍ%$$Ð5^Q===žžžÆÆÆ»víE¶ÝÝÝmmmvvvûöíã»d¬j:Tó2™L??¿½{÷¢Gä“üýý rssÉdrHHHYY÷­ƒΚ5kíÚµ555ü3t§#­)‡SPP@s ^½z5š>uêTô¨)**R(”+V ³‰îܹÃ}@DD„L&+++O™2ÅÙÙÙÇÇg89dff®\¹2::š»S999ooïG%%%¾~ýš,;èNOŸ>-""’™™yñâÅ’’’OÃÒÒ²ººZAAAZZZGGÇsߺpáÂüùó/^ÌûÕ>(qqq''§¬¬¬¼¼¼ÖÖÖœœœÑæõë×IIIvvv¼‰ãÇ¿}û¶‹‹ËõëשTj||¼  àèÎÇÜÜ\[[[}}ýˆˆˆOFù|zïðikk£¥}òäɳgÏ´µµGѼcxEúBÞ¿/%%ÕÓÓcoo?èÑ¡R©ÆÆÆÜ°ÛÕÕõĉíííL&311ÑØØ˜{j766¾xñ‚û³j¬Ü”””_ý•›2cÆŒ‚‚ôo¶víZŸ÷ïßóÏJOO/ `ñâÅîîîiii222ˆ¿šââbôÑ“ÌÌL###<8ÌÏ3”õöÃäîî~ôèц††ªª*nâO?ýtäÈ‘ãÇGGGÓéôÑ ddd466FEE™˜˜ìرã_®)o&×®]377Ÿ2eÊ0?»sçN}}}AAAîc”\PPðìÙ³€€€   ád²páB??¿Y³fݺu MyûömHHˆ™™™»»{kk+ï0ü ?>ÞiwwwttôªU«DDD°XìæÍ›?YŒ{÷îáp¸òòr*•šŸŸ_WW‡¦[[[ŸâñøÈÈÈ‹/fee577§¤¤Œ®÷ŽB~~þ‘#GBCCEEEGѼcxEúB8ް°pcc£´´ôüùó?Þ ¦¦fÚ´iÿ÷½%(èííÃáf̘amm½lÙ2Þs9((¨¨¨hÒ¤Ic^ÎA/ ¦¨¨èÏ?ÿ|øð!@8vìŸX,VXX˜¥¥åÛ·o#""|||¤¥¥!>~5ºººT*•J¥šššæææR©Ô;w""--ýôéSô>]gg§   :†7iÒ¤úúzîP™ŠŠ ÿKƼyó¸£S•••_â÷"ƒÑÕÕuqqá½Õ‹ È„ Œç̙ýa:"ÒÒÒjjj›7oŸ?þƒø<ò?V5ªy¯_¿N&“ñx¼ƒƒChhè'Ÿ1ç‡à¾TPPPPPÖÔÔ”à?p8èNGQÓ¶¶¶µk×.^¼xåÊ•ÜÄÇ›ššN›6MJJjéÒ¥YYYÃiŸçÏŸ„‰'¢/æÌ™3~üø%K–œ?~8· Ñ#‚F`[¶lqvvNMM=þü'GŒøì”û9nܸOƒB¡ØØØHKK+))YYYrÇkÕÕÕ1ŒŒŒÌܹsùÇ7»víÒÖÖŽ‰‰ILL´µµô û“…éèèÈÎÎ^³f ?tèБ#GøtõQœÂÂÂÚÚÚãÇŸ;wî'G‡ê½#•œœ|îܹóçÏóvÑ5ïØ^‘†êœ#J05^TT´­­MSS“D"Í;íϼÛOœ8qÀ¨^ww7•J%‘HT*õã] ÚÚCÍÇNÉ­¬¬ž?ÎM)--Õ××GÿÖÔÔ”––!‘H.vÚÝÝ­¬¬œššúîÝ;ww÷ÈÈHøwÂÇo‘¤¤$@ P(çÊ•+Üp3==½±±±¯¯/**ÊÒÒ’>...±±±l6»¨¨HDDdøãgÃqåÊ•êêj‡óöíÛ´´´éÓ§s‡^Z[[ÑG¶ïܹÃ?Æʸqã<==SRRz{{ïß¿¯££3~üø/]Ó¡š÷òåËh”çî¥Å?Ÿ'N ÓnÚÛÛÏ;‡>¼X[[ÓÕÕÅd2ïܹƒÁ`äääød2ÔNGTÓ—/_®ZµÊËËËÜÜœÍfÿóÏ?hº††FZZZSSNOOOç(òw÷î]sssîKYYÙŽŽŽ'Ož0™Ìììì%K–ðD5//¯  €ÅbÑh´´´4ô¶]kk«Ð´iÓïܹsïÞ=þet§bbbNNN111,‹Á`DDD çX§¥¥uvv¶¶¶Þ¼ymÞîîîààদ&‡SSS“””Ä'œåp8wïÞÕÐÐ?~üóçϯ^½Š¦´0'N¤þÏ¡C‡|||øwõ‚\¼xñéÓ§l6»¥¥%!!ÁÈÈh½wDØlvHHHnnnxx8‡+))©¨¨ióŽa RVV¦©©>à#ñññ***Ü›¹\Û·o700hiiáMüðá \]]¹`±X))©ÖÖÖ 6755 8vÓ¦MãxN§Ó7oÞlccƒÁ`Ž9ÂêyzzΞ=»¹¹™ÿNù×èãtOOÏÇ××׳ÙìÒÒÒððpô9Z …rëÖ-&“ÙÕÕ•˜˜èììÌg§‹-ª««c0W¯^}òäÉ ÓÌøøÎf^“ÉäÎÎNÞ”ŽŽŽ]»vðNÛ¬¨¨X¹r¥‰‰ ïÆK—.yyyp÷î]î4Õ‰äááÑÒÒ2¶e.++óòò"K–,áNe³ÙNNN3fÌX¿~}yy9ÿL:::LLL~ûí7111°råJîôÒ¾¾¾Ó§O‰ÄÍ›7£_9ü'ä~\S>™eÐæE¥¤¤¨©©ÉËËó©TEE…†††›››ƒƒCaa!ú‹ÅJNN^ºtéÌ™3÷ìÙÓÜÜ<œFþx§#:¦222@ ̘1ƒw¢e~~¾µµµAXXØ''¶£:ôîÝ;Þ”—/_nÚ´‰@ 8p`À[{óæÍ±cÇ æÍ›wîÜ9n¯Ž%‘HóæÍ;yò¤µµõœ9sÚÚÚøä3èN FXX˜±±ñ²eËÐa'þ‡»¿¿ÿÒ¥KóæÍ377ÏÎÎæ½»aÆ3f¸¸¸|rêîÇ—,Y2{öì;wîÛ·OYY ¼FZî$kyyy‰„^  ddd444ÐÊŽâ|äp8õõõ$‰æææ)))ü;ÿP½·¤¤„@ ¨©©ÉÉÉ„³gÏòÉÿõ×_ÑŽ§¨¨È=›FÔ¼crEâVD"ÅÆÆøÈÍ›7çÌ™óøñãéþþþæææííí¼‰4mùòåÞÞÞ¼ÿî 66ÖÏϯ»»»¡¡!''g@>½½½ÏŸ?G¯èó¾d2™ÃálÚ´ A£GòîÔÂÂb8;åS£AÓ+**6nÜH$÷îÝ˽htvvžÃÇà% IDAT;wÎØØ˜D"õôô|r§èÅgýúõÿüóÏØþþµ™×Þž›É!=ÝtAâ®ØØØ hrùÆJTTTRR’ºººƒƒÃ¬Y³lœœ\RRâççmÀ’™™Éç‡CcÅ× /CC‚…¡½|]BBBëÖ­[·nÝPXZZrg¾:X´À·NXXxø«^ |>„@øFý§k?ÂNGZÂööö}d¨0>“ÉDýûtuuñ_Rò[öåŽÑ(: @øø¯zÿþýÞ½{õôôNž<ÉûMV]]íììlbb»-ƒÁ8sæ ‰Drttä]ä€Åb…††’H$OOOþKäNvv¶™™™ïNGÊÍÍMUU]û;>>žM‡rñâE4ooïï 544Œ®„¥¥¥RRRhæ&&&Ã\SŽw§ªªª'OžüüæÑ1½w¬,ZrMMMYYYnï ž7o^ppððËSPP $$”‘‘Á›ØÒÒ²mÛ¶éÓ§ëééñ¾¡r°±±!‘H‘‘‘Ü-jkk=ª¥¥•ŸŸ?æ§ŸHèÒ¥KFFF …›ž——çå奠 0Ìóeд0C¡Ñh‡ž5k–Ï0{]kk«¢¢â‘#G>ÿ<ŒŒ”’’B?2Šóù½wL:t‹Åª««kjjÚÚÚr˜A/;êêêx<^II‰L&•Ijjª¬¬¬’’R||ü‹/ÔÕÕGQžêêj"‘¸oß¾§ø R©ŽŽŽ$)!!¢ ð£øÎV9~üø‡xS¶mÛ–Ýß߆&Òét‰T__Ï`06lØ€.qÁápN:uáƒñòåK‰ôæÍ4=..îĉ,ëÁƒÎÎÎc»NÀ³gÏV¬XA£ÑZZZH$Ò'Êúõ뫪ª$UÓ¡DEE}¼N ª®®nÙ²e¯^½] Ÿòûï¿ïÙ³‡÷°~Îyº}ûö'OžŒ¢ÃŒIï+è%±¡¡ÁÄĤ¶¶]ô¥¶¶öÇ==ù/¥súôé[·nq8œ{÷î™™™½~ýz%©­­µ¶¶®««c2™EEE.ûÿ¦ÖÖV++«7oÞÐh´uëÖ•””Àâ%àGXuæ{},,,¤ÑhÜ—íííÅÅÅ ,´··?{ö,š^\\lff6eÊ ãêꊮ‡† ˆ‰‰ÉêÕ«1Œ¢¢¢‘‘w˜-::ÚÑÑQHHˆH$ööö¾zõj Ëœ••µvíZ,+##ãèèÈýYÿäÉ“ 6LŸ>ÝÅÅe˜ãIª¦£¸Ýæïïïëë‹Åb?¹ñ‡>lhhH$ƒ‚‚x—£“vtt®\¹òÁƒ£kÞSîÇyyyÜÅ™$%%õôôÄÄĆ_©ØØXggg555nJWW×üù󃂂6nܨ¥¥….¤Ë¿Y°X,ƒ‘àŽÕ¡cÏ"""Ã)ÆHO >wxÅÅÅEDDDEEÅÅŹÌš5KAAA@@`˜zд0999...x<~ÕªUT*•›žžž¾páBQQQtýåOŸ—””¼{÷nÀ*ÕCu$>£†¶¶¶&&&çΣÓé£ë0cÒ{Çœ¼¼¼™™º÷Áƒ•””¸oÍ™3ÇÑÑñ“9dffþõ×_ÑÑÑ“'Oæ¿eyyùºuëfÍšµcÇŽãÇOž<977÷Ì™3¾¾¾ÊÊʺººnnnqqq_ëK'77×ÁÁaÒ¤Iuuu¢¢¢uuu0,àæõ^kk«¶¶6ú&!!Áf³ÑàòÍ›7ÜKÞ¤I“ª««Ñ¿µµµÑÐíÙ³gÚÚÚèw…BáÞ¯TWWÛ{%/_¾ä^Cååå_¿~Þ 9zô¨OIII@@@\\Ü'¿®ÐKù¬Y³Ö®][SSƒ¦ US>.\¸0þüÅ‹óÞ‹ÌÉÉQRRBä“ÄÅÅœœ²²²òòòZ[[srrx/µ¶¶¶úúú¼÷(‡ŠÝ©¿¿¿Ann.™L )++ió~Î1½zõªÁèŽõëׯ“’’ìììxÇûöm—ëׯS©Ôøøx´eêÔ©æææŠŠŠ ]ÿ÷KŸC±´´¬®®VPP––ÖÑÑÁãñ£(ÌP5iaðx|``àÓ§O}}}y×/177ÏÈÈ Óé)))ñññh “ÉôóóÛ»wï€ØwÐŽ4”Û·ogeeEEEeddLž<9<<| /_úŠôÉ T*5))iúôéèqáí® æçŸæŸCtt´™™Ù¦M›¤¤¤øoY__ÿûï¿:tèáÇnnnûöí;v옡¡aJJʯ¿þÊÝlÆŒù<~!222ñññ±±±8¢ ðƒøN-,..vqqA¯¶FFFãÆsuuݹsçp>ûñI~~þ©S§BCC]#k˜*£ÃÍœB¡rG¹h4š¸¸¸¾¾>ÿØA99¹êêj …‚Á`FZrkkk===%%¥>lذA^^^UU•F£ÄÆÆ³]]])))999ÂÂÂt:]KK‹ûí©¤¤$ ð×_¥¤¤,]ºt¨LøìtçÎhSÈÈÈxxx$''ÿöÛo£;Ö#=¦õõõÂÂÂòòò£;¾>>>ŽËH577'%%ÕÔÔL˜0!888==ÝÊÊê‹öF>îÝ»‡ÃáÊËËétúîÝ»­¬¬¦Nú%j4œÂÔÔÔDGGWWW+))rÓ===Ïž=‹>±sçNIII>™\»vÍÜÜ|Ê”)MMM£n™þùçàÁƒè9µdÉ’/w8¾èi###111}}ý°°°_~ùet™`0˜òòòýû÷ËÈÈð?soݺµ~ýzA455CBB¾J­‡shòóó+++!ª?ˆïdôQWW—J¥R©TSSÓÜÜ\*•ŠÆŽÒÒÒOŸ>E§Ovvv Š‹‹£¿˜ëëë¹#***ܬ’““Ï;wþüyî¥aÞ¼yÜß÷•••Ü·Æ„¢¢â›7oпÐÁ†_~ùÅËË«ø*++;Æ?aaaMMM ´À|j:(§®®ŽÁ`dddæÎ‹Ž÷”••566âñø7n|ræÊ®]»´µµcbbmmmÿïÇŠ°°¶¶öøñãÅÅÅçÎËÔÏNyG;øÕ Ú¼£>¦ùùùË–-ÝîèèÈÎÎ^³f ?tèБ#G†9c€Ç›ššN›6MJJjéÒ¥YYY£Èd§Æ (Š´´´’’’••oÐöù5QaJKK£££÷ïߟ™™9 ‹b±Ø½{÷fdd8;;߿ʔ)|ò¹~ý:™LÆãñ¡¡¡ååå|:Ò0£½ñãÇáÅáK_‘¸£ŒO<ÏÍÍ-)) þ0óÇÏ®¬X±'>tèЀª0`cAAAÞ{hy­¬¬ž?Î{èü´ô™¡¦ÒõtÍ0Ó±X,ƒÁðòò"“Éx÷îÝçì¿ ’’’B¡p8œ+W®xxxpÃÍôôôÆÆÆ¾¾¾¨¨(KKKô< ÉÍÍ Çáp%%%èÃ=‚¸¸¸ÄÆÆ²Ù좢"þ_?#ejjzáÂ…îîîÖÖÖ¸¸8ôƨ‰‰IzzzYY‡ÃéîîNMMMMMå“ImmmLLLWW“ɼs烑““ª¦CéîînjjB'ˆ$%%͘1A}}}êÿXZZ~<#›‡Ã¹{÷®††ÆøñãŸ?~õêUî[/^|úô)›ÍniiIHHà>M8(>;=qâ:‹¢½½ýܹsžQNóŽú˜&''“H¤Ñè‰'rktèÐ!ŸÑEiiiMMMt:===H$~éSƒÿ/·´´´ÎÎÎÖÖÖ›7orGšÇ¤F#*ÌË—/•••ååå FLL ï[ýýýl6»²²rõêÕ'Ožä?ú{ùòeôÅÅŹ»»sk4TG”³³shhhWW›Í¾uëÖ€ò|æÅáK_‘ùðá \]]?ù„ Û·oGŸ7ýø-UUÕÉ“'?yò„÷£¦¦&ïþ… ^¸p¡ººº¯¯¯´´tË–-hº§§çáÇëëëÙlviiixx8ïÃît¨}¼Sþéñññ***¼÷Ê•••Ÿ={6uêÔØØØúúzÞ§&FºSþK¾³™×d2¹³³“7¥££c×®] ƒ›^QQ±råJîDcô×ü¯¿þJ ‚¢¢"÷-&“B"‘<<ø¶¿¨„…?¹àßk^„ÂGá#;]]]½½½ÃßžÃá XÈa µ¶¶~~&L&³³³ó)ÌH›|Q_´÷ð…P(”žžháãwåýû÷{÷îÕÓÓ;yò$o P]]íììlbb’œœÌMììì Ô××755MOO禳X¬ÐÐP‰äééÉ]+l̵µµÍš5ËÍÍ }™——çå奠 0¢= 544ð¯éP­iBBÂÊ•+ÍÌ̆YŒAwZ[[{ôèQ--­üüüQ»Q&;;ÛÌÌÌÎή´´”›8ºæý8ÜIII±´´\¸páõëׇó‘þþþ7n888>zôM¬¯¯ß²e‹ŽŽŽ¯¯oGGÇÿÇÞ™B¹õÿ™1¥k‹W&¹Ö)ÃAÈdÉ`Bº‘,iºäª(iQº…"·Þ¨î’Òrã-’nJ½RTD¶¸–”5dß—Ù~<¿÷ùÍ™a¦q[Þóùkæ;ÏsÎù~Ïö}ÎsÎ|ù3/'My…§ÃSCšÒ2...úúú|æãÇûöíÓÕÕÝ»wo[[Û§tÆââb___ƒ?þøƒ?ó>þÜÝÝ}éÒ¥üi4::zæÌàææÆšé?3"M`||üìÙ³†††>>>H(Åž±±1kkkssó/GÓÎÎNOOOÖZ`¾P¾±¨3Çïëëc•ìܹ3++‹N§ÇÅÅ?‰@ FGG½½½á˜(pÌ•P©Ôîînggg$FErrò‰'h4ÚË—/ÝÝÝ'„ UUU^^^Hì–ÆÆF''§ÆÆÆiÞþîÝ;GGG[[[äNšr‚­¦T*5''çÝ»wx<~:Åà”iMMÍ›7o(Ê_ý5tØÖ¯…©¬¬\¿~ýàà`{{;@èîîæÛ¼“yò䉟Ÿ____ww·¯¯ï“'O¦¼%"""$$¤¥¥…Á`ÐétX#ccãòòòñññ{÷îùùùñg^Nšò¯ †§†4e —ýû÷³V+O…¡Óék×®}ñâÅøøø³gÏV¯^Íw?ÍÎÎvtt¬®®¦ÓéHžÌK§Ó£££[[[i4Zff¦æ=uêÔ¥K—FGGëëë Bkkë?<"±síÚ5*•úìٳ͛7Æq¾³³ÓÌÌì‹Ò4//ï?ÿùÏtFàÛˆ:ó­­>æçç"_»ººŠŠŠ,,,Ðh´³³óÙ³gayQQ‰DRTTöððÈÈÈ€åzzzVVV FRRRQQ‰jíÚ5777!!!ƒ±±±ÆÆF–¹««+$$ÄÀÀÀÛÛ»¸¸‘ëëë+(( P¨é¯„…‡‡‡„„ˆŠŠ"BNšr‚­¦ ÆÄÄDZZzš%ᔩšš‡›5kÖ4Ͷîx-ÌÇ===EEE±X¬››¬–'ó2™Ì»wï:88À+[ïÞ½ƒåŠŠŠáááRRRÖÖÖÕÕÕÜÓ),,lnn–““C¡Ph4N‚ 111 #!!1e”aNæå¤)'.\¸`gg§¥¥µoß¾®®.þLMM¿¿¿ŽŽŽ¥¥å_ýŽ!q_i>sæ Ô˜Â0™Ì°°0CCÃY³f744ÀC§ºãD__ß‘#G._¾¼hÑ"4Á`ø0/öññ‘••RQQAÞlòj^"‘¸iÓ&aaa%%%SSSä­ÂŒŽHla0gΜqvvîêêº{÷îçêà7E›7o®¯¯ÿìš._¾|‚(O /¯¿,:::´´´`ABB‚Á`À3Jkk«²²2|¬¬lmm-ë] ÅÆÆFBBB[[ž~²³³çÏŸÿª®®.À·Eããã>>>vvv/^¼ ‡ >xüø±²²²––«»¦“'`hÊS¦¼Ö¯Ô××ËÉÉÁŸååå[ZZøHäúõ륥¥.\ÈÏÏß²e‹¿¿{{;A***bbbpi/^¼heeÅ=²²²¥K—--­°°öBCCŸ?^YYõéM©)F{ñâÅÖ­[­­­‘ÕG^Íõñãǘ˜‰´uëÖŽŽ¶.þ”éüý÷ß•••–––Ÿ^wL&3..®¼¼|ß¾}Ó©;¶Ï-‡Æáp‰‰‰t:uï#¯…QUU ºp᧴Ƽ¼¼°°°ØØØ9sæ|®.Æd21Lss³ŒŒÌÊ•+?{_611±²²B¡PêêêOž<ùÂ5ý¢†A¸ÿ]]ÝŠŠŠŠŠ kk뜜œŠŠŠ½{÷B$##S^^¯çõ÷÷£Ñhx­HVV¶¡¡™ÑUUUYSÖÕÕ%“Éð«% eff†<ßWWWc±Øòi„……ùK¤¬¬¬¹¹yÅŠ8.##ãäÉ“È M'—D šò”)'8Õ¯())!›ß›ššõžPSS;þ|Ñijjúé§Ÿ//¯ˆˆx­š;ÊÊÊ‘‘‘K–,‘‘‘±µµ-**‚K…B¡ŒŒŒÄÅÅíííããã‘]<™—'M»»»)Jff¦¿¿?u700àëëëîî~÷îÝøøxļ6¤'Ožiiiéëë¿~ý OÇkC¢R©¡¡¡ÝÝÝG={ö”uÇ–ï¿ÿÞÏÏÏÒÒR\\ÜÆÆæñãÇŸÒäää\\\***à? à£k¤¥¥;w.>>±áLH0ð~Jäëœ9s:;;—,YB LLLàÚŸð@ÂéAeÊÄùHYdë™}J¦|k:#ÜÇσ´´4ÏÎÎf2™©©©Û·oGÜÍû÷ï777_¹rÅÎΖ§¦¦ÖÖÖ2™Ì?þõ×_K—.…åd29))‰Á`Κ5KQQQP%ÄápµµµEEEL&³««ëرcü½¼^¾|yű³³Û³gwM9!MyÍ”§ºãkkëK—. wtt$''󑈇‡Çï¿ÿO]]]±±±•••åääüúë¯ñññêêêYYYÜÓ!‘H·oßnkkxôèÜÀæÏŸßÓÓSRRB¥R³²²ìíí‘ýv<™—'M«««UUU±Xl{{{bb"u×ÑÑ!$$´páB4ýäÉ“gÏžñ×¶mÛ7ÝW¯^áñxggg> 300°cÇyyùýû÷c0˜»wïÂÿÅ©î8¡¡¡ÑÓÓSVV666– ;¼š·¾¾>--mxx˜J¥æççC$%%Å«F #&&&'''..NRR²¸¸¸ªªj¦G$˜¾¾> d'®¨¨è¼yó:::¼½½‹ŠŠ>|øï €¹~ýºªªêäí}»ví266ž°[`râÈ3ð’%Kâââ&?³•sâ3åOÓy€/—oìä5…Béïïg•ôôôGDDŒŽŽ²žqvuu%‰7oÞD„eeeþþþx<ÞÞÞžõt0•J‰‰!Û·ooool™;::‚‚‚ŒŒŒ¼¼¼¥¥¥£¢¢˜LæŽ;ðxüܹs555 ‡¦LjddÄÖÖvîܹ»víâ®)'ØjÚÓÓC$üñG<ïêê æ~„|r¦ x<^^^^UUÇ?}ú”{"lëŽÂdff’H$GGÇ’’DÈ«yËËËùå__ßÔÔÔ±±1&“iee¥¢¢‚ÇãñxüâÅ‹¦´pyy¹‹‹‹‰‰IJJ "¬¯¯ß¶m?tèÐtNhrªS¶š²¥¹¹yË–-ÚÚÚd2ùÌ™3X,ÞwËkƒIJJ"fff'Ož\³f‘‘Qgg']¦¦¦FOOODDäúõë|´Þììl‚ðÿEZZº¦¦†KÝqï’»víÒÓÓ;~üøÈÈæ¾|ù2‰DZ¶lÙ¡C‡X-0}àõE X#%%%ä–‘˜Læàà ““Óž={XÏt'%%9rdxx¸©©éñãǬ×ß»wÏÈÈèõë×Ò ·±±éêêš2qØ2!))irkg•3Œ7ŠˆˆP(&“¹{÷n‚˜)šN侓ר=~Û")1#ÃC]OIåòZ'??ßÚÚ8Üð?N¿råÊíÛ·ÕÕÕ'ÿC'ÐøÚyðà§_%%%a_±¥©>6&ì€)Ú¼yóæÍ›¦-÷ÜGpÀ}÷ñ Nñ þÇ#g|"T*þ?ç/¡0Ÿ…±±1МÀ ñÍÓÙÙÉýOÚp¿Pz{{ Ož<É:g×ÖÖº»»‰Ä´´´É~‰’’RXX"¡Ñh±±±ÁÏω&(úûû###—/_nmm}ÿþ}ÖŸètzFF†‹‹ËŠ+^½z%pMÙz6¿ýö›®®®——Wmm-RŒ””WWW‰4M¥¼¼¼B||<ƒÁ€…uuuGÕÔÔÌËË›N"eeed2ÙÀÀ€B¡ŒŽŽò]˜¬¬,‰´nݺÒÒR¾ëT æÍÍÍõ÷÷WPPøÄVÄ)S¶šÎ¨F1ïøøø–/_þüùó÷ïßÛÙÙýôÓOÜŸ1>=Ó±±1 …Ãáp8œ––Ö›7oø3#ÌóçÏ…„„233Y»€¯¯¯ŽŽNHHHOOƒ@iié¼yóàBŽ«Œ IDAT‰Ä ÑóBqq±¯¯¯ÛèÞŸÈíÛ·wíÚõ Ì#cccÖÖÖ¢¢¢pkñõõ­¯¯‡òôôœ7oÞõë×›šš´´´”••Ḕÿ@ÝŸ“o,êÌñãÇûúúX%;wîÌÊÊ¢ÓéqqqçÏŸ‡…CCC¡¡¡attÔÛÛ»  €õ–ƒîß¿ÿÈ‘#ˆ$99ùĉ4íåË—îîîâ|"¯^½zðà•Jíîîvvv.++C~Šˆˆ iiia0SÆVáCÓÉ¥¦¦ŽÃ!@†‡‡á999ïÞ½ÃãñÓшJ¥‰Äׯ_ ]¼x‰èPSSóæÍ …Âчííí&&&###çÏŸ?uê’8O…©¬¬\¿~ýàà`{{;@@bºðZ§1oAAAcc£““Scc#ß †S¦œ4QbÞ§OŸ†……Ñét:~àÀçÏŸS©Ô™Îttt‹ÅN?qîÑžH$’¿¿?Ò°©Tª±±qyyùøøø½{÷üüüøJJJ¦ʈo²³³«««ét:w›óǵkל¿€fffL&“N§Ãá‹^¼xLEEEøgêø¼Qg¾µÕÇüüüÁÁAäkWWWQQ‘……vvv>{ö,,/**"‘HŠŠŠÂ¬ÏâÝÝÝkÖ¬aMöÚµknnnBBBccc,³žžž••ƒ‘””TTT¤Ñh°¼°°°¹¹988XNN…B¡ÑÜ*‹MÙB§ÓÅÅÅ…„„DEE…„„`!ƒ111‘––ž¦FL&SGGGDDÄÉÉéäÉ“°\MM ‡ÃÍš5k:‰Ìž=;!!AAAaΜ9–––Èâ+¯…yøð¡§§§¨¨(‹ussC‚ÕòT§‚2¯¾¾¾‚‚ …b2™Ì .ØÙÙiiiíÛ·¯««‹{"œ2å¤éŒjôéæ½|ù²››ÛÙ³gÃÃÜœbbb6lØPXX8ÓuÊkâ\HJJrww_´hkB$&&†Á`$$$&ÄYžþ 0£ôõõ9räòåË‹-B£ÑÜ#­ó‡¨¨è¿þõ¯oí­««+**:!¬6^^;ttthiiÁ³µ„„ƒÁ€ËÖÖVeeeøYYYä--•J=räH`` ë?£ÏŸ?þª®®.ð÷×Q( mmmäÕíÒ¥K<èààpïÞ=Ájʉ½{÷îÞ½[IIéû￈ˆøî»ïøÐEFFFHHèÕ«WQQQ………|lv”””TPP€+%::zÓ¦Mü¶¾¾^NNþ,//ßÒÒÂG ʼlA¡P––– ¥¥¥ÆÆÆ±±±Ü¯ç”)[MgZ£O7¯‡‡G|||PPPPPÐÍ›7Édò;w gºN!ôôôÔÑÑ êííåÃŒµ´´Ü¾}{ݺu¬ÂY³fQ(EEEww÷   þ‚rrr–/_~áÂ…)ÝPž¨««333‹···‰‰ø°&""2wîÜolZ}ðà°°ð‚ `Ill¬®®®®®î† X¯œ¹º€û(ŠŠŠà-&<055Åáp‘‘‘ÓŸ¼‘Ï·nݲ±±QTTœæõdëÖ­Gmjjª©©A¼„àà`2™|þüù´´4îë1¼jʉ+W®TTT¼~ý:$$„¿ƒÁ\¼xñêÕ«?ÿü³–––±±±˜˜eÚ½{·®®®@â­s²€@ê”ïDh4Ú‹/¶nÝjmm˜˜8åêã«ÑŒFà™ þûßÿ.((ÀãñÇŽã¯äAAA¬B&“úüùóÊÊʈˆˆ¨¨(þw¥‡¶µµ¥§§ öéúðáÃ8.11‘N§ÏÄÞÇýë_ˆCÿ PPPod|ùòe||<²^»uëÖ¢¢¢¢¢¢ÄÄDäâ­;¸‚AWW·¢¢¢¢¢ÂÚÚ:''§¢¢bïÞ½ð2Xyy9ü"©¿¿FÃ~Œ¬¬,¼»öÒTUUáÏwîÜ¡P(8ÎÅÅ%66ÞMB¡ÌÌÌ•Œêêj,+p„……uuuÉd2òºPYY922rÉ’%222¶¶¶EEE\nçUS.îãš5k$$$tttÔÔÔø[Nƒ HAA!**êæÍ› ,Ð××çþæžžž«V­ruuåÛ°JJJ­­­ð禦&xa‰×:”yÙ’˜˜ØÝÝM¡P233ýýý§¼žS¦l5ibÞÏR§ÁkÖ¬YááÇ|˜±§§'++ëçŸÆáp‡ ƒOH455¡P(###qqq{{ûøøøé¼ž<`0---qqq111“²²2šñûï¿÷óó³´´·±±yüø1믜’sR„­\__ß××w²\ ‰ó*ÿôL—-[VQQ‘››"##3åSôÌÕÜÇ™EZZÇggg3™ÌÔÔÔíÛ·#îæýû÷›››ÇÇǯ\¹bggËÿüóOØ MNNÞºu«¦¦&,'“ÉIII £°°pÖ¬YÜ—'y%55µ¶¶–Éd~üøñ¯¿þZºt),'‘H·oßnkkxôè"ˆ¦œX½zõƒÆÆÆjjjJKKùÖ”N§ŽŽ>{ö, àÀ|¤P__¿qãFƒÁ÷Òˆµµõ¥K—†‡‡;::’““ù¨SA™—-ÕÕÕªªªX,¶½½uõ‚ËÃÛL9i:£ ļŸ¥N³³³=zD¥Rnܸáîî·¥¤¤*þËáǃ‚‚ÄÅÅ!š?~OOOII •JÍÊʲ··ç¾³Ó põêÕòòrƒÑÞÞž’’bjj*@3jhhôôô”••egg›˜˜ ?õõõYXXxxxLxåZVV¶dÉ’¸¸¸ I]¿~]UUuò>Ñ—/_&$$ ÿ½À_â¼fºk×.ccã •éô™Ñº>?ߨÉk …ÒßßÏ*ééé 066ŽˆˆEäUUU®®®D"ñæÍ›IOO_´h‘¼¼ü›7os”111aûöíííí‚-sYY™¿¿?···Ÿp$¹¼¼ÜÅÅÅÄÄ$%%eÊtøÐt2ýýýááázzzUUUHÊD"ñÇÁãñ®®®Ü{xx„£G¶¶¶"ò„„<///¯ªªŠÇãŸ>}Ê%‘ÈÈH,‹Çãñx¼¶¶6rH–×ÂÀ§ÉH$’££cII ëñpžêT æÝ±cŸ;w®¦¦&@øðá“ÉlnnÞ²e‹¶¶6™L>sæ ‹çž§LÙj:£}ºyÿýwUUUyyùC‡ÙÚÚJKK/^¼øåË—3]§ýýýçÎ377'QQQ###ü™&$$D^^ž@ ãO}}ý¶mÛðxü¡C‡¦<¾Íihhh600°±±IOOø€ÙÑѱk×.==½ãdzZ`ppÐÉÉiÏž=N¯WUUä¿îÝ»gddôúõë òèèèÕ«WÃàÀwâ¼fnccÓÕÕ%ÀLGGGmllà1ÇÓÓI¤³³ÓÈÈhÁ‚ð÷àñx,{ïÞ½ î€Ï{òµÇo[$%fdx‚ ë)©?ýô'G3??_ ûÏ_<000àô«¤¤$ì+¶4ÕÇÆDƒ¨3î#¸à>€ûî#¸€™†SP„¯&“9áƒ?W"œÌ;00066öÏæË1/૾½A÷ñ‹ ··700ÐÐÐðäÉ“¬ŽBmm­»»;‘HLKKC„¥¥¥óæÍƒÃg‰D8þA4-66–@ øùù!QÑKGG‡’’RXXß)üòË/jjjpá¯_¿ŽÈ¼¼¼B||ü”ÞÆû÷ï÷ìÙ£££C&“+**yYY™L600 P(£££Ó)NwqqÑ××G$ýýý‘‘‘Ë—/·¶¶¾ÿþ4õŠŽŽjjjB$ƒƒƒ¡¡¡úúúAAAHñjÞÜÜ\ž*traxâêÕ« píÙ³‡µŽ|}}uttBBBzzzø3¯ º¯dee‘H¤uëÖ•––"B^» ÛþÈEÎN™ò¡iZZš¹¹ùÒ¥Kz{{gzäáopxþü¹Pff¦¢ÀÀ@QQÑ»wïB”——§¦¦&))™——wæÌ uöìYxœ”””$‰T*•ÓàÀd2ïß¿¿~ýzƒƒFGGÃ5rõêU7þ|¸#<}ú‚ ááakkkeee õèÑ#8…ááá•+WŠŠŠ¾{÷‚ ˜˜--­ÖÖÖõë×‹ŠŠ@B¡`#“H$999…7~™^upp°¨¨(‡[ºt©¿¿ss3ðB_+ßXÔ™ãÇ÷õõ±JvîÜ™••E§ÓãââΟ? ‡††BCCÃè訷·wAA,/)) ˜œlrrò‰'h4ÚË—/ÝÝÝ'Ä-Ü¿ÿ‘#GøNÁËË«¦¦f‚J¥‰Äׯ_ ]¼xqrp… ܸq£¼¼œN§×ÕÕikk 1™Ìööv“ÆÆÆ‘‘‘óçÏŸ:uj:åIOOß¿?G$¯^½zðà•Jíîîvvv.++›2‘wïÞ9::ÚÚÚ666²F•HHHÉÍÍõóóãϼNNN¬)óQž¸råÊäP.T*ÕØØ¸¼¼|||üÞ½{ÓÔh²yy…m×à•ÊÊÊõë×¶··$¼ O]†Sä$ç§LyÕ´¡¡ÁÖÖŽÄC¥Rh^^5â28ŒŒŒH$ÿ ¡ª>###‚à´ªªjÛ¶mH1nݺGV433ëííå28ܺukß¾}ÝÝÝcccyyy"""HgÏž}ðàÁ„|/^¼H&“}}} ìqnÙ²®Ê”””„„8`’‰‰Iee%“ÉÌÈÈðõõEBOÅÇǧ¥¥}±3l:øsMM Ìøê¢Î|k«ùùùƒƒƒÈ×®®®¢¢" 4íìì ?:CTTTD"‘………=<<222¸'{íÚ5777!!!ƒ±±±ÆÆFÁ»¸¸¸»»{Íš5¬Â’’ooï¥K—’Éä¼¼<¾5™L¦ŽŽŽˆˆˆ““ÓÉ“'¹_ïè訩©‰F£eee¥¤¤àÕÊÙ³g'$$(((Ì™3ÇÒÒòÕ«WÓYz9s振¯/«POOÏÊÊ ƒÁHJJ***Òh´)_Ά‡‡‡„„ˆŠŠ²Êïß¿oii9gÎ8²í”klÍ«¯¯¯  €B¡¦iI¶…:wî‘H\±bÅÉ“'ù[¦‚—IÄÄÄ0Œ„„Ä„˜¼Ó7/•J½víÚªU« ÃÃÃ÷îÝË%N]£¯¯/44tÅŠQQQSÖÑÇ===EEE±X¬››€˜§.é? ¤ŸrÒ”ÉÉɹ¹¹x<‡Ã!]O æåU#N­‚ ¤¤$ww÷E‹ |ˆˆ¸|ùòùîÝ»#""ÚÚÚNž`[˜ÌŸ?ÿÎ;YYYúúú;vì˜Òù»téÒÊ•+W­Z• KfÍšE¡PTTTÝÝ݃‚‚ø3oLL NOKKËÉÉÁápEEE|t 11± 6<|ø077·££ãñãÇÜKR__/''–——‡ë‚×.é?ré§l½p¶™rÒ”...nnn¦¦¦4/Oqi½---·oß^·nÝ œ...YYYõõõ¬Âýë_!!!îîƒˆ'7ypèèè–––@î]½zµ””—+++çλpá 6äääü¿) Þ½{wXXØ„]K—.uww‡÷HKK¥3”ššZyy9pD_#˜oC¢¢"2™ Of¦¦¦³gÏöððà¾<€À:.ãp¸‹/Â[pNŸ>žž¾víZ.× „[·nÙØØ(**~øðfggççç#!ÈÅÄÄ–/_ÎÝw„ hÁ‚µµµd29;;[XXƒÁ\¼xñßÿþwkkëÏ?ÿlll {„\øî»ïÂÂÂ^¿~}áÂd±mhh(00Þ¹È=…¿ÿþ»²²rß¾}lçé­[·„¸¸¸ššuuuN‰ FDD$%%MþÉÏÏïìÙ³ð{ä½{÷rŸ<Øš—Wئ··÷ìٳϞ= ‡%uuuõõõ .ä”Κ5k •••ûúú¼½½åååÕÔÔ˜LfhhèóçÏ555333£¢¢¸oekÞñññ¸¸¸òòrxæ§Ÿ~úñÇùÐt`` ==ýñãÇ fhhHSSsú÷rêJ‰Ì®®®D"‘õ$lCCCpp° «»F¥RcbbÂöíÛ¹{`|“žž¾hÑ"yyù7oÞÀ’öööC‡»ººž;w®««‹Ëí4---míÚµzzzû÷ïGF±ññqpôèQx´åƒÁÈÌÌܰaƒ¶¶¶——R’ÈÈH,‹Çãñx¼¶¶6‹ŽF555zzz"""ׯ_‡%eeeþþþx<ÞÞÞ~šsÞÈȈ­­íܹswíÚ…Ïœ9c``°}ûöéœÝædÞ;vàñø¹sçjjj„>ðQƒqïÞ=GGG33³äääpOáÕ«WÞÞÞÚÚÚd2™µðõõõÛ¶mÃãñ‡šæt2Ù¼###qqqD"ÑØØ800u¶f Û®QPP`oo¿lÙ²½{÷8p@EEeÊÓÁ™™™$ÉÑѱ¤¤„ï.ö?r‘³…S¦œ¶œ:uJCCCZZÇ/[¶¬ªªJ€æåU#N­&$$D^^ž@ Lô>…;wˆhkkà ž;wñ¤ à.£¡¡6åàPVV¶eË==½mÛ¶!­ýÚµkx<^^^^UUÇ?{ö¬±±QCCCIIéÒ¥KL&³°°pñâÅÒÒÒiii‡±±±¤Óéîîî ° ŽÅbá!úÔ©SyxxŒŽŽÚÛÛ+))©¨¨ÀåQQQAÜÇÁÁA''§={öLx’©ªª"“ÿ’‚“üÞ½{FFF¯_¿žütacc3a”žœéáÇEDDðx¼žžÞöíÛ€ËøJÝGÔ¿m‘”˜‘á!‚®§¤"›í&“ŸŸ?å¦7ÀWǃ ¸l¾‚}Å–¦úؘhuÀÀ}÷ÜGpÀ}÷0ÓÀÿ ö‰‰ÀFø…ÀŸž•J2¬9ð w&“ÙÕÕŒ÷ñ“èíí 444FN¤¥¥™››/]ºÔÁÁ¡··—õ§‚‚…«W¯ j º{÷îüùó•••áþõÃ?ìÞ½–/Y²…Báp¸çÏŸ#×>|ø‡~˜7ož¡¡á”}ãÆ  ¥¥¥õöíÛœœøÆüü|.ý‘mrê2½½½ÑÑÑfffÑÑÑ`vf–o,êÌñãÇûúúX%;wîÌÊÊ¢ÓéqqqHª¡¡!ÐÐÐ0::êííÍW#;;ÛÑѱººšN§#qÿ’““Oœ8A£Ñ^¾|éîî>A <¸ÿ~Ö¸dW®\™~\ ˜wïÞ9::ÚÚÚòˆoBl‰äïïÏw0´'Ožøùùõõõuwwûúú>yò p·~ýúÁÁÁööv0ex//¯šššéË9zyðà•JíîîvvvF¢_ܸq£¼¼œN§×ÕÕikks@G§Ó£££[[[i4Zff&`KCb ÛL©TjNNλwïX#r¡½½ýòåËCCC###‘‘‘p78Í›7o(Ê4+Žm×à•S§N]ºtitt´¾¾‰#Çk—áÔ`x5/§LyÒ”S+åµõò:òp¢¡¡ÁÖÖŽ[ƒŒH¬¤¤¤ ±UÂï¿ÿþèÑ#$r cixxXEEeòõEEE˜fâFFFpøŠ ‰sêlë”S—éìì|ñâÅãÇÙxŒ:ó­­>æçç"_»ººŠŠŠ,,,Ðh´³³óÙ³gayQQ‰DRTT{{åØ IDATöððÈÈÈ€å}}}G޹|ùò¢E‹Ðh4ƒå×®]sss200ƒCÁ âââîîî5kÖ|J"pà¬QQQVyNNŽ«««ŽŽÎŽ;¼½½‡††¸§“””äîî¾hÑ"VáÛ·oýüütttœ÷ïßÏ}õEQQ1<<\BBBJJÊÚÚººº–?|øÐÓÓSTT‹Åº¹¹±®aÌzzzVVV FRRRQQ‘F£ÁrGGGMMM4-+++%%Åý?öññ‘••RQQáÞ8Á6S cbb"--=M°XìÏ?ÿ,""2gÎeeåññqX¯ÈΚ5k:‰pê}}}¡¡¡+V¬000ˆŠŠBÌÅ "‘¸iÓ&aaa%%%SSSdÙ›§.éÁðj^¶™rÒ”œZ)O­—ב‡ÉÉɹ¹¹x<‡Ã!ëÊUUUÞÞÞ†††‡úðáÃLtœ¾¾¾«W¯ª©©mݺõè§œú#Û:åÔe¤¥¥ EDDÀÂ^^êa--- A„„ƒÁ€ËÖÖVeeeøYYÙÚÚZäõŸ™™Y||¼½½}LL <1ÃK’óçχ¯QWWìûk*•zäÈ‘ÀÀ@¸œ¬\ºtiåÊ•«V­ÊÎΞ2Ç+++kii± sssÓÓÓÏ;WXXèíí}ÿþý.‰´´´Ü¾}{ݺu¬Â¶¶¶ýû÷ïÙ³çõë× åï¿ÿf}{;111Øþ/^´²²‚åõõõrrrðgyyù–––)• Ö××÷ôô|ûöít䜠P(666ÚÚÚˆpddÄÏÏÏÜÜ< .0wÞ¾}»yóæµk×ÃN ‰ ¼fʉ¸ºº^»vmýúõìbbb6lxøðannnGGÇãǹ§£¥¥…F£!*))©¬¬„›¯]†Sƒáɼœ2å¤)'8µRžZ/¯#'\\\222ÜÜÜ******LMM!jnn zþü¹‹‹‹¿¿¿ÀGέ[·._¾<++kΜ9ž$gŽÉ]c¦Ç^À7˜oC¢¢"2™ ñ¦¦¦³gÏöððØ»wïtîeuÚ:::>üðáÃÍ›7_¹rå?þðòòâr½@¸uë–¢¢â„U„5kÖ*++÷õõy{{ËËË«©©qJdpp0"""))iòR¢¿¿¿¤¤$<Ó?}ú‹Ù$,,<Á1ݰaƒ’’<çÅÇÇÏ™3gJ½ššš|}}CCC‘ù’W3Â^Ú‚ jkkÉdrvv6\0NrîÓ!@ˆ‹‹«©©QWW‡…ß}÷]XXØëׯ/\¸`bb2aÕv2ªªªaaaOŸ>½páBxx8 ƒ×L9aii©¢¢’ššúèÑ£O\·fe`` ==ýñãÇ fhhHSSs:wååå:u*66–mئe>½Á¼ŸrJdFŸ’‡zxx(((@¤©©I¡P>¢ÆÆÆjiiÁ|tt”mµëèèL~®­­ÕÐÐà#Ó)»†ÀÇ^À7ßÈ꣮®.ütnmm““SQQûŽ222åååð âþþ~4 ?ÔÊÊÊ644 +ªªªðçï¿ÿÞÏÏÏÒÒR\\ÜÆÆ^zA¡PfffÈSouu5‹`áïܹC¡Pp8œ‹‹Kllì›7o`¹¤¤¤ººº°°0‹511á¾PQVVÖÜܼbÅ —‘‘qòäIX>>>/!Ë<\†àžžž¬¬¬Ÿþ‡Ã>|8,, ^ª¤Ñh¬‰ÈÈȈ‹‹sWêÍ›7^^^¬«}JJJ­­­ˆ¯€¬åpBAAAAAƒÁ,Y²DBB©Nr. ëêê’Éä ¯ çÎknnnddôêÕ«éT–œœœ‹‹KEE|ä“SC⯙²ïºhô¢E‹|||bbbø¸S×ÐÒÒJLL¼qㆃƒÃt’JKK;wî\||<Ò/øè2l Oæå”)'M9Á©•òÔzyy>Åõüî»ïfbPÅb±§Nb2™¦¦¦l·vH¤ÉçêëëOŸ>ͽ!ï.>~ü8áô„®!رWPÿ&ÁiG[9§L§Ü÷ñs"--Çã³³³™LfjjêöíÛwóþýûÍÍÍãããW®\±³³ƒå===eeecccÙÙÙ&&&°œL&'%%1ŒÂÂÂY³f)** °þù'ìû&''oݺ^Žþðá“É|ûöííÛ·Y§ÕÉ,_¾¼â¿ØÙÙ!'µœœâââúûû™LfKKKPPPee%§D¤¤¤D>»‰æææW®\inn†çÂøøø›7or)LNNί¿þ¯®®ÞÑÑ‘••Ë­­­/]º4<<ÜÑÑ‘œœlllÌ%‘ºººÄÄÄ*•úäÉaaá p‘s"55µ¶¶–Éd~üøñ¯¿þZºt)lÞk×®utt0™Ìººº'OžpŸÈëëëÓÒÒ†‡‡©T*|PTJJŠKCb ¯™r"77÷ùóç4mppð¯¿þ277T×`2™OŸ>]¼x±¸¸øßÿͽ–á©1&&&'''..NRR²¸¸¸ªªŠ.éÁðd^N™r8Á©•òÔzyyxÂÊÊ éµµµ3ñòFHHˆÉdä¿À`Ö­[wãÆ *•:44”””D$¹w A½}}}t:ýSÊýúuUUÕÉ;_wíÚellÜÞÞ>LËÊÊ–,Y\ÀWÌ7vòšB¡À®BOOO@@€±±qDD|z¦ªªÊÕÕ•H$N8ÝÜÑѱk×.==½ãÇŒŒÀB*•C ¶oßÞÞÞ>%OOO_´h‘¼¼ü›7o#ÃÞÞÞÚÚÚd29/<å¡i[[Û¹sç"çá³Tzzz›7oþÏþ3cã!!!òòò1æ›7o¼½½õôôþüóOÄ2l±²²RQQÁãñx<~ñâŬ…!‘HŽŽŽ%%%ÜË@£ÑÒÒÒÖ®]«§§·ÿþ¶¶6îrN”••ùûûãñx{{{äH2ƒÁÈÌÌܰaƒ¶¶¶——bsN _¾|™D"-[¶ìСC¬m€SCš §L{zzˆDâ?þ(""‚Çã]]]ét:—tZ[[;flllffvîÜ9¤U'$$àñxyyyUUU<ÿôéSîåaÛ5 ìíí—-[¶wïÞ¨¨¨p9 / ihhÀu­¤¤„§.Ã¥ÁLß¼\2å4p9~ȶ•N¿õò1òp:Ø®¡¡;£Ë–-«ªªBŽoÞ¼ÙØØø×_=uê”’’Ò³gÏ2edd MÇÃO­T*5##þŒÿ/ŽŽ†††.^¼‹ÅÂB ///îýúÊ•+æææ¶¶¶ÈœÂ¥?²­SN]¦¸¸Ç/Z´hÁ‚x<þìÙ³H:ƒƒƒNNN{öìùÄÿ͸wïž‘‘Ñëׯ'ÈÃÃÃmllºººX…œ2­ªª"IIIà¨/àë=yÚã·-’32<AÐõ”ÔŸ~ú‰“£™ŸŸomm n€oŒpúURRö[šêcc¢AÔ÷ÜGpÀ}÷ÜGÀ× “ÉìêêúÆ2…ã¾L*•ÚßßZà¶? ŠÉÁfp¿5z{{ Ož<É:êÕÖÖº»»‰Ä´´4Dhgg§®®ŽÃáp8œœœÜ­[·`9F‹%~~~Ó ‘Ç+YYY$iݺu¥¥¥ˆ×LŸ?îîî¾téÒÀÀ@$,Xooott´™™YttôtJrõêUØHè˜ÁÁÁóçÏ“H$;;;î“ß”™vvvêëëÿòË/\yöìÙüùóá’,Y² ÕM§ÓSRR\]]I$Òt4ª««;zô¨¦¦f^^Þ?Ö8!†ÿɼ¥¥å;w¦lHœ(++#“É ett”?FGGÏœ9C ÜÜÜøn½\4â©0?~Ü·oŸ®®îÞ½{ÛÚÚ¦¬;ž4âÕ¼l3åµ?–––Λ7îD""Št„ŒŒ —+V|JôËé“››ëïﯠ €Tè£G$%%øá‡‚‚‚nÞ¼©   ¬¬Œ°ÒÔÔ¤®®.''AÐßÿ½dÉQQÑÛ·oã¾>¾±¨3Çïëëc•ìܹ3++‹N§ÇÅÅ? „†††ÑÑQooo$®FRRO%000??þœœœ|âÄ öòåKww÷OŒ[0ÊÊÊõë×¶··„îîn>2¥ÓéÑÑÑ­­­4-33ÓÇÇ–wvv¾xñâñãÇGŽ™Na®\¹Â6ÆÈȈ³³sRRRoo/•JåžÈt2­ªªâ¢±±ñÉ“'ðç·oߺ¸¸ Q(rrrÞ½{‡Çã§£QMMÍ›7o( r†?xjHœHCzò䉟Ÿ____ww·¯¯/b%N ‰-ííí&&&###çÏŸ‡£ó¡Ñ©S§.]º4::Z__O Z[[ùД“F<†N§¯]»öÅ‹ãããÏž=[½z5’)ÛºãU#žÌË)S^ûcII k V"""BBBZZZ ÷0E‚¢   ±±ÑÉÉ©±±ž?žuÄ8yòäþ󽃋 Y+ôÉ“''Nœf|Qg¾µÕÇüüüÁÁAäkWWWQQ‘……vvv>{ö,,/**"‘HŠŠŠÂ°ÜÅÅeΜ9 #ñ‘!ºvíš›››ÁØØXcc£ËüðáCOOOQQQ,ëææ†DSå)S4íãã#+++$$¤¢¢222Ë¥¥¥ EDD>± kÖ¬qqq™;w.ƒá~1§L»ººBBB ¼½½‹‹‹¹'¢  `jjŠ,{ ñ0Œ‰‰‰´´ô4K®¦¦†ÃáfÍš5AÞÓÓsìØ1`iiùÛo¿%$$pI„×†Ä ¶uÊd2/\¸`gg§¥¥µoß¾)_k***†‡‡KHHHIIY[[WWWsoHl™={vBB‚‚‚œ9s,--‘å+^5"‰›6mVRR255mjjâ£õrÒˆ§Â0™Ì°°0CCÃY³f744ÀC§ºãU#žÌË)SAõÇÂÂÂæææàà`999 …Fÿ#¹¾¾¾‚‚ …bZZZþùçŸÈÂí­[·ŒŒŒ¸¯:tÈÀÀ€L&_ºtIRR’B¡üï¬×èèè<}ú´§§þzãÆ þâžàåõÌÒÑÑ¡¥¥w žQZ[[•••ákdeekkk'ÜXTT´nÝ:aaaxZÊÎÎF^žª«« öýu}}½œœüY^^¾¥¥…ïLß¾}»yóæµk×ó]žK—.­\¹rÕªUÙÙÙ¬ï­ÄÄÄ~ùåOOÏŠŠ >’÷ññ±³³{ñâEhhh||<“Éœæ½7oÞ466 Í©TêŽ;ÌÍÍŸ>}zóæM›]à i‚öNQ(”¥¥eBBBii©±±qll,÷«¨¨ˆ‰‰Á¥ºxñ¢••—†Ä IIIØÑÑÑ›6m‚åã«¢¢"$$TWWAP^^ž““üÎxyÍš5/^¼ˆŒŒ¼sçκuëvîÜù¿3ãb0˜M›6åää@ÔÖÖÖÔÔ´xñbàˆ¾ÊÆüm¨QTTD&“á!ÞÔÔtöìÙ{÷îν¦a=zÄ)À7Ûë§Ä§™©ªªjXXØÓ§O/\¸ÎGÖ¬Ychh¨¬¬Ü××çíí-//¯¦¦O h4úßÿþw¿§§gZZš””O)¿yófáÂ…úúú°+rõêÕéÜØÐЀÁ`äååhçêêj999CCCxv üôG^r=F{ñâÅ;wººº¤¤¤¦©iSS“¯¯ohh(â`ñQ˜¡¡¡ÀÀÀåË—³míÓ×(//ïÔ©S±±±l]‡i¦#à¥ÜwïÞ…††~Jm D£O‡Ã]¼xQYY…B>}:==}íÚµ°cûðáÃyóæýúë¯óçÏ×ÓÓû\ï««kVVÖÂ… SRR¸ºšššð €Åb8ïüŸÂÊÊê×_ýé§Ÿ²²²Èdò?Ö–Áò¬>êêêVTTTTTX[[çääTTTÀ£˜ŒŒLyy9¼ÊÕßßF£áEYYÙ††d…CUUuÂ#rZZG¦ 333Ľ¨®®Æb±,¼’’Rkk+2ƒÂ+|g*''çââRQQÁÓÁdÖE)uuuaaa,kbb‚¬÷XYYÈÈÈ,\¸ÐÈÈhÊE©),xewš¹£££` NB¾Îž=›»ÓÆ_Cš¬>Û:MLLìîî¦P(™™™þþþÓô޼¼"""´µµ¹7$.tvvzzz®ZµÊÕÕò¤LZZÚ¹sçâãã‘&ÊGëe«¯…¡R©¡¡¡ÝÝÝG={6÷ºãI#^ÍËG¦œ«´´´ÄÅÅÅÄÄLLLÊÊÊ`¹²²rddä’%Kdddlmm‹ŠŠ>¨Â;G§s¥©©é•+Wz{{á§MVh4Úÿ›oÐhdöõ¹\ü)ò/‡Éf\¸p!•J­««ûã?V®\ ¼p¿D¤¥¥ñx|vv6“ÉLMMݾ};ânÞ¿¿¹¹y||üÊ•+vŸ”””¬Y³†uÕL&'%%1ŒÂÂÂY³f)** °ÖÖÖ—.]îèèHNNFÞÒò”i}}}ZZÚðð0•JÍÏχ ˆ×ÕA‚†‡‡£££?|øŸV¹}û62—oذ!55u``àÇyyy .äc¥¶¶¶¨¨þ×’cÇŽMsrJKK#‚m‹/®©©),,d2™cccYYYaaaoH“a[§ÕÕÕªªªX,¶½½=11qÊÂçääüúë¯ñññêêêYYYܧ³qãFƒñÇð¡ƒÁˆ‰‰ÉÉɉ‹‹“””,..FŽÜòÔz9iÄSavìØ!//¿ÿ~ s÷î]ø¯š8Õ¯ñd^ž2åÂÕ«WËËË F{{{JJ ²˜D"ݾ}»­­m``àÑ£GÈ.mAÑ××gaaáááÁêíqBJJŠ@ x{{»»»Oøi×®]ÆÆÆíííðW ºººÜÜܱ±±¦¦¦Ã‡³eeeK–,‰‹‹›'ùõë×UUU¹oBý¼p2ㆠ||| %%%øZùÆN^S(”þþ~VIOOO@@€±±qDDÄèè(ëÉ_WWW"‘8ù qJJÊëׯY%T*5&&†@ lß¾½½½}&Ž;‘H$GGÇ’’þ2¾|ù2‰DZ¶lÙ¡C‡ë‹‹‹ñxü¢E‹,X€ÇãÏž=Ë=W¯^y{{kkk“Éä²²2ÖŸÒÓÓ­­­×¬Y»€\à”iGGGPP‘‘‘——Wbb¢´´tTTÔ”zíÞ½{B…‰ÄüQDDÇ»ººr?vš€ÇãåååUUUñxüÓ§Oaùǃƒƒ‰DâéÓ§§´0 i2lë´¹¹yË–-°ÍÏœ9ƒÅbᡜ°²²RQQÁãñx<~ñâŬ9Ù6$¶DFFb±X8mmm,ˇFðú¢††œŽ’’r O­—‹FÓ/ ¼Uÿ_¤¥¥kjj¸×Oñd^N™òÚ‚ƒƒ lllÒÓÓY*//wqq111IIIøˆ488èää´gÏÖ#ó;vìÀãñsçÎÕÔÔ$ðs&ÌÓ§OáuÖ é„‡‡ÛØØtuu!’îîîcÇŽYXXøøø$$$°þýBUU@HJJšü/ lå÷îÝ322š0VQ°5#|‚ øñøJO^£öøm‹¤ÄŒ At=%9ß:™üü|NÛà‰êêêÈÈÈ .S_<000àô«¤¤$ì+¶4ÕÇÆDƒ¨3ø§9}ú´ƒƒÃíÛ·§ùêà‹L€˜]»víÚµ ØøJ«à>€ûî#¸ÿKô÷÷ïÛ·¯§§˜b†à/|€oÓ}ó÷ìÛ·¯¤¤äÈ‘#óæÍƒ èØ±coÞ¼‰ ÔÐи{÷.•J½yóæöíÛ÷ìÙsøðá‹/ÊÊÊ677{xxœ?þ‡~`›8‘H—’’"ÞÞÞîîîÿWg4:444**jhhˆÉd¾ÿ><<|ppS ½½½&&&mmmŠŠŠ:::ªªªÜÿJÆÁÁáìÙ³íííÕÕÕ%&&š››s/d__Ÿ‰‰Éƹ¬¹~í0Œ˜˜˜œœœ¸¸8IIÉââbÖ}«eeeK–,‰‹‹}€/œ/b±göìÙ7n|ö왲²2"ôöö¾ÿ¾§§ç‡ˆDbjjªˆˆHXXXnn®¥¥å¼yóRRR¸¿DFX³fÍÉ“'oܸÁêá}÷Ýw›6mêêê222"‘Hbbb4ÍÅÅ¥°°F?~\^^þúõësæÌß²eKSS“²²òæÍ›áó7]]]NNN}}}uuuÖÖÖ³gÏŽŒŒ477Çáp{öì9pà@EE…‘‘Ñï¿ÿŽÅb»ººvïÞ]__O ÌÍÍ;–½aÃøý8ƒ‘——_°`Á7üòº««Ë××WCCãéÓ§ð×S§N!§à………eee%$$X½v''§ÿO;÷š0Æa8‚ÆÕ[x€ O‘#¸º¸x.*=€KÛäà ˆ‹“K[ÈÔ¡%ÄÄdèêóL¢Nßô’zÚívQM§ÓÍfs ã>üqƒÕrqw¿~{ ‚àéù%I’¦¯fYVùÿ@š¦q7}:™L>[ñxØ?®<Ë ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òQõ\$iIDATù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#òù€|ù€|@> ÈGÈGä#¿nØëÛiš:€|ì$Žc÷¸qÆkä#òù€|@>€|@>ð=J>ŸÏ]€®ùx>Ÿ]€Šq8*^¯èA> ÈGä#òä#òùÀOÚn·aÊG:™Ífõ7‡îÀEyž×ßôô€’b³6^p]±Y¯¸®Ø¬×4ªoÖÆkÕ7kã5꛵ñ€ª–ÍÚx @UËfm¼ ªe³¾8^—òqŽ\€Ækzøzúx<ìÝ€««åÂèèu0,€Uö°IEND®B`‚ddcui-0.3.0/src/000077500000000000000000000000001427175135000133765ustar00rootroot00000000000000ddcui-0.3.0/src/action_dialogs/000077500000000000000000000000001427175135000163555ustar00rootroot00000000000000ddcui-0.3.0/src/action_dialogs/debug_actions_dialog.cpp000066400000000000000000000126401427175135000232110ustar00rootroot00000000000000/** \file debug_actions_dialog.cpp */ // Copyright (C) 2020-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include "base/core.h" #include "help/help_dialog.h" #include "help/help_browser.h" #include "action_dialogs/debug_actions_dialog.h" #include "ui_debug_actions_dialog.h" // generated by UIC from debug_actions_dialog.ui DebugActionsDialog::DebugActionsDialog(QWidget *parent) : QDialog(parent) , _ui(new Ui::DebugActionsDialog) { bool debug = false; _cls = metaObject()->className(); TRACECF(debug, "Constructor starting"); _ui->setupUi(this); setWindowTitle("ddcui - Debugging Actions"); // setWindowFlag(Qt::CustomizeWindowHint, true); // not needed setWindowFlag(Qt::WindowContextHelpButtonHint, false); // setWindowFlag(Qt::WindowMinimizeButtonHint, false); // no effect // setWindowFlag(Qt::WindowMinMaxButtonsHint, false); // no effect QPushButton* okButton = _ui->actionButtonBox->button(QDialogButtonBox::Ok); okButton->setText("Close"); connect(_ui->resetStats_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionResetStatsButton_clicked); connect(_ui->all_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionAllStatsButton_clicked); connect(_ui->calls_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionCallsStatsButton_clicked); connect(_ui->tries_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionTriesStatsButton_clicked); connect(_ui->errors_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionErrorsStatsButton_clicked); connect(_ui->elapsed_pushButton, &QPushButton::clicked, this, &DebugActionsDialog::for_actionElapsedStatsButton_clicked); connect(_ui->extendedStats_checkBox, &QCheckBox::stateChanged, this , &DebugActionsDialog::for_actionExtendedStatsCheckBox_stateChanged); TRACECF(debug, "Constructor done. _cls = %s", _cls); } DebugActionsDialog::~DebugActionsDialog() { delete _ui; } // // QButtonBox actions // void DebugActionsDialog::on_actionButtonBox_accepted() { bool debugFunc = false; // not needed, automatically emitted when dialog accepted, by accept() or done() // emit userInterfaceDialog_accepted(_state); // probably not needed TRACECF(debugFunc, "Before calling accept()"); accept(); // causes accepted() to be emitted } void DebugActionsDialog::on_actionButtonBox_helpRequested() { // TRACE(); #ifdef OLD QString fn(":/docs/uioptions.html"); // -> debug_actions.html QFile f(fn); f.open(QFile::ReadOnly | QFile::Text); QTextStream in(&f); QString htmlText = in.readAll(); // qDebug() << htmlText; // doesn't show dialog box // HelpDialog2("ddcui Help - Other Options", htmlText, this); HelpDialog2* hd = new HelpDialog2(this); hd->setText(htmlText); hd->setWindowTitle("ddcui Help - Debugging Actions"); hd->show(); #endif // viewHelp("actions_debug.html", "ddcui Help - Execution Statistics", this); // HelpBrowser::showPage("qrc:/docs/help_actions_debug.html", false); HelpBrowser * browser = new HelpBrowser("qrc:/docs/help_actions_debug.html", false); // browser->setMinimumSize(1000,400); browser->resize(500,400); browser->show(); } // // Actions for stats buttons // void DebugActionsDialog::for_actionAllStatsButton_clicked(bool onoff) { bool debug = false; TRACECF(debug, "Executing"); bool isChecked = _ui->extendedStats_checkBox->isChecked(); emit reportStats_triggered(DDCA_STATS_ALL, isChecked ); } void DebugActionsDialog::for_actionCallsStatsButton_clicked(bool onoff) { bool debug = false; TRACECF(debug, "Executing"); bool isChecked = _ui->extendedStats_checkBox->isChecked(); emit reportStats_triggered(DDCA_STATS_CALLS, isChecked ); } void DebugActionsDialog::for_actionErrorsStatsButton_clicked(bool onoff) { bool debug = false; TRACECF(debug, "Executing"); bool isChecked = _ui->extendedStats_checkBox->isChecked(); emit reportStats_triggered(DDCA_STATS_ERRORS, isChecked ); } void DebugActionsDialog::for_actionTriesStatsButton_clicked(bool onoff) { bool debug = false; TRACECF(debug, "Executing"); bool isChecked = _ui->extendedStats_checkBox->isChecked(); emit reportStats_triggered(DDCA_STATS_TRIES, isChecked ); } void DebugActionsDialog::for_actionElapsedStatsButton_clicked(bool onoff) { bool debug = false; // printf("_cls = %s\n", _cls); // printf("Z "); // fflush(stdout);SA TRACECF(debug, "Executing"); bool isChecked = _ui->extendedStats_checkBox->isChecked(); emit reportStats_triggered(DDCA_STATS_ELAPSED, isChecked ); } void DebugActionsDialog::for_actionExtendedStatsCheckBox_stateChanged(int newState) { bool debug = false; bool checked = _ui->extendedStats_checkBox->isChecked() ; TRACECF(debug, "Executing. checked = %s, newState x = %d", SBOOL( checked), newState ); } void DebugActionsDialog::for_actionResetStatsButton_clicked(bool onoff) { bool debug = false; TRACECF(debug, "Executing"); emit resetStats_triggered(); } ddcui-0.3.0/src/action_dialogs/debug_actions_dialog.h000066400000000000000000000026171427175135000226610ustar00rootroot00000000000000// debug_actions_dialog.h // Copyright (C) 2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DEBUG_ACTIONS_DIALOG_H #define DEBUG_ACTIONS_DIALOG_H #include // Becasue MOC #include #include #include "ddcutil_types.h" #include "ui_debug_actions_dialog.h" // generated by UIC from debug_actions_dialog.ui // namespace Ui { // class DebugActionsDialog; // } class DebugActionsDialog : public QDialog { Q_OBJECT public: explicit DebugActionsDialog(QWidget *parent = 0); ~DebugActionsDialog(); signals: void resetStats_triggered(); void reportStats_triggered(DDCA_Stats_Type stats_type, bool extended); private slots: void on_actionButtonBox_accepted(); void on_actionButtonBox_helpRequested(); void for_actionAllStatsButton_clicked(bool onoff); void for_actionCallsStatsButton_clicked(bool onoff); void for_actionErrorsStatsButton_clicked(bool onoff); void for_actionTriesStatsButton_clicked(bool onoff); void for_actionElapsedStatsButton_clicked(bool onoff); void for_actionExtendedStatsCheckBox_stateChanged(int newState); void for_actionResetStatsButton_clicked(bool onoff); private: const char * _cls; Ui::DebugActionsDialog *_ui; // void setUiSource(NcValuesSource source); }; #endif // DEBUG_ACTIONS_DIALOG_H ddcui-0.3.0/src/action_dialogs/debug_actions_dialog.ui000066400000000000000000000076241427175135000230520ustar00rootroot00000000000000 DebugActionsDialog 0 0 235 399 Dialog 10 360 191 32 Qt::Horizontal QDialogButtonBox::Help|QDialogButtonBox::Ok true 20 10 241 31 14 Execution Statistics 20 40 171 261 Dump Statistics 40 30 88 34 All 40 70 88 34 Calls 40 150 88 34 Tries 40 110 88 34 Errors 40 190 88 34 Elapsed 40 230 121 22 Extended Stats 60 310 88 34 Reset Stats actionButtonBox accepted() DebugActionsDialog accept() 248 254 157 274 ddcui-0.3.0/src/base/000077500000000000000000000000001427175135000143105ustar00rootroot00000000000000ddcui-0.3.0/src/base/.gitignore000066400000000000000000000000101427175135000162670ustar00rootroot00000000000000unused/ ddcui-0.3.0/src/base/core.cpp000066400000000000000000000174421427175135000157540ustar00rootroot00000000000000// ddcui_globals.cpp // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include "ddcui_parms.h" #include "core.h" const int FeatureRowHeight = 22; const int FeatureHeaderHeight = 22; const QFont FeatureValueTextFont( "SansSerif", 8, QFont::Normal); const QFont FeatureValueMonoFont( "Monospace", 8, QFont::Normal); // used? const QFont FeatureValueButtonFont( "Serif", 8, QFont::Normal); const QFont FeatureValueNumberEntryFont("Monospace", 8, QFont::Normal); const QFont FeatureValueComboBoxFont( "SansSerif", 8, QFont::Normal); const QFont FeatureValueHeaderFont( "SansSerif", 8, QFont::Bold); QFont MainMenuFont2( "DejaVu Sans [Qt Embedded]", 10, QFont::Normal); void init_core() { MainMenuFont2.setKerning(true); MainMenuFont2.setStyleStrategy( QFont::PreferDefault); } // from ddcutil glib_util.c /** Handles the boilerplate of obtaining a thread specific fixed size buffer. * The first call to this function in a thread with a given key address * allocates the buffer. Subsequent calls in the thread for the same key * address return the same buffer. * * \param buf_key_ptr address of a **GPrivate** used as the identifier * for the buffer * \param buffer_size size of buffer to allocate * \return pointer to thread specific buffer * * \remark * When the buffer is first allocated, byte 0 is set to '\0' */ static gchar * get_thread_fixed_buffer_ddcui( GPrivate * buf_key_ptr, guint16 buffer_size) { // printf("(%s) buf_key_ptr=%p, buffer_size=%d\n", __func__, buf_key_ptr, buffer_size); assert(buffer_size > 0); char * buf = (char *) g_private_get(buf_key_ptr); // GThread * this_thread = g_thread_self(); // printf("(%s) this_thread=%p, buf=%p\n", __func__, this_thread, buf); if (!buf) { buf = (char *) g_new0(char, buffer_size); // buf[0] = '\0'; // (sort of) mark buffer as unused g_private_set(buf_key_ptr, buf); } // printf("(%s) Returning: %p\n", __func__, buf); return buf; } // ddcutil timestamp.c uint64_t cur_realtime_nanosec() { // on Pi, __time_t resolves to long int struct timespec tvNow; clock_gettime(CLOCK_REALTIME, &tvNow); uint64_t result = tvNow.tv_sec * (uint64_t)(1000*1000*1000); result += tvNow.tv_nsec; // printf("(%s) result=%"PRIu64"\n", __func__, result); // printf("(%s) tv_sec=%ld, tv_nsec=%10ld, Returning: %"PRIu64"\n", // __func__, tvNow.tv_sec, tvNow.tv_nsec, result); return result; } static uint64_t initial_timestamp_nanos = 0; /** Returns the elapsed time in nanoseconds since the start of * program execution. * * The first call to this function marks the start of program * execution and returns 0. * * @return nanoseconds since start of program execution */ uint64_t elapsed_time_nanosec() { // printf("(%s) initial_timestamp_nanos=%"PRIu64"\n", __func__, initial_timestamp_nanos); uint64_t cur_nanos = cur_realtime_nanosec(); if (initial_timestamp_nanos == 0) initial_timestamp_nanos = cur_nanos; uint64_t result = cur_nanos - initial_timestamp_nanos; // printf("(%s) Returning: %"PRIu64"\n", __func__, result); return result; } /** Returns the elapsed time since start of program execution * as a formatted, printable string. * * The string is built in a thread specific private buffer. The returned * string is valid until the next call of this function in the same thread. * * @return formatted elapsed time */ char * formatted_elapsed_time() { static GPrivate formatted_elapsed_time_key = G_PRIVATE_INIT(g_free); char * elapsed_buf = get_thread_fixed_buffer_ddcui(&formatted_elapsed_time_key, 40); uint64_t et_nanos = elapsed_time_nanosec(); uint64_t isecs = et_nanos/ (1000 * 1000 * 1000); uint64_t imillis = et_nanos/ (1000 * 1000); // printf("(%s) et_nanos=%"PRIu64", isecs=%"PRIu64", imillis=%"PRIu64"\n", __func__, et_nanos, isecs, imillis); snprintf(elapsed_buf, 40, "%3" PRIu64 ".%03" PRIu64 "", isecs, imillis - (isecs*1000) ); // printf("(%s) |%s|\n", __func__, elapsed_buf); return elapsed_buf; } static bool ddcui_trace_show_time; static bool ddcui_trace_show_thread_id; bool enable_trace_show_time(bool onoff) { // printf("(%s) Setting %s\n", __func__, sbool(onoff)); bool old = ddcui_trace_show_time; ddcui_trace_show_time = onoff; return old; } bool enable_trace_show_thread_id(bool onoff) { // printf("(%s) Setting %s\n", __func__, sbool(onoff)); bool old = ddcui_trace_show_thread_id; ddcui_trace_show_thread_id = onoff; return old; } bool printftcmf( bool debug, const char * metaclass_classname, const char * cls, // _cls const char * funcname, int lineno, const char * filename, const char * format, ...) { #ifdef FOR_FUNCTION_DEBUG bool metadebug = true; if (metadebug) { printf("(printfcmf) debug=%s, metaclass_classname = %s, cls=%s, funcname=%s, lineno=%d, filename=%s\n", sbool(debug), metaclass_classname, cls, funcname, lineno, filename); printf(" format = %s\n", format); fflush(stdout); } #endif bool msg_emitted = false; if (debug) { va_list args; va_start(args, format); char * buffer = g_strdup_vprintf(format, args); va_end(args); char * funcbuf = nullptr; if (metaclass_classname && cls) { if (strcmp(metaclass_classname, cls) == 0) { funcbuf = g_strdup_printf("%s::%s", metaclass_classname, funcname); } else { funcbuf = g_strdup_printf("%s/%s::%s", metaclass_classname, cls, funcname); } } else if (metaclass_classname && !cls) { funcbuf = g_strdup_printf("%s::%s", metaclass_classname, funcname); } else if (!metaclass_classname && cls) { funcbuf = g_strdup_printf("%s::%s", cls, funcname); } else { funcbuf = g_strdup(funcname); } // printf("(printfcmf) len class::func field in funcbuf: %ld, value=|%s|\n", // strlen(funcbuf), funcbuf); char elapsed_prefix[15] = ""; if (ddcui_trace_show_time) g_snprintf(elapsed_prefix, 15, "[%s]", formatted_elapsed_time()); char thread_prefix[15] = ""; if (ddcui_trace_show_thread_id) { pid_t tid = syscall(SYS_gettid); snprintf(thread_prefix, 15, "[%7jd]", (intmax_t) tid); // is this proper format for pid_t } #ifdef FOR_FUNCTION_DEBUG printf("(printfcmf) bufsz+100=%d, buf2sz=%d, lengths: thread_prefix %lu, elapsed_prefix %lu, funcbuf %lu, buffer %lu\n", bufsz+100, buf2sz, strlen(thread_prefix), strlen(elapsed_prefix), strlen(funcbuf), strlen(buffer)); printf("(printfcmf) buf2=%p, thread_prefix=%p, elapsed_prefix=%p, funcbuf=%p, buffer=%p\n", buf2, thread_prefix, elapsed_prefix, funcbuf, buffer); fflush(stdout); #endif char * buf2 = g_strdup_printf("%s%s(%-30s) %s", thread_prefix, elapsed_prefix, funcbuf, buffer); fputs(buf2, stdout); // no automatic terminating null fputs("\n", stdout); // if \n at end of format string for buf2 it's sometimes unrecognized fflush(stdout); free(buffer); free(buf2); free(funcbuf); msg_emitted = true; //} } return msg_emitted; } ddcui-0.3.0/src/base/core.h000066400000000000000000000052221427175135000154120ustar00rootroot00000000000000// core.h // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef CORE_H #define CORE_H #include #include #include #include #include #include "config.h" #include "ddcui_parms.h" const QString ddcui_version = DDCUI_VSTRING; // Qt const int FeatureValueRole = Qt::UserRole+1; // DisplayRole, EditorRole, .. etc const int FeatureWidgetType = QListWidgetItem::UserType+1; extern const int FeatureRowHeight; extern const int FeatureHeaderHeight; extern const QFont FeatureValueTextFont; extern const QFont FeatureValueMonoFont; extern const QFont FeatureValueButtonFont; extern const QFont FeatureValueNumberEntryFont; extern const QFont FeatureValueComboBoxFont; extern const QFont FeatureValueHeaderFont; extern QFont MainMenuFont2; void init_core(); // // Tracing // bool enable_trace_show_time(bool onoff); bool enable_trace_show_thread_id(bool onoff); bool printftcmf( bool debug, const char * metaclass_classname, const char * cls, const char * funcname, int lineno, const char * filename, const char * format, ...); // Naming conventions: // C use _cls // F flag controls whether shown // M use metaObject->className() // MC #define TRACEC( _FMT, ...) \ do { \ printftcmf(true, nullptr, _cls, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) #define TRACECF(_FLAG, _FMT, ...) \ do { \ printftcmf(_FLAG, nullptr, _cls, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) #define TRACEM( _FMT, ...) \ do { \ printftcmf(true, metaObject()->className(), nullptr, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) #define TRACEMF(_FLAG, _FMT, ...) \ do { \ printftcmf(_FLAG, metaObject()->className(), nullptr, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) #define TRACEMC( _FMT, ...) \ do { \ printftcmf(true, metaObject()->className(), _cls, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) #define TRACEMCF(_FLAG, _FMT, ...) \ do { \ printftcmf(_FLAG, metaObject()->className(), _cls, __func__, __LINE__, __FILE__, _FMT, ##__VA_ARGS__); \ } while(0) // Inline functions // inline const char * sbool(bool val) { return (val) ? "true" : "false"; } // wrong. on function end the underlying QByteArray is free'd, so the // returned pointer is invalid // inline const char * qs2s(QString qstr) {return qstr.toLatin1().data(); } // A macro alternative to sbool() #define SBOOL(val) ( (val) ? "true" : "false" ) #define QS2S(qstr) qstr.toLatin1().data() #endif // CORE_H ddcui-0.3.0/src/base/ddca_utils.cpp000066400000000000000000000115361427175135000171350ustar00rootroot00000000000000// ddca_utils.cpp // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include extern "C" { #include "c_util/data_structures.h" } #include "ddca_utils.h" // Parsed capabilities and feature values Bit_Set_256 bs256_from_cfr(DDCA_Cap_Vcp * cfr) { Bit_Set_256 result = EMPTY_BIT_SET_256; for (int ndx = 0; ndx < cfr->value_ct; ndx++) { result = bs256_insert(result, cfr->values[ndx]); } return result; } Bit_Set_256 bs256_from_sl_values(DDCA_Feature_Value_Entry * sl_values) { Bit_Set_256 result = EMPTY_BIT_SET_256; if (sl_values) { DDCA_Feature_Value_Entry * cur = sl_values; while(cur->value_name) { result = bs256_insert(result, cur->value_code); cur++; } } return result; } #ifdef UNUSED static bool cap_vcp_contains(DDCA_Cap_Vcp* cfr, uint8_t feature_code) { // printf("(%s) cfr=%p, feature_code=0x%02x\n", __func__, cfr, feature_code); fflush(stdout); bool result = false; for (int ndx = 0; ndx < cfr->value_ct; ndx++) { if (cfr->values[ndx] == feature_code) { result = true; break; } } // printf("(%s) Returning %d\n", __func__, result); return result; } static DDCA_Feature_Value_Entry * find_feature_value_entry(DDCA_Feature_Value_Entry * sl_values, uint8_t feature_code) { DDCA_Feature_Value_Entry * result = NULL; if (sl_values) { for (int ndx = 0; sl_values[ndx].value_name; ndx++) { if (sl_values[ndx].value_code == feature_code) { result = &sl_values[ndx]; break; } } } return result; } static int feature_value_entry_ct(DDCA_Feature_Value_Entry * sl_values) { int ct = 0; if (sl_values) { while( sl_values[ct].value_name ) ct++; } return ct; } #endif #ifdef OLD static inline int int_max(int v1, int v2) { return (( v1 > v2) ? v1 : v2); } #endif DDCA_Cap_Vcp * ddcutil_find_cap_vcp(DDCA_Capabilities * parsed_caps, uint8_t feature_code) { DDCA_Cap_Vcp * result = NULL; if (parsed_caps) { for (int ndx = 0; ndx < parsed_caps->vcp_code_ct; ndx++) { DDCA_Cap_Vcp* cur = &parsed_caps->vcp_codes[ndx]; if (cur->feature_code == feature_code) { result = cur; break; } } } return result; } // Error Reporting // declaration for recursive call static void format_error_detail_aux( DDCA_Error_Detail * erec, QString causesTitle, int indentation_per_depth, int cur_depth, QString& accum); static void format_error_detail_aux( DDCA_Error_Detail * erec, QString causesTitle, int indentation_per_depth, int cur_depth, QString& accum) { int indentct = indentation_per_depth * cur_depth; QString istring = ""; for (int ndx = 0; ndx < indentct; ndx++) { istring.append(" "); } accum.append(istring); accum.append(erec->detail); accum.append("\n"); if (erec->cause_ct > 0) { if (causesTitle.length() > 0) { accum.append(causesTitle); accum.append("\n"); } for (int ndx = 0; ndx < erec->cause_ct; ndx++) { format_error_detail_aux( erec->causes[ndx], causesTitle, indentation_per_depth, cur_depth+1, accum); } } } QString ddcutil_format_error_detail( DDCA_Error_Detail * erec, QString causesTitle, int indentation_per_depth) { QString accum = QString(""); format_error_detail_aux(erec, causesTitle, indentation_per_depth, 0, accum); return accum; } #ifdef OLD // use api function ddca_dbgrpt_feature_metadata() void ddcui_dbgrpt_ddca_feature_metadata( DDCA_Feature_Metadata * meta) { assert(meta); printf("DDCA_Feature_Metadata at %p:", meta); printf(" VCP code %02X: %s\n", meta->feature_code, meta->feature_name); // rpt_vstring(d1, "Version spec: %d.%d", meta->vspec.major, meta->vspec.minor); printf(" Description: %s\n", meta->feature_desc); DDCA_Version_Feature_Flags vflags = meta->feature_flags; printf(" feature_flags: 0x%04x\n", vflags); // rpt_vstring(d1, "Global_flags: 0x%02x", info->global_flags); // TODO: interpretation function if(meta->sl_values) { DDCA_Feature_Value_Entry * sl_values = meta->sl_values; printf("Simple NC values:\n"); while (sl_values->value_name != NULL) { printf(" 0x%02x: %s\n", sl_values->value_code, sl_values->value_name); sl_values++; } } else printf("Simple NC values; No table specified\n"); } #endif ddcui-0.3.0/src/base/ddca_utils.h000066400000000000000000000016061427175135000165770ustar00rootroot00000000000000// ddca_utils.h // // Wrap ddcutil API functionality // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCA_UTILS_H_ #define DDCA_UTILS_H_ #include #include #include "c_util/data_structures.h" // NC Feature Values Bit_Set_256 bs256_from_cfr(DDCA_Cap_Vcp * cfr); Bit_Set_256 bs256_from_sl_values(DDCA_Feature_Value_Entry * sl_values); // Capabilities DDCA_Cap_Vcp * ddcutil_find_cap_vcp( DDCA_Capabilities * parsed_caps, uint8_t feature_code); #ifdef UNUSED void free_ddca_feature_value_table( DDCA_Feature_Value_Table * table); #endif // Error Reporting QString ddcutil_format_error_detail( DDCA_Error_Detail * erec, QString causesTitle, int indentation_per_depth); #endif /* DDCA_UTILS_H_ */ ddcui-0.3.0/src/base/ddcui_parms.cpp000066400000000000000000000007251427175135000173120ustar00rootroot00000000000000// ddcui_parms.cpp // Copyright (C) 2019-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "ddcui_parms.h" const bool debugSignals = false; const bool debugValueWidgetSignals = false; const bool debugFeatureLists = false; const bool debugFeatureSelection = false; const bool debugLayout = false; const bool debugNcValues = false; const bool debugFeatureDimensions = false; ddcui-0.3.0/src/base/ddcui_parms.h000066400000000000000000000032541427175135000167570ustar00rootroot00000000000000// ddcui_parms.h // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUI_PARMS_H_ #define DDCUI_PARMS_H_ #ifdef TOO_MUCH_INDIRECTION #define FEATURE_VALUE_MONO_FONT_SIZE 8 #define FEATURE_VALUE_MONO_FONT_FAMILY "Monospace" #define FEATURE_VALUE_MONO_FONT_WEIGHT QFont::Normal #define FEATURE_VALUE_TEXT_FONT_SIZE 8 #define FEATURE_VALUE_TEXT_FONT_FAMILY "SansSerif" #define FEATURE_VALUE_TEXT_FONT_WEIGHT QFont::Normal #define FEATURE_VALUE_BUTTON_FONT_SIZE 8 #define FEATURE_VALUE_BUTTON_FONT_FAMILY "Serif" #define FEATURE_VALUE_BUTTON_FONT_WEIGHT QFont::Normal #define FEATURE_VALUE_NUMBER_ENTRY_FONT_SIZE 8 #define FEATURE_VALUE_NUMBER_ENTRY_FONT_FAMILY "Monospace" #define FEATURE_VALUE_NUMBER_ENTRY_FONT_WEIGHT QFont::Normal #define FEATURE_VALUE_COMBO_BOX_FONT_SIZE 8 #define FEATURE_VALUE_COMBO_BOX_FONT_FAMILY "SansSerif" #define FEATURE_VALUE_COMBO_BOX_FONT_WEIGHT QFont::Normal #define FEATURE_VALUE_HEADER_FONT_SIZE 8 #define FEATURE_VALUE_HEADER_FONT_FAMILY "SansSerif" #define FEATURE_VALUE_HEADER_FONT_WEIGHT QFont::Bold #define MAIN_MENU_FONT_SIZE 10 #define MAIN_MENU_FONT_FAMILY "DejaVu Sans [Qt Embedded]" #define MAIN_MENU_FONT_WEIGHT QFont::Normal #endif #define PERSISTENT_SERIAL_MSG_BOX #define MSGBOX_THREAD_RUN_DELAY_MILLIS 200 extern const bool debugSignals ; extern const bool debugValueWidgetSignals ; extern const bool debugFeatureLists ; extern const bool debugFeatureSelection ; extern const bool debugNcValues ; extern const bool debugLayout ; extern const bool debugFeatureDimensions ; #endif /* DDCUI_PARMS_H_ */ ddcui-0.3.0/src/base/feature_list.c000066400000000000000000000071611427175135000171470ustar00rootroot00000000000000/** \file feature_list.cpp */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #include "c_util/string_util.h" #include "base/ddcui_parms.h" #include "base/feature_list.h" /** Parse a string containing a list of feature codes * * \param unparsed_string * \error_msgs_loc return null terminated string array of error messages here, * caller is responsible for freeing * set to NULL if no errors * \return feature code set, DDCA_EMPTY_FEATURE_LIST if errors * * \remark * On return. the value of error_msgs_loc is non-null iff errors occurred, */ DDCA_Feature_List parse_custom_feature_list( char * unparsed_string, Null_Terminated_String_Array * error_msgs_loc) { assert(unparsed_string); assert(error_msgs_loc); bool debug = false; if (debug) printf("(parse_custom_feature_list) unparsed_string = |%s|\n", unparsed_string ); DDCA_Feature_List feature_list = DDCA_EMPTY_FEATURE_LIST; *error_msgs_loc = NULL; // convert all commas to blanks char * x = unparsed_string; while (*x) { if (*x == ',') *x = ' '; x++; } GPtrArray * errors = g_ptr_array_new(); Null_Terminated_String_Array pieces = strsplit(unparsed_string, " "); // gchar ** pieces = g_strsplit(features_work, " ", -1); // doesn't handle multiple blanks int ntsal = ntsa_length(pieces); if (debug) printf("(parse_custom_feature_list) ntsal=%d\n", ntsal ); if (ntsal == 0) { // char * s = "No custom features specified"; // g_ptr_array_add(errors, s); // fprintf(stderr, "%s\n", s); if (debug) printf("(parse_custom_feature_list) Empty string\n"); } else { bool ok = true; int ndx = 0; for (; pieces[ndx] != NULL; ndx++) { // char * token = strtrim_r(pieces[ndx], trimmed_piece, 10); char * token = g_strstrip(pieces[ndx]); if (debug) printf("(parse_features_list) token= |%s|\n", token); Byte feature_code = 0; if ( any_one_byte_hex_string_to_byte_in_buf(token, &feature_code) ) { ddca_feature_list_add(&feature_list, feature_code); } else { if (debug) printf("(parsed_feature_list) Invalid feature code in --custom_features: %s\n", token); char * s = g_strdup_printf("Invalid feature code: %s", token); g_ptr_array_add(errors, s); ok = false; } } assert(ndx == ntsal); ASSERT_IFF(ok, errors->len == 0); if (ok) { g_ptr_array_free(errors,true); *error_msgs_loc = NULL; } else { feature_list = DDCA_EMPTY_FEATURE_LIST; *error_msgs_loc = g_ptr_array_to_ntsa(errors, false); g_ptr_array_free(errors, false); } } ntsa_free(pieces, /* free_strings */ true); if (debug) { const char * s = ddca_feature_list_string(feature_list, /*prefix*/ "x", /*sepstr*/ ","); printf("Returning feature list: %s\n", s); if (*error_msgs_loc) { printf("(parse_custom_feature_list) Returning error messages:\n"); ntsa_show(*error_msgs_loc); } } assert(!(*error_msgs_loc && ntsa_length(*error_msgs_loc) == 0)); assert(!(ddca_feature_list_count(feature_list) > 0 && *error_msgs_loc)); return feature_list; } ddcui-0.3.0/src/base/feature_list.h000066400000000000000000000010741427175135000171510ustar00rootroot00000000000000// feature_list.h // Copyright (C) 2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "ddcutil_types.h" #include "c_util/string_util.h" #ifndef FEATURE_LIST_H_ #define FEATURE_LIST_H_ #define ASSERT_IFF(_cond1, _cond2) \ assert( ( (_cond1) && (_cond2) ) || ( !(_cond1) && !(_cond2) ) ) #ifdef __cplusplus extern "C" { #endif DDCA_Feature_List parse_custom_feature_list( char * features_work, Null_Terminated_String_Array * error_msgs_loc); #ifdef __cplusplus } #endif #endif /* FEATURE_LIST_H_ */ ddcui-0.3.0/src/base/feature_selector.cpp000066400000000000000000000122321427175135000203470ustar00rootroot00000000000000/** \file feature_selector.cpp * * Controls which features are shown, as specified in the * Options->Feature Selection dialog. */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "base/core.h" #include "base/feature_selector.h" #include "cmdline/ddcui_parsed_cmd.h" // For feature selection dialog DDCA_Feature_Subset_Id parsedFeatureSet_to_ddcaFeatureSubsetId(Parsed_Feature_Set fs) { DDCA_Feature_Subset_Id fsid = DDCA_SUBSET_UNSET; // dummy value switch(fs) { case FS_UNSET: fsid = DDCA_SUBSET_UNSET; break; case FS_MCCS: fsid = DDCA_SUBSET_KNOWN; break; case FS_CAPABILITIES: fsid = DDCA_SUBSET_CAPABILITIES; break; case FS_MANUFACTURER: fsid = DDCA_SUBSET_MFG; break; case FS_COLOR: fsid = DDCA_SUBSET_COLOR; break; case FS_SCAN: fsid = DDCA_SUBSET_SCAN; break; case FS_CUSTOM: fsid = DDCA_SUBSET_CUSTOM; break; } return fsid; } bool defaultIncludeOnlyCapabilities(DDCA_Feature_Subset_Id fsid) { bool result = false; if (fsid == DDCA_SUBSET_KNOWN || fsid == DDCA_SUBSET_CAPABILITIES || fsid == DDCA_SUBSET_MFG || fsid == DDCA_SUBSET_COLOR) result = true; return result; } bool defaultIncludeAllCapabilities(DDCA_Feature_Subset_Id fsid) { bool result = false; if (fsid == DDCA_SUBSET_CAPABILITIES) result = true; return result; } void FeatureSelector::applyParsedOptions(Parsed_Ddcui_Cmd * parsed_cmd) { bool debug = false; if (ddca_feature_list_count(parsed_cmd->custom_feature_list) > 0) { // printf("(applyParsedOptions) feature list count > 0\n"); _customFeatureList = parsed_cmd->custom_feature_list; // printf("(applyParsedOptions) setting _featureListId = DDCA_SUBSET_CUSTOM\n"); _featureSubsetId = DDCA_SUBSET_CUSTOM; } else if (parsed_cmd->feature_set) { // printf("(applyParsedOptions) feature set passed\n"); _featureSubsetId = parsedFeatureSet_to_ddcaFeatureSubsetId(parsed_cmd->feature_set); } else _featureSubsetId = DDCA_SUBSET_KNOWN; // default _showUnsupportedFeatures = parsed_cmd->flags & CMD_FLAG_SHOW_UNSUPPORTED; if (parsed_cmd->include_only_capabilities_features == TRIVAL_TRUE) _includeOnlyCapabilities = true; else if (parsed_cmd->include_only_capabilities_features == TRIVAL_FALSE) _includeOnlyCapabilities = false; else { _includeOnlyCapabilities = defaultIncludeOnlyCapabilities(_featureSubsetId); } if (parsed_cmd->include_all_capabilities_features == TRIVAL_TRUE) _includeAllCapabilities = true; else if (parsed_cmd->include_all_capabilities_features == TRIVAL_FALSE) _includeAllCapabilities = false; else { _includeAllCapabilities = defaultIncludeAllCapabilities(_featureSubsetId); } if (debug) { TRACEC("Done."); dbgrpt(); } } FeatureSelector::FeatureSelector() { } FeatureSelector::FeatureSelector(Parsed_Ddcui_Cmd * parsedCmd) { applyParsedOptions(parsedCmd); } FeatureSelector::FeatureSelector(const FeatureSelector &other) { _featureSubsetId = other._featureSubsetId; _includeTableFeatures = other._includeTableFeatures ; _showUnsupportedFeatures = other._showUnsupportedFeatures ; _includeOnlyCapabilities = other._includeOnlyCapabilities ; _includeAllCapabilities = other._includeAllCapabilities; } bool FeatureSelector::operator==(const FeatureSelector &other) const { bool debugFunc = false; bool result = (_featureSubsetId == other._featureSubsetId && _includeTableFeatures == other._includeTableFeatures && _showUnsupportedFeatures == other._showUnsupportedFeatures && _includeOnlyCapabilities == other._includeOnlyCapabilities && _includeAllCapabilities == other._includeAllCapabilities); if (result && _featureSubsetId == DDCA_SUBSET_CUSTOM) { TRACECF(debugFunc, "Comparing %s to %s", ddca_feature_list_string(_customFeatureList, "x", ","), ddca_feature_list_string(other._customFeatureList, "x", ",") ); result = ddca_feature_list_eq(_customFeatureList, other._customFeatureList); } TRACECF(debugFunc, "Returning: %s", SBOOL(result)); return result; } bool FeatureSelector::operator!=(const FeatureSelector &other) const { return !(*this == other); } void FeatureSelector::dbgrpt() { printf(" feature_list_id: %d - %s\n", _featureSubsetId, ddca_feature_list_id_name(_featureSubsetId)); printf(" custom features: %s\n", ddca_feature_list_string(_customFeatureList, "", ", ")); printf(" includeTableFeatures: %s\n", SBOOL(_includeTableFeatures)); printf(" showUnsupportedFeatures: %s\n", SBOOL(_showUnsupportedFeatures)); printf(" includeOnlyCapabilities: %s\n", SBOOL(_includeOnlyCapabilities)); printf(" includeAllCapabilities: %s\n", SBOOL(_includeAllCapabilities)); fflush(stdout); } ddcui-0.3.0/src/base/feature_selector.h000066400000000000000000000025001427175135000200110ustar00rootroot00000000000000/** \file feature_selector.h * * Controls which features are shown, as specified by the * Options->Feature Selection dialog. */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURE_SELECTOR_H #define FEATURE_SELECTOR_H #include #include "ddcutil_types.h" #include "cmdline/ddcui_parsed_cmd.h" class FeatureSelector // : public QObject { // Q_OBJECT public: FeatureSelector(); FeatureSelector(Parsed_Ddcui_Cmd * parsedCmd); FeatureSelector(const FeatureSelector &other); FeatureSelector& operator=(const FeatureSelector& sel2) = default; bool operator==(const FeatureSelector& sel2) const; bool operator!=(const FeatureSelector& sel2) const; void dbgrpt(); DDCA_Feature_Subset_Id _featureSubsetId = DDCA_SUBSET_KNOWN; bool _showUnsupportedFeatures = false; bool _includeTableFeatures = false; bool _includeOnlyCapabilities = true; bool _includeAllCapabilities = false; DDCA_Feature_List _customFeatureList = DDCA_EMPTY_FEATURE_LIST; private: void applyParsedOptions(Parsed_Ddcui_Cmd * parsed_cmd); const char * _cls = "FeatureSelector"; }; #endif // FEATURE_SELECTOR_H ddcui-0.3.0/src/base/global_state.cpp000066400000000000000000000011351427175135000174540ustar00rootroot00000000000000/** @file global_state.cpp * Singleton class maintaining pointers to key class instances */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "global_state.h" GlobalState::GlobalState() { // Auto-generated constructor stub } #ifdef PRE_CPP11 GlobalState * GlobalState::getInstance() { if (!_theOneAndOnly) { _theOneAndOnly = new GlobalState(); } return _theOneAndOnly; } #endif // Static C++11 thread safe way GlobalState& GlobalState::instance() { static GlobalState _instance; return _instance; } ddcui-0.3.0/src/base/global_state.h000066400000000000000000000020601427175135000171170ustar00rootroot00000000000000/** @file global_state.h * Singleton class maintaining pointers to key class instances */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef GLOBAL_STATE_H_ #define GLOBAL_STATE_H_ // #include // to define Q_OBJECT #include "cmdline/ddcui_parsed_cmd.h" #include "base/user_interface_options_state.h" #include "base/nc_values_state.h" #include "main/mainwindow.h" // ugh - referencing out of base, to clean up class GlobalState { // Q_OBJECT public: static GlobalState& instance(); Parsed_Ddcui_Cmd * _parsed_cmd = nullptr; NcValuesState * _ncValuesState = nullptr; UserInterfaceOptionsState * _uiOptionsState = nullptr; QApplication * _application = nullptr; MainWindow * _mainWindow = nullptr; MsgBoxThread * _msgBoxThread = nullptr; MsgBoxQueue * _msgBoxQueue = nullptr; private: GlobalState(); // No need for destructor. Created once for life of the program. }; #endif /* GLOBAL_STATE_H_ */ ddcui-0.3.0/src/base/help_viewer.cpp000066400000000000000000000010671427175135000173310ustar00rootroot00000000000000// help_viewer.cpp // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "help_viewer.h" void HelpViewer::show(QString &simpleFn, QString& title) { QString fn = simpleFn.prepend(":/docs/"); QFile f(fn); f.open(QFile::ReadOnly | QFile::Text); QTextStream in(&f); QString htmlText = in.readAll(); // qDebug() << htmlText; HelpDialog2* hd = new HelpDialog2(this); hd->setText(htmlText); // hd->_textBrowser->setSource(fn); hd->setWindowTitle( title ); hd->show(); } ddcui-0.3.0/src/base/help_viewer.h000066400000000000000000000005421427175135000167730ustar00rootroot00000000000000// help_viewer.c // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef HELP_VIEWER_C_ #define HELP_VIEWER_C_ #include #include class QTextBrowser; namespace HelpViewer { void show(QString helpfile, QString title); }; #endif /* HELP_VIEWER_C_ */ ddcui-0.3.0/src/base/monitor.h000066400000000000000000000037731427175135000161620ustar00rootroot00000000000000/* monitor.h */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef MONITOR_H #define MONITOR_H #include #include #include #include "config.h" #include "base/feature_selector.h" class QListView; class QListWidget; class QPlainTextEdit; class QTableView; class QTableWidget; class QWidget; // class QHash; // incomplete type, need full #include class FeatureBaseModel; class FeaturesScrollAreaView; class VcpRequest; class VcpRequestQueue; class VcpThread; // Represents a single display class Monitor : public QObject { Q_OBJECT public: Monitor(DDCA_Display_Info * display_info, int monitorNumber); ~Monitor(); bool supportsDdc(); bool capabilitiesCheckComplete(); bool capabilitiesCheckSuccessful(); DDCA_Feature_List getFeatureList(DDCA_Feature_Subset_Id); DDCA_Display_Ref getDref(); QString dref_repr(); void dbgrpt(); const int _monitorNumber = -1; // 1 based DDCA_Display_Info * _displayInfo; FeatureBaseModel * _baseModel; VcpRequestQueue* _requestQueue; QWidget * _page_moninfo; int _pageno_moninfo; QPlainTextEdit * _moninfoPlainText; QWidget * _page_capabilities; int _pageno_capabilities; QPlainTextEdit * _capabilitiesPlainText; FeatureSelector _curFeatureSelector; VcpThread * _vcpThread; // FEATURES_VIEW_SCROLLAREAVIEW // When using FeaturesScrollAreaView, do not allocate a permanent // QScrollArea and contents. These must be created dynamically // each time features are loaded. FeaturesScrollAreaView * _featuresScrollAreaView = NULL; public slots: void putVcpRequest(VcpRequest * rqst); void vcpThreadFinished(); private: const char * _cls; // className QHash _features; }; #endif // MONITOR_H ddcui-0.3.0/src/base/nc_values_state.cpp000066400000000000000000000043521427175135000201770ustar00rootroot00000000000000/** @file nc_values_state.cpp * Maintains the current state of the NC Feature Values dialog, which * controls which features are shown. */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include "nc_values_state.h" // For NcValues dialog NcValuesSource parsedNcValuesSource_to_NcValuesSource(Parsed_NC_Values_Source val) { NcValuesSource ncvs = NcValuesFromBoth; // put something // yes, the values in NcValuesSource and Parsed_NC_Values_Source match, but relying on that is brittle if (val != NC_VALUES_SOURCE_UNSET) { switch(val) { case NC_VALUES_SOURCE_MCCS: ncvs = NcValuesFromMccs; break; case NC_VALUES_SOURCE_CAPABILITIES: ncvs = NcValuesFromCapabilities; break; case NC_VALUES_SOURCE_BOTH: ncvs = NcValuesFromBoth; break; case NC_VALUES_SOURCE_UNSET: assert(false); // impossible case to avoid compiler warning }; } else { ncvs = NcValuesFromCapabilities; // default } return ncvs; } NcValuesState::NcValuesState() {} NcValuesState::NcValuesState(Parsed_Ddcui_Cmd * parsed_cmd) { if (parsed_cmd->nc_values_source != NC_VALUES_SOURCE_UNSET) _ncValuesSource = parsedNcValuesSource_to_NcValuesSource(parsed_cmd->nc_values_source); } NcValuesState::NcValuesState(const NcValuesState &other) : QObject() { _ncValuesSource = other._ncValuesSource; // _useLatestNcValues = other._useLatestNcValues; } void NcValuesState::changeNcValuesSource(NcValuesSource mode, bool useLatestNcValues) { bool changed = (mode != _ncValuesSource || useLatestNcValues != _useLatestNcValues); _ncValuesSource = mode; // _useLatestNcValues = useLatestNcValues; if (changed) emit ncValuesSourceChanged(_ncValuesSource, _useLatestNcValues); } const char * ncValuesSourceName(NcValuesSource source) { char * result = NULL; switch(source) { case NcValuesFromMccs: result = (char*) "NcValuesSourceFromMccs"; break; case NcValuesFromCapabilities: result = (char*) "NcValuesFromCapabilities"; break; case NcValuesFromBoth: result = (char*) "NcValuesFromBoth"; break; } return result; } ddcui-0.3.0/src/base/nc_values_state.h000066400000000000000000000022301427175135000176350ustar00rootroot00000000000000/** @file nc_values_state.h * Maintains the current state of the NC Feature Values dialog */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef NC_VALUES_STATE_H_ #define NC_VALUES_STATE_H_ #include #include "cmdline/ddcui_parsed_cmd.h" // move inside class? typedef enum { NcValuesFromMccs, NcValuesFromCapabilities, NcValuesFromBoth, } NcValuesSource; class NcValuesState : public QObject { Q_OBJECT public: static const NcValuesSource DefaultNcValuesSource = NcValuesFromCapabilities; static const bool DefaultUseMaximalMccsNcValues = false; NcValuesState(); NcValuesState(Parsed_Ddcui_Cmd * parsedCmd); NcValuesState(const NcValuesState &other); void changeNcValuesSource(NcValuesSource mode, bool useLatestNcValues); NcValuesSource _ncValuesSource = DefaultNcValuesSource; bool _useLatestNcValues = DefaultUseMaximalMccsNcValues; signals: void ncValuesSourceChanged(NcValuesSource valuesSource, bool latestNcValues); }; const char * ncValuesSourceName(NcValuesSource source) ; #endif /* OPTIONS_STATE_H_ */ ddcui-0.3.0/src/base/user_interface_options_state.cpp000066400000000000000000000031271427175135000227700ustar00rootroot00000000000000/** @file user_interface_options_state.cpp * Maintains the current state of the User Interface Options dialog */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // NB was originally named ui_options_state.h etc, but the ui prefix is // special, causes the user interface compiler to look for a dialog named ui_options_state_dialog #include "user_interface_options_state.h" #include "base/core.h" #include "cmdline/ddcui_parsed_cmd.h" UserInterfaceOptionsState::UserInterfaceOptionsState() : _cls(metaObject()->className()) { } UserInterfaceOptionsState::UserInterfaceOptionsState(Parsed_Ddcui_Cmd* parsed_cmd) : _cls(metaObject()->className()) { bool debug = false; TRACEMCF(debug, "Starting"); _controlKeyRequired = parsed_cmd->flags & CMD_FLAG_UI_REQUIRE_CONTROL_KEY; TRACEMCF(debug, "Done"); } UserInterfaceOptionsState::UserInterfaceOptionsState(UserInterfaceOptionsState &other) : QObject() , _cls(metaObject()->className()) { _controlKeyRequired = other._controlKeyRequired; } void UserInterfaceOptionsState::setControlKeyRequired(bool onoff) { bool debug = false; bool old = _controlKeyRequired; bool newControlKeyRequired = onoff; TRACECF(debug, "old = %s, new = %s", SBOOL(_controlKeyRequired), SBOOL(onoff)); if (newControlKeyRequired != old) { _controlKeyRequired = newControlKeyRequired; TRACECF(debug, "emitting controlKeyRequired_changed(%s)", SBOOL(_controlKeyRequired)); emit controlKeyRequired_changed(_controlKeyRequired); } } ddcui-0.3.0/src/base/user_interface_options_state.h000066400000000000000000000015501427175135000224330ustar00rootroot00000000000000/** @file user_interface_options_state.h * Maintains the current state of the User Interface Options dialog */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef USER_INTERFACE_OPTIONS_STATE_H_ #define USER_INTERFACE_OPTIONS_STATE_H_ #include #include "cmdline/ddcui_parsed_cmd.h" class UserInterfaceOptionsState : public QObject { Q_OBJECT public: UserInterfaceOptionsState(); UserInterfaceOptionsState(Parsed_Ddcui_Cmd* parsed_cmd); UserInterfaceOptionsState(UserInterfaceOptionsState &other); static const bool CkrDefault = false; bool _controlKeyRequired = CkrDefault; void setControlKeyRequired(bool onoff); signals: void controlKeyRequired_changed(bool onoff); private: const char * _cls; }; #endif /* USER_INTERFACE_OPTIONS_STATE_H_ */ ddcui-0.3.0/src/base/widget_debug.cpp000066400000000000000000000414761427175135000174610ustar00rootroot00000000000000// widget_debug.cpp // Functions for debugging Qt layouts // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "widget_debug.h" void reportBasicWidgetDimensions( QWidget * w, const char * caller_class, const char * caller_func, const int caller_lineno, const char * caller_filename) { const char * cls = w->metaObject()->className(); QSize sizeHint = w->sizeHint(); QSize minSize = w->minimumSize(); QSize minSizeHint = w->minimumSizeHint(); QSize maxSize = w->maximumSize(); QSizePolicy sp = w->sizePolicy(); QSizePolicy::Policy hp = sp.horizontalPolicy(); QSizePolicy::Policy vp = sp.verticalPolicy(); printftcmf( true, caller_class, NULL, caller_func, caller_lineno, caller_filename, "BASIC WIDGET DIMENSIONS for class %s:, sizePolicy(%s,%s)", cls, sizePolicyName(hp), sizePolicyName(vp) ); printf(" size (%d,%d) sizeHint(%d,%d) minimumSize(%d,%d) minimumSizeHint(%d,%d) maximumSize(%d,%d) \n", // maximumSize(%d,%d)\n", w->width(), w->height(), sizeHint.width(), sizeHint.height(), minSize.width(), minSize.height(), minSizeHint.width(), minSizeHint.height(), maxSize.width(), maxSize.height() ); // maxSize.width(), maxSize.height() ); QMargins margins = w->contentsMargins(); QRect rect = w->contentsRect(); printf(" contents margins (%d,%d,%d,%d) rectangle (%d,%d) \n", margins.top(), margins.right(), margins.bottom(), margins.left(), rect.width(), rect.height() ); } #ifdef NOT_NEEDED void reportBasicWindowDimensions2( const char * classname, const char * func, const int line, const char * filename, const char * format, const char * format, ...) { } #endif void reportWidgetChildren(QWidget * w, const char * msg) { if (msg) puts(msg); QObjectList childs = w->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child[%d]: %s, type:%s\n", ndx, name.toLatin1().data(), clsName); } fflush(stdout); } const char * sizePolicyName(QSizePolicy::Policy policy) { char * s = NULL; switch(policy) { case QSizePolicy::Fixed: s = (char*) "Fixed"; break; case QSizePolicy::Minimum: s = (char*) "Minimum"; break; case QSizePolicy::Maximum: s = (char*) "Maximum"; break; case QSizePolicy::Preferred: s = (char*) "Preferred"; break; case QSizePolicy::Expanding: s = (char*) "Expanding"; break; case QSizePolicy::MinimumExpanding: s = (char*) "MinimumExpanding"; break; case QSizePolicy::Ignored: s = (char*) "Ignored"; break; default: s = (char*) "other"; } return s; } void reportPolicy( QSizePolicy::Policy hp, int depth, const char * msg = nullptr) { int d1 = depth+1; char indent[100]; g_snprintf(indent, 100, "%*s", depth*3, ""); if (msg) printf("%s%s\n", indent, msg); g_snprintf(indent, 100, "%*s", d1*3, ""); // Two ways of looking at the policy field, as bits or as enum printf("%spolicy: %s %s %s %s\n", indent, (hp & QSizePolicy::GrowFlag) ? "Grow" : "", (hp & QSizePolicy::ExpandFlag) ? "Expand" :"", (hp & QSizePolicy::ShrinkFlag) ? "Shrink" : "", (hp & QSizePolicy::IgnoreFlag) ? "Ignore" : ""); char * s = NULL; switch(hp) { case QSizePolicy::Fixed: s = (char*) "Fixed"; break; case QSizePolicy::Minimum: s = (char*) "Minimum"; break; case QSizePolicy::Maximum: s = (char*) "Maximum"; break; case QSizePolicy::Preferred: s = (char*) "Preferred"; break; case QSizePolicy::Expanding: s = (char*) "Expanding"; break; case QSizePolicy::MinimumExpanding: s = (char*) "MinimumExpanding"; break; case QSizePolicy::Ignored: s = (char*) "Ignored"; break; default: s = (char*) "other"; } printf("%s %s\n", indent, s); } void reportQSizePolicy( QSizePolicy p , // const char * className, // const char * funcName, int depth, const char * msg = nullptr) { int d1 = depth+1; char indent[100]; g_snprintf(indent, 100, "%*s", depth*3, ""); if (msg) printf("%s%s\n", indent, msg); g_snprintf(indent, 100, "%*s", d1*3, ""); char buf[100]; Qt::Orientations orientations = p.expandingDirections(); g_snprintf(buf, 100, "%sexpandingDirections: %s %s\n", indent, (orientations & Qt::Horizontal) ? "Horizontal" : "", (orientations & Qt::Vertical) ? "Vertical" : ""); printf("%s%s\n", indent, buf); printf("%shorizontalStretch: %d\n", indent, p.horizontalStretch()); printf("%sverticalStretch: %d\n", indent, p.verticalStretch()); char * s; QSizePolicy::ControlTypes ct = p.controlType(); switch(ct) { case QSizePolicy::DefaultType: s = (char*) "DefaultType"; break; case QSizePolicy::ButtonBox: s = (char*) "ButtonBox"; break; case QSizePolicy::CheckBox: s = (char*) "CheckBox"; break; case QSizePolicy::ComboBox: s = (char*) "ComboBox"; break; case QSizePolicy::Frame: s = (char*) "Frame"; break; case QSizePolicy::GroupBox: s = (char*) "GroupBox"; break; case QSizePolicy::Label: s = (char*) "Label"; break; case QSizePolicy::Line: s = (char*) "Line"; break; case QSizePolicy::LineEdit: s = (char*) "LineEdit"; break; case QSizePolicy::PushButton: s = (char*) "PushButton"; break; case QSizePolicy::RadioButton: s = (char*) "RadioButton"; break; case QSizePolicy::Slider: s = (char*) "Slider"; break; case QSizePolicy::SpinBox: s = (char*) "SpinBox"; break; case QSizePolicy::TabWidget: s = (char*) "TabWidget"; break; case QSizePolicy::ToolButton: s = (char*) "ToolButton"; break; default: s = (char*) "other"; } printf("%scontrolType: %s\n", indent, s); QSizePolicy::Policy hp = p.horizontalPolicy(); reportPolicy(hp, depth+1, "Horizontal Policy:"); reportPolicy(p.verticalPolicy(), depth+1, "Vertical Policy"); // TODO: additional // ->ExpandingDirections(); // more? } void reportLayout( QLayout * lay, int depth) { int d1 = depth+1; char indent[100]; g_snprintf(indent, 100, "%*s", d1*3, ""); QMargins layoutContentsMargins = lay->contentsMargins(); printf("%slayoutContentsMargins: left: %d, top: %d, right: %d, bottom: %d\n", indent, layoutContentsMargins.left(), layoutContentsMargins.top(), layoutContentsMargins.right(), layoutContentsMargins.bottom() ); #ifdef NOT_USEFUL QRect layoutContentsRect = lay->contentsRect(); printf("layoutContentsRect: x: %d, y: %d, width: %d, height: %d\n", layoutContentsRect.x(), layoutContentsRect.y(), layoutContentsRect.width(), layoutContentsRect.height()); #endif // spacing between the widgets inside the layout // int layoutSpacing = lay->spacing(); printf("%slayout spacing: %d\n", indent, lay->spacing()); // layoutSpacing); char buf[100]; Qt::Orientations orientations = lay->expandingDirections(); g_snprintf(buf, 100, "%sexpandingDirections: %s %s\n", indent, (orientations & Qt::Horizontal) ? "Horizontal" : "", (orientations & Qt::Vertical) ? "Vertical" : ""); puts(buf); QSize sz = lay->minimumSize(); printf("%sminimumSize: %d,%d\n", indent, sz.width(), sz.height() ); sz = lay->maximumSize(); printf("%smaximumSize: %d,%d\n", indent, sz.width(), sz.height() ); // and more } void reportWidgetDimensions( QWidget * w, const char * className, const char * funcName, const char * msg) { int depth = 0; int d1 = depth+1; char indent[100]; g_snprintf(indent, 100, "%*s", d1*3, ""); if (msg) printf("%s\n", msg); // printf("(%s::%s) Dimensions:\n", className, funcName); QSize sz = w->baseSize(); printf("%sbaseSize: %d,%d\n", indent, sz.width(), sz.height()); sz = w->sizeIncrement(); printf("%ssizeIncrement: %d,%d\n", indent, sz.width(), sz.height()); // QSize minimumSize = w->minimumSize(); // printf("%sminimumSize: %d,%d\n", indent, minimumSize.width(), minimumSize.height()); printf("%sminimumSize: %d,%d\n", indent, w->minimumWidth(), w->minimumHeight()); sz = w->minimumSizeHint(); printf("%sminimumSizeHint: %d,%d\n", indent, sz.width(), sz.height()); // QSize maximumSize = w->maximumSize(); printf("%smaximumSize: %d,%d\n", indent, w->maximumWidth(), w->maximumHeight()); // sz = w->size(); // size of widget excluding any window frame printf("%ssize: %d,%d\n", indent, w->width(), w->height()); // recommended widget size sz = w->sizeHint(); printf("%ssizeHint: %d,%d\n", indent, sz.width(), sz.height()); // size of the widget including any window frame QSize frameSize = w->frameSize(); printf("%sframeSize: %d,%d\n", indent, frameSize.width(), frameSize.height()); // both work // int m_left, m_right, m_top, m_bottom; // w->getContentsMargins(&m_left, &m_top, &m_right, &m_bottom); // printf("%scontents margins: left=%d, top=%d, right=%d, bottom=%d\n", indent, // m_left, m_top, m_right, m_bottom); QMargins contentsMargins = w->contentsMargins(); printf("%scontentsMargins: left=%d, top=%d, right=%d, bottom=%d\n", indent, contentsMargins.left(), contentsMargins.top(), contentsMargins.right(), contentsMargins.bottom() ); printf("%shasHeightForWidth: %s\n", indent, (w->hasHeightForWidth()) ? "True" : "False"); printf("%supdatesEnabled: %s\n", indent, (w->updatesEnabled()) ? "True" : "False"); printf("%svisible: %s\n", indent, (w->isVisible()) ? "True" : "False"); printf("%shidden: %s\n", indent, (w->isHidden()) ? "True" : "False"); Qt::LayoutDirection direction = w->layoutDirection(); char * s = NULL; switch(direction) { case Qt::LeftToRight: s = (char *) "LeftToRight"; break; case Qt::RightToLeft: s = (char *) "RightToLeft"; break; case Qt::LayoutDirectionAuto: s = (char*) "LayoutDirectionAuto"; break; } printf("%slayoutDirection: %d - %s\n", indent, direction, s); #ifdef USELESS QRect childrenRect = w->childrenRect(); printf("%schildrenRect: x: %d, y: %d, width: %d, height: %d\n", indent, childrenRect.x(), childrenRect.y(), childrenRect.width(), childrenRect.height()); // specifies a clip region for a painter // QRegion childrenRegion = w->childrenRegion(); QRect frameGeometry = w->frameGeometry(); printf("%sframeGeometry: x: %d, y: %d, width: %d, height: %d\n", indent, frameGeometry.x(), frameGeometry.y(), frameGeometry.width(), frameGeometry.height()); QRect normalGeometry = w->normalGeometry(); printf("%snormalGeometry: x: %d, y: %d, width: %d, height: %d\n", indent, normalGeometry.x(), normalGeometry.y(), normalGeometry.width(), normalGeometry.height()); QRect rect = w->rect(); printf("%srect: x: %d, y: %d, width: %d, height: %d\n", indent, rect.x(), rect.y(), rect.width(), rect.height()); QRect contentsRect = w->contentsRect(); printf("%scontentsRect: x: %d, y: %d, width: %d, height: %d\n", indent, contentsRect.x(), contentsRect.y(), contentsRect.width(), contentsRect.height()); #endif QSizePolicy sizePolicy = w->sizePolicy(); reportQSizePolicy(sizePolicy, d1, "widget sizePolicy:"); QLayout * lay = w->layout(); if (lay) { printf("%sLayout:\n", indent); reportLayout(lay, d1+1); } else printf("%sNo layout set\n", indent); printf("\n"); fflush(stdout); } void reportFrameDimensions( QFrame * f, const char * className, const char * funcName, const char * msg) { if (msg) printf("%s\n", msg); printf("(%s::%s) Frame Dimension Information: \n", className, funcName); fflush(stdout); QRect frameRect = f->frameRect(); printf("frameRect: x: %d, y: %d, width: %d, height: %d\n", frameRect.x(), frameRect.y(), frameRect.width(), frameRect.height()); QFrame::Shape shape = f->frameShape(); char * s = NULL; switch(shape) { case QFrame::NoFrame: s = (char*) "NoFrame"; break; case QFrame::Box: s = (char*) "Box"; break; case QFrame::Panel: s = (char*) "Panel"; break; case QFrame::StyledPanel: s = (char*) "StyledPanel"; break; case QFrame::HLine: s = (char*) "HLIine"; break; case QFrame::VLine: s = (char*) "VLine"; break; case QFrame::WinPanel: s = (char*) "WinPanel"; break; } printf("shape: %d - %s\n", shape, s); // int style = f->frameStyle() printf("frameWidth: %d\n", f->frameWidth() ); printf("lineWidth: %d\n", f->lineWidth() ); reportWidgetDimensions(f, className, funcName); } void reportLabelDimensions( QLabel * label, const char * className, const char * funcName, const char * msg) { if (msg) printf("%s\n", msg); printf("(%s::%s) Label Dimension Information: \n", className, funcName); fflush(stdout); printf("indent: %d\n", label->indent()); reportFrameDimensions(label, className, funcName, NULL); } void whereIsApplication() { printf("Application screens\n"); QApplication* qGuiApplication = qApp; QList screens = qGuiApplication->screens(); for(int ndx=0; ndx < screens.count();ndx++) { QScreen* screen = screens.at(ndx); QRect geometry = screen->availableGeometry(); QSize availableSize = screen->availableSize(); QSize size = screen->size(); QSize virtualSize = screen->virtualSize(); printf("screen[%d]\n", ndx); printf(" geometry: left=%d, top=%d, right=%d, bottom=%d\n", geometry.left(), geometry.top(), geometry.right(), geometry.bottom() ); printf(" availableSize: %d,%d\n", availableSize.width(), availableSize.height()); printf(" Size: %d,%d\n", size.width(), size.height()); printf(" virtualSize: %d,%d\n", virtualSize.width(), virtualSize.height()); } QDesktopWidget * desktopWidget = QApplication::desktop(); printf("Desktop widget width, height: %d,%d\n", desktopWidget->width(), desktopWidget->height() ); #ifdef FOR_TESTING printf("screen count: %d\n", desktopWidget->screenCount() ); printf("is virtual desktop: %s\n", SBOOL( desktopWidget->isVirtualDesktop() ) ); QRect geometry = desktopWidget->availableGeometry(); printf(" geometry: left=%d, top=%d, right=%d, bottom=%d\n", geometry.left(), geometry.top(), geometry.right(), geometry.bottom() ); #endif } void whereAmI(QWidget * w, const char * msg) { if (msg) printf("%s\n", msg); else printf("This widget:\n"); printf(" x,y (upper left == pos) =%d,%d\n", w->x(), w->y()); printf(" width,height = %d,%d\n", w->width(), w->height() ); // QScreen * screen = w->screen(); // bit in 5.12 printf(" isWindow(): %s\n", SBOOL(w->isWindow() )) ; if (w->isWindow() ) { #ifdef OUT QWindow* wind = dynamic_cast(w); QScreen * screen = wind->screen(); // this is the line that causes crash QRect geometry = screen->availableGeometry(); printf(" screen geometry: left=%d, top=%d, right=%d, bottom=%d\n", geometry.left(), geometry.top(), geometry.right(), geometry.bottom() ); #endif } } void dbgrptQKeyEvent(QKeyEvent * event) { printf(" key: %d\n", event->key()); printf(" modifiers: 0x%x\n", (unsigned int) event->modifiers()); printf(" nativeModifiers: 0x%08x\n", event->nativeModifiers()); printf(" nativeScanCode: 0x%08x\n", event->nativeScanCode()); } ddcui-0.3.0/src/base/widget_debug.h000066400000000000000000000025471427175135000171220ustar00rootroot00000000000000// widget_debug.h - Functions for debugging Qt layouts // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef WIDGET_DEBUG_H_ #define WIDGET_DEBUG_H_ class QWidget; class QFrame; class QLabel; class QString; class QKeyEvent; const char * sizePolicyName( QSizePolicy::Policy policy); void reportWidgetChildren( QWidget * w, const char * msg = nullptr); void reportLabelDimensions( QLabel * l, const char * className, const char * funcName, const char * msg=nullptr); void reportFrameDimensions( QFrame * f, const char * className, const char * funcName, const char * msg=nullptr); void reportWidgetDimensions( QWidget * w, const char * className, const char * funcName, const char * msg=nullptr); void reportBasicWidgetDimensions( QWidget * w, const char * caller_class, const char * caller_func, const int caller_lineno, const char * caller_filename ); #define REPORT_BASIC_WIDGET_DIMENSIONS( _widget) \ do { \ reportBasicWidgetDimensions(_widget, this->metaObject()->className(), __func__, __LINE__, __FILE__); \ } while(0) void whereIsApplication(); void whereAmI(QWidget * w, const char * msg); void dbgrptQKeyEvent(QKeyEvent * event); #endif /* WIDGET_DEBUG_H_ */ ddcui-0.3.0/src/c_util/000077500000000000000000000000001427175135000146555ustar00rootroot00000000000000ddcui-0.3.0/src/c_util/coredefs_base.h000066400000000000000000000010621427175135000176110ustar00rootroot00000000000000/** \file coredefs_base.h * Portion of coredefs.h shared with ddcui */ // Copyright (C) 2021-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef COREDEFS_BASE_H_ #define COREDEFS_BASE_H_ /** Raw byte */ typedef unsigned char Byte; #ifndef ARRAY_SIZE /** Number of entries in array */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif #ifndef ASSERT_IFF #define ASSERT_IFF(_cond1, _cond2) \ assert( ( (_cond1) && (_cond2) ) || ( !(_cond1) && !(_cond2) ) ) #endif #endif /* COREDEFS_BASE_H_ */ ddcui-0.3.0/src/c_util/data_structures.c000066400000000000000000001320711427175135000202410ustar00rootroot00000000000000/** @file data_structures.c * General purpose data structures */ // Copyright (C) 2014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ #include #include #include #include #include #include #include // for MIN, MAX /** \endcond */ #include "report_util.h" #include "string_util.h" #include "data_structures.h" // // Buffer with length management // bool trace_buffer_malloc_free = false; bool trace_buffer = false; // controls buffer tracing bool trace_buffer_resize = false; /** Allocates a **Buffer** instance * * @param size maximum number of bytes that buffer can hold * @param trace_msg optional trace message * * @return pointer to newly allocated instance */ Buffer * buffer_new(int size, const char * trace_msg) { int hacked_size = size+16; // try allocating extra space see if free failures go away - overruns? // printf("(%s) sizeof(Buffer)=%ld, size=%d\n", __func__, sizeof(Buffer), size); // sizeof(Buffer) == 16 Buffer * buffer = (Buffer *) malloc(sizeof(Buffer)); memcpy(buffer->marker, BUFFER_MARKER, 4); buffer->bytes = (Byte *) calloc(1, hacked_size); // hack buffer->buffer_size = size; buffer->len = 0; buffer->size_increment = 0; if (trace_buffer_malloc_free) printf("(%s) Allocated buffer. buffer=%p, buffer->bytes=%p, &buffer->bytes=%p, %s\n", __func__, (void*)buffer, buffer->bytes, (void*)&(buffer->bytes), trace_msg); return buffer; } /** Sets a size increment for the buffer, allowing it to be dynamically * resized if necessary. * * @param buf pointer to Buffer instance * @param size_increment if resizing is necessary, the buffer size will be * increased by this amount */ void buffer_set_size_increment(Buffer * buf, uint16_t size_increment) { buf->size_increment = size_increment; } /** Allocates a **Buffer** instance and sets an initial value * * @param bytes pointer to initial value * @param bytect length of initial value, the buffer size is * also set to this value * @param trace_msg optional trace message * * @return pointer to newly allocated instance * * @remark * Setting the buffer size to the initial value does not allow for * expansion, unless buffer_set_size_increment() is called */ Buffer * buffer_new_with_value(Byte * bytes, int bytect, const char * trace_msg) { Buffer* buf = buffer_new(bytect, trace_msg); buffer_put(buf, bytes, bytect); return buf; } /** Copies a Buffer. * * @param srcbuf instance to copy * @param trace_msg optional trace message * * @return newly allocated copy * * @remark * - The contents of the newly allocated Buffer is identical to * the original, but the maximum length and size increment are * not. Is this an issue? * - Not currently used. (3/2017) */ Buffer * buffer_dup(Buffer * srcbuf, const char * trace_msg) { return buffer_new_with_value(srcbuf->bytes, srcbuf->len, trace_msg); } /** Frees a Buffer instance. All memory associated with the Buffer is released. * * @param buffer pointer to Buffer instance, must be valid * @param trace_msg optional trace message */ void buffer_free(Buffer * buffer, const char * trace_msg) { if (trace_buffer_malloc_free) printf("(%s) Starting. buffer = %p\n", __func__, (void*) buffer); // ASSERT_WITH_BACKTRACE(buffe#ifdef TEMPr); // ASSERT_WITH_BACKTRACE(memcmp(buffer->marker, BUFFER_MARKER, 4) == 0); if (buffer->bytes) { if (trace_buffer_malloc_free) printf("(%s) Freeing buffer->bytes = %p, &buffer->bytes=%p\n", __func__, buffer->bytes, (void*)&(buffer->bytes)); free(buffer->bytes); } if (trace_buffer_malloc_free) printf("(%s) Freeing buffer = %p, %s\n", __func__, (void*)buffer, trace_msg); buffer->marker[3] = 'x'; free(buffer); if (trace_buffer_malloc_free) printf("(%s) Done\n", __func__); } /** Returns the length of the data in the Buffer. * * @param buffer pointer to Buffer instance * @return number of bytes in Buffer */ int buffer_length(Buffer * buffer) { return buffer->len; } /** Adjusts the number of bytes in a Buffer. * * @param buffer pointer to buffer instance * @param bytect new length of buffer contents, must be less that * the maximum size of the buffer */ void buffer_set_length(Buffer * buffer, int bytect) { if (trace_buffer) printf("(%s) bytect=%d, buffer_size=%d\n", __func__, bytect, buffer->buffer_size); assert (bytect <= buffer->buffer_size); buffer->len = bytect; } /** Sets the value stored in a Buffer to a range of bytes. * The buffer length is updated. * * @param buffer pointer to Buffer instance * @param bytes pointer to bytes to store in buffer * @param bytect number of bytes to store */ void buffer_put(Buffer * buffer, Byte * bytes, int bytect) { if (trace_buffer) { printf("(%s) buffer->bytes = %p, bytes=%p, bytect=%d\n", __func__, buffer->bytes, bytes, bytect); printf("(%s) cur len = %d, storing |%.*s|, bytect=%d\n", __func__, buffer->len, bytect, bytes, bytect); } assert (bytect <= buffer->buffer_size); memcpy(buffer->bytes, bytes, bytect); buffer->len = buffer->len + bytect; // printf("(%s) Returning. cur len = %d\n", __func__, buffer->len); } /** Stores a single byte at a specified offset in the buffer. * The buffer length is not updated. * * @param buf pointer to Buffer instance * @param offset offset in buffer at which to store byte * @param byte byte value to be stored * * @remark * A dangerous function. Use with care. */ void buffer_set_byte(Buffer * buf, int offset, Byte byte) { if (trace_buffer) printf("(%s) Storing 0x%02x at offset %d\n", __func__, byte, offset); assert(offset >= 0 && offset < buf->buffer_size); buf->bytes[offset] = byte; } /** Sets a range of bytes in a Buffer. * The logical length of the buffer is not updated. * * @param buf pointer to Buffer instance * @param offset offset in buffer at which to store byte * @param bytes pointer to bytes to store * @param bytect number of bytes to store */ void buffer_set_bytes(Buffer * buf, int offset, Byte * bytes, int bytect) { if (trace_buffer) printf("(%s) Storing %d bytes at offset %d, buffer_size=%d\n", __func__, bytect, offset, buf->buffer_size); assert(offset >= 0 && (offset + bytect) <= buf->buffer_size); memcpy(buf->bytes+offset, bytes, bytect); } /** Appends a sequence of bytes to the current contents of a Buffer. * The buffer length is updated. * * @param buffer pointer to the Buffer object * @param bytes pointer to the bytes to be appended * @param bytect number of bytes to append */ void buffer_append(Buffer * buffer, Byte * bytes, int bytect) { // printf("(%s) Starting. buffer=%p\n", __func__, buffer); assert( memcmp(buffer->marker, BUFFER_MARKER, 4) == 0); if (trace_buffer) { printf("(%s) cur len = %d, appending |%.*s|, bytect=%d\n", __func__, buffer->len, bytect, bytes, bytect); printf("(%s) buffer->bytes + buffer->len = %p, bytes=%p, bytect=%d\n", __func__, buffer->bytes+buffer->len, bytes, bytect); } // buffer->len + 2 + bytect .. why the + 2? int required_size = buffer->len + 2 + bytect; if (required_size > buffer->buffer_size && buffer->size_increment > 0) { int new_size = MAX(required_size, buffer->buffer_size + buffer->size_increment); if (trace_buffer_resize) printf("(%s) Resizing. old size = %d, new size = %d\n", __func__, buffer->buffer_size, new_size); buffer_extend(buffer, new_size - buffer->buffer_size); } assert(buffer->len + 2 + bytect <= buffer->buffer_size); memcpy(buffer->bytes + buffer->len, bytes, bytect); buffer->len = buffer->len + bytect; // printf("(%s) Returning. cur len = %d\n", __func__, buffer->len); } /** Appends a string to the current string in the buffer. * * @param buffer pointer to Buffer * @param str string to append * * @remark * If the buffer is not empty, checks by assert that * the last character stored is '\0'; */ void buffer_strcat(Buffer * buffer, char * str) { assert( memcmp(buffer->marker, BUFFER_MARKER, 4) == 0); if (buffer->len == 0) { buffer_append(buffer, (Byte *) str, strlen(str)+1); } else { assert(buffer->bytes[buffer->len - 1] == '\0'); buffer_set_length(buffer, buffer->len - 1); // truncate trailing \0 buffer_append(buffer, (Byte *) str, strlen(str) + 1); } } /** Appends a single byte to the current value in the buffer. * The buffer length is updated. * * @param buffer pointer to Buffer instance * @param byte value to append * * @todo Increase buffer size if necessary and size_increment > 0 */ void buffer_add(Buffer * buffer, Byte byte) { assert( memcmp(buffer->marker, BUFFER_MARKER, 4) == 0); assert(buffer->len + 1 <= buffer->buffer_size); buffer->bytes[buffer->len++] = byte; } /** Tests whether 2 Buffer instances have the same * contents. * * @param buf1 pointer to first Buffer * @param buf2 pointer to second Buffer * @return true if contents are identical, false if not * * @remark * - If both buf1==NULL and buf2==NULL, the result is true */ bool buffer_eq(Buffer* buf1, Buffer* buf2) { bool result = false; if (!buf1 && !buf2) result = true; else if (buf1 && buf2 && buf1->len == buf2->len && memcmp(buf1->bytes, buf2->bytes, buf1->len) == 0 ) result = true; return result; } /** Increases the size of a Buffer * * @param buf pointer to Buffer instance * @param addl_size number of additional bytes */ void buffer_extend(Buffer* buf, int addl_size) { int new_size = buf->buffer_size + addl_size; buf->bytes = realloc(buf->bytes, new_size); buf->buffer_size = new_size; } /** Displays all fields of the Buffer. * This is a debugging function. * * @param buffer pointer to Buffer instance * * @remark * Output is written to stdout. */ void buffer_dump(Buffer * buffer) { printf("Buffer at %p, bytes addr=%p, len=%d, max_size=%d\n", (void*)buffer, buffer->bytes, buffer->len, buffer->buffer_size); // printf(" bytes end addr=%p\n", buffer->bytes+buffer->buffer_size); if (buffer->bytes) hex_dump(buffer->bytes, buffer->len); } /** Displays all fields of the Buffer using rpt_* functions. * This is a debugging function. * * @param buffer pointer to Buffer instance * @param depth logical indentation depth * * @remark * Output is written to stdout. */ void buffer_rpt(Buffer * buffer, int depth) { rpt_vstring(depth, "Buffer at %p, bytes addr=%p, len=%d, max_size=%d", (void*)buffer, buffer->bytes, buffer->len, buffer->buffer_size); if (buffer->bytes) rpt_hex_dump(buffer->bytes, buffer->len, depth); } // // Circular_String_Buffer // /** Allocates a new #Circular_String_Buffer * * @param size buffer size (number of entries) * @return newly allocated #Circular_String_Buffer */ Circular_String_Buffer * csb_new(int size) { Circular_String_Buffer * csb = calloc(1, sizeof(Circular_String_Buffer)); csb->lines = calloc(size, sizeof(char*)); csb->size = size; csb->ct = 0; return csb; } /** Appends a string to a #Circular_String_Buffer. * * @param csb #Circular_String_Buffer * @param line string to append * @param copy if true, a copy of the string is appended to the buffer * if false, the string itself is appended */ void csb_add(Circular_String_Buffer * csb, char * line, bool copy) { int nextpos = csb->ct % csb->size; // printf("(%s) Adding at ct %d, pos %d, line |%s|\n", __func__, csb->ct, nextpos, line); if (csb->lines[nextpos]) free(csb->lines[nextpos]); if (copy) csb->lines[nextpos] = g_strdup(line); else csb->lines[nextpos] = line; csb->ct++; } /** All the strings in a #Circular_String_Buffer are moved to a newly * allocated GPtrArray. The count of lines in the now empty #Circular_String_Buffer * is set to 0. * * @param csb #Circular_String_Buffer to convert * @return newly allocated #GPtrArray */ GPtrArray * csb_to_g_ptr_array(Circular_String_Buffer * csb) { // printf("(%s) csb->size=%d, csb->ct=%d\n", __func__, csb->size, csb->ct); GPtrArray * pa = g_ptr_array_sized_new(csb->ct); int first = 0; if (csb->ct > csb->size) first = csb->ct % csb->size; // printf("(%s) first=%d\n", __func__, first); for (int ndx = 0; ndx < csb->ct; ndx++) { int pos = (first + ndx) % csb->size; char * s = csb->lines[pos]; // printf("(%s) line %d, |%s|\n", __func__, ndx, s); g_ptr_array_add(pa, s); } csb->ct = 0; return pa; } // // Identifier id to name and description lookup // /** Returns the name of an entry in a Value_Name_Title table. * * @param table pointer to table * @param val value to lookup * * @return name of value, NULL if not found */ char * vnt_name(Value_Name_Title* table, uint32_t val) { // printf("(%s) val=%d\n", __func__, val); // debug_vnt_table(table); char * result = NULL; Value_Name_Title * cur = table; for (; cur->name; cur++) { if (val == cur->value) { result = cur->name; break; } } return result; } /** Returns the title (description field) of an entry in a Value_Name_Title table. * * @param table pointer to table * @param val value to lookup * * @return title of value, NULL if not found */ char * vnt_title(Value_Name_Title* table, uint32_t val) { // printf("(%s) val=%d\n", __func__, val); // debug_vnt_table(table); char * result = NULL; Value_Name_Title * cur = table; for (; cur->name; cur++) { if (val == cur->value) { result = cur->title; break; } } return result; } /** Searches a Value_Name_Title_Table for a specified name or title, * and returns its id value. * * @param table a Value_Name_Title table * @param s string to search for * @param use_title if false, search name field\n * if true, search title field * @param ignore_case if true, search is case-insensitive * @param default_id value to return if not found * * @result value id */ uint32_t vnt_find_id( Value_Name_Title_Table table, const char * s, bool use_title, // if false, search by symbolic name, if true, search by title bool ignore_case, uint32_t default_id) { assert(s); uint32_t result = default_id; Value_Name_Title * cur = table; for (; cur->name; cur++) { char * comparand = (use_title) ? cur->title : cur->name; if (comparand) { int comprc = (ignore_case) ? strcasecmp(s, comparand) : strcmp( s, comparand); if (comprc == 0) { result = cur->value; break; } } } return result; } /** Interprets an integer whose bits represent named flags. * * @param flags_val value to interpret * @param bitname_table pointer to Value_Name table * @param use_title if **true**, use the **title** field of the table,\n * if **false**, use the **name** field of the table * @param sepstr if non-NULL, separator string to insert between values * * @return newly allocated character string * * @remark * - It is the responsibility of the caller to free the returned string * - If a referenced **title** field is NULL, "missing" is used as the value */ char * vnt_interpret_flags( uint32_t flags_val, Value_Name_Title_Table bitname_table, bool use_title, char * sepstr) { bool debug = false; if (debug) printf("(%s) Starting. flags_val=0x%08x, bitname_table=%p, use_title=%s, sepstr=|%s|\n", __func__, flags_val, (void*)bitname_table, sbool(use_title), sepstr); GString * sbuf = g_string_sized_new(200); bool first = true; Value_Name_Title * cur_entry = bitname_table; while (cur_entry->name) { if (debug) printf("(%s) cur_entry=%p, Comparing flags_val=0x%08x vs cur_entry->value = 0x%08x\n", __func__, (void*)cur_entry, flags_val, cur_entry->value); if (!flags_val && cur_entry->value == flags_val) { // special value for no bit set char * sval = (use_title) ? cur_entry->title : cur_entry->name; if (!sval) sval = "missing"; g_string_append(sbuf, sval); break; } if (flags_val & cur_entry->value) { if (first) first = false; else { if (sepstr) { g_string_append(sbuf, sepstr); } } char * sval = (use_title) ? cur_entry->title : cur_entry->name; if (!sval) { sval = "missing"; } g_string_append(sbuf, sval); } cur_entry++; } char * result = strdup(sbuf->str); g_string_free(sbuf, true); if (debug) printf("(%s) Done. Returning: |%s|\n", __func__, result); return result; } /** Shows the contents of a **Value_Name_Title table. * Output is written to stdout. * * @param table pointer to table */ void vnt_debug_table(Value_Name_Title * table) { printf("Value_Name_Title table:\n"); Value_Name_Title * cur = table; for (; cur->name; cur++) { printf(" %2d %-30s %s\n", cur->value, cur->name, cur->title); } } // bva - Byte Value Array // // An opaque structure containing an array of bytes that // can grow dynamically. Note that the same byte can // appear multiple times. /** Creates a new **Byte_Value_Array** instance. * @return newly allocated **Byte_Value_Array**. */ Byte_Value_Array bva_create() { GByteArray * ga = g_byte_array_new(); return (Byte_Value_Array) ga; } /** Creates a new **Byte_Value_Array** instance, * containing the values from an existing instance * that satisfy the filter function. * * @param bva **Byte_Value_Array** instance * @param filter_func function that takes a byte value as an argument, * returning true if the value should be included * in the output **Byte_Value_Array** * @return new **Byte_Value_Array** */ Byte_Value_Array bva_filter(Byte_Value_Array bva, IFilter filter_func) { GByteArray * src = (GByteArray*) bva; GByteArray * result = g_byte_array_new(); for (guint ndx=0; ndx < src->len; ndx++) { guint8 v = src->data[ndx]; // Byte v1 = v; if (filter_func(v)) bva_append(result,v); } return (Byte_Value_Array) result; } /** Returns the number of entries in a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance * @return number of entries */ int bva_length(Byte_Value_Array bva) { GByteArray* ga = (GByteArray*) bva; return ga->len; } /** Adds a value to a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance * @param item value to add */ void bva_append(Byte_Value_Array bva, Byte item) { GByteArray* ga = (GByteArray*) bva; #ifdef NDEBUG g_byte_array_append(ga, &item, 1); #else GByteArray * ga2 = g_byte_array_append(ga, &item, 1); assert(ga2 == ga); #endif } /** Gets a value by its index from a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance * @param ndx index of entry * @return value * * **ndx** must be a valid value. * The only check is by assert(). */ Byte bva_get(Byte_Value_Array bva, guint ndx) { GByteArray* ga = (GByteArray*) bva; assert(ndx < ga->len); guint8 v = ga->data[ndx]; Byte v1 = v; return v1; } /** Checks if a **Byte_Value_Array** contains a value. * * @param bva **Byte_Value_Array** instance * @param item value to check for * @return true/false */ bool bva_contains(Byte_Value_Array bva, Byte item) { GByteArray* ga = (GByteArray*) bva; guint ndx; bool result = false; // printf("(%s) item=0x%02x, ga->len=%d\n", __func__, item, ga->len); for (ndx=0; ndx < ga->len; ndx++) { guint8 v = ga->data[ndx]; // Byte v1 = v; if (v == item) { result = true; break; } } // printf("(%s) returning %d\n", __func__, result); return result; } // Comparison function used by gba_sort() static int bva_comp_func(const void * val1, const void * val2) { const guint8 * v1 = val1; const guint8 * v2 = val2; int result = 0; if (*v1 < *v2) result = -1; else if (*v1 > *v2) result = 1; // printf("(%s) *v1=%u, *v2=%u, returning: %d\n", __func__, *v1, *v2, result); return result; } /** Sorts a **Byte_Value_Array** in ascending order * * @param bva **Byte_Value_Array** instance */ void bva_sort(Byte_Value_Array bva) { // printf("(%s) Starting", __func__); GByteArray* ga = (GByteArray*) bva; qsort(ga->data, ga->len, 1, bva_comp_func); // printf("(%s) Done", __func__); } /** Compare 2 sorted #Byte_Value_Array instances for equality. * If the same value occurs multiple times in one array, it * must occur the same number of times in the other. * * @param bva1 pointer to first instance * @param bva2 pointer to second instance * \retval true arrays are identical * \retval false arrays not identical * * @remark * If bva1 or bva2 is null, it is considered to contain 0 values. */ bool bva_sorted_eq(Byte_Value_Array bva1, Byte_Value_Array bva2) { int len1 = (bva1) ? bva_length(bva1) : 0; int len2 = (bva2) ? bva_length(bva2) : 0; bool result = true; if (len1 != len2) { result = false; } else if ( (len1+len2) > 0 ) { for (int ndx = 0; ndx < bva_length(bva1); ndx++) { if (bva_get(bva1,ndx) != bva_get(bva2,ndx)) result = false; } } return result; } /** Returns the bytes from a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance * @return pointer to bytes within * * @remark * The length of the bytes returned must be obtained from **bva_length()**. * Alternatively, consider returning a **Buffer**. * @remark * Caller should not free the returned pointer. */ Byte * bva_bytes(Byte_Value_Array bva) { GByteArray* ga = (GByteArray*) bva; // Byte * result = calloc(ga->len, sizeof(guint8)); // memcpy(result, ga->data, ga->len); Byte * result = ga->data; return result; } /** Returns a string representation of the data in a **Byte_Value_Array. * * @param bva **Byte_Value_Array** instance * @param as_hex if true, use 2 character hex representation, * if false, use 1-3 character integer representation * @param sep separator string between values, if NULL then none * @return string representation of data, caller must free */ char * bva_as_string(Byte_Value_Array bva, bool as_hex, char * sep) { assert(bva); GByteArray* ga = (GByteArray*) bva; if (!sep) sep = ""; int len = ga->len; Byte * bytes = ga->data; int sepsz = strlen(sep); int alloc_sz = len * (3+sepsz) + 1; // slightly large, but simpler to compute char * buf = calloc(1, alloc_sz); for (int ndx = 0; ndx < len; ndx++) { char * cursep = (ndx > 0) ? sep : ""; if (as_hex) snprintf(buf + strlen(buf), alloc_sz-strlen(buf), "%s%02x", cursep, bytes[ndx]); else snprintf(buf + strlen(buf), alloc_sz-strlen(buf), "%s%d", cursep, bytes[ndx]); } return buf; } /** Destroy a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance */ void bva_free(Byte_Value_Array bva) { GByteArray* ga = (GByteArray*) bva; g_byte_array_free(ga,TRUE); } /** Debugging function to report the contents of a **Byte_Value_Array**. * * @param bva **Byte_Value_Array** instance * @param title if non-null, line to print at start of report */ void bva_report(Byte_Value_Array bva, char * title) { if (title) printf("%s\n", title); int ct = bva_length(bva); int ndx = 0; for (; ndx < ct; ndx++) { Byte hval = bva_get(bva, ndx); printf(" %02X\n", hval); } } #ifdef TESTS // Tests and sample code int egmain(int argc, char** argv) { GList* list1 = NULL; list1 = g_list_append(list1, "Hello world!"); // generates warning: // printf("The first item is '%s'\n", g_list_first(list1)->data); g_list_free(list1);bbf_to_string GSList* list = NULL; printf("The list is now %d items long\n", g_slist_length(list)); list = g_slist_append(list, "first"); list = g_slist_append(list, "second"); printf("The list is now %d items long\n", g_slist_length(list)); g_slist_free(list); return 0; } void test_value_array() { Byte_Value_Array bva = bva_create(); bva_append(bva, 0x01); bva_append(bva, 0x02); int ndx = 0; int ct = bva_length(bva); for (;ndx < ct; ndx++) { Byte val = bva_get(bva, ndx); printf("Value[%d] = 0x%02x\n", ndx, val); } bva_free(bva); } #endif // // Bit_Set_256 - A data structure containing 256 flags // const Bit_Set_256 EMPTY_BIT_SET_256 = {{0}}; /** Sets a flag in a #Bit_Set_256 * * @param flags existing #Bit_Set_256 value * @param flagno flag number to set (0 based) * @return updated set */ Bit_Set_256 bs256_insert( Bit_Set_256 bitset, Byte bitno) { bool debug = false; Bit_Set_256 result = bitset; int bytendx = bitno >> 3; int shiftct = bitno & 0x07; Byte flagbit = 0x01 << shiftct; if (debug) { printf("(%s) bitno=0x%02x, bytendx=%d, shiftct=%d, flagbit=0x%02x\n", __func__, bitno, bytendx, shiftct, flagbit); } result.bytes[bytendx] |= flagbit; if (debug) { char * bs1 = strdup(bs256_to_string(bitset, "","")); char * bs2 = strdup(bs256_to_string(result, "","")); printf("(%s) old bitstring=%s, value %d, returning: %s\n", __func__, bs1, bitno, bs2); free( bs1); free(bs2); } return result; } /** Tests if a bit is set in a #Bit_Set_256. * * @param bitset #Bit_Set_256 to check * @param bitno bit number to test (0 based) * @return true/false */ bool bs256_contains( Bit_Set_256 bitset, Byte bitno) { bool debug = false; int flagndx = bitno >> 3; int shiftct = bitno & 0x07; Byte flagbit = 0x01 << shiftct; // printf("(%s) bitno=0x%02x, flagndx=%d, shiftct=%d, flagbit=0x%02x\n", // __func__, bitno, flagndx, shiftct, flagbit); bool result = bitset.bytes[flagndx] & flagbit; if (debug) { printf("(%s) bitset:\n ",__func__); for (int ndx = 0; ndx < 32; ndx++) { printf("%02x", bitset.bytes[ndx]); } printf("\n"); printf("(%s) bit %d, returning: %d\n", __func__, bitno, result); } return result; } /** Returns the bit number of the first bit set. * @param bitset #Bit_Set_256 to check * @return number of first bit that is set (0 based), * -1 if no bits set */ int bs256_first_bit_set( Bit_Set_256 bitset) { int result = -1; for (int ndx = 0; ndx < 256; ndx++) { if (bs256_contains(bitset, ndx)) { result = ndx; break; } } return result; } bool bs256_eq( Bit_Set_256 set1, Bit_Set_256 set2) { return memcmp(&set1, &set2, 32) == 0; } Bit_Set_256 bs256_or( Bit_Set_256 set1, Bit_Set_256 set2) { Bit_Set_256 result; for (int ndx = 0; ndx < 32; ndx++) { result.bytes[ndx] = set1.bytes[ndx] | set2.bytes[ndx]; } return result; } Bit_Set_256 bs256_and( Bit_Set_256 set1, Bit_Set_256 set2) { Bit_Set_256 result; for (int ndx = 0; ndx < 32; ndx++) { result.bytes[ndx] = set1.bytes[ndx] & set2.bytes[ndx]; } return result; } Bit_Set_256 bs256_and_not( Bit_Set_256 set1, Bit_Set_256 set2) { // DBGMSG("Starting. vcplist1=%p, vcplist2=%p", vcplist1, vcplist2); Bit_Set_256 result; for (int ndx = 0; ndx < 32; ndx++) { result.bytes[ndx] = set1.bytes[ndx] & ~set2.bytes[ndx]; } // char * s = ddca_bs256_string(&result, "0x",", "); // DBGMSG("Returning: %s", s); // free(s); return result; } #define BB256_REPR_BUF_SZ (3*32+1) /** Represents a #Bit_Set_256 value as a sequence of 32 hex values. * * @param buf buffer in which to return value * @param bufsz buffer size, must be at least #BB256_REPR_BUF_SZ * @param bbset value to represent */ void bb256_repr(char * buf, int bufsz, Bit_Set_256 bbset) { assert(bufsz >= BB256_REPR_BUF_SZ); g_snprintf(buf, bufsz, "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x", bbset.bytes[ 0], bbset.bytes[ 1], bbset.bytes[ 2], bbset.bytes[ 3], bbset.bytes[ 4], bbset.bytes[ 5], bbset.bytes[ 6], bbset.bytes[ 7], bbset.bytes[ 8], bbset.bytes[ 9], bbset.bytes[10], bbset.bytes[11], bbset.bytes[12], bbset.bytes[13], bbset.bytes[14], bbset.bytes[15], bbset.bytes[16], bbset.bytes[17], bbset.bytes[18], bbset.bytes[19], bbset.bytes[20], bbset.bytes[21], bbset.bytes[22], bbset.bytes[23], bbset.bytes[24], bbset.bytes[25], bbset.bytes[26], bbset.bytes[27], bbset.bytes[28], bbset.bytes[29], bbset.bytes[30], bbset.bytes[31] ); } /** Returns the number of bits set in a #Bit_Set_256 instance. * * @param bbset value to examine * @return number of bits set */ int bs256_count( Bit_Set_256 bbset) { bool debug = false; int result = 0; int flagndx; int bitndx; for (flagndx=0; flagndx < 32; flagndx++) { for (bitndx = 0; bitndx < 8; bitndx++) { unsigned char flagbit = (0x80 >> bitndx); if (bbset.bytes[flagndx] & flagbit) result += 1; } } if (debug) { char buf[BB256_REPR_BUF_SZ]; bb256_repr(buf, sizeof(buf), bbset); printf("(%s) Returning %d. bbset: %s\n", __func__, result, buf); } return result; } #ifdef COMPILE_ERRORS int bs256_count( Bit_Set_256 bbset) { // regard the array of 32 bytes as an array of 8 4-byte unsigned integers uint64_t list2 = (uint64_t) bbset.bytes; unsigned int ct = 0; for (int ndx = 0; ndx < 4; ndx++) { // clever algorithm for counting number of bits per Brian Kernihgan uint64_t v = list2[ndx]; for (; v; ct++) { v &= v - 1; // clear the least significant bit set } // DBGMSG("feature_list_count() returning: %d", ct); } // #ifdef OLD assert(ct == bs256_count0(bbset)); // #endif return ct; } #endif /** Returns a string representation of a #Bit_Set_256 as a list of hex numbers. * * The value returned is valid until the next call to this function in the * current thread. * * @param bitset value to represent * @param decimal_format if true, represent values as decimal numbers * if false, represent values as hex numbers * @param value_prefix prefix for each hex number, typically "0x" or "" * @param sepstr string to insert between each value, typically "", ",", or " " * @return string representation, caller should not free */ static char * bs256_to_string_general( Bit_Set_256 bitset, bool decimal_format, const char * value_prefix, const char * sepstr) { bool debug = false; if (debug) { printf("(%s) value_prefix=|%s|, sepstr=|%s| bitset: ", __func__, value_prefix, sepstr); for (int ndx = 0; ndx < 32; ndx++) { printf("%02x", bitset.bytes[ndx]); } printf("\n"); // rpt_hex_dump((Byte*)feature_list, 32, 2); } static GPrivate key = G_PRIVATE_INIT(g_free); static GPrivate len_key = G_PRIVATE_INIT(g_free); if (!value_prefix) value_prefix = ""; if (!sepstr) sepstr = ""; int vsize = strlen(value_prefix) + 2 + strlen(sepstr); // for hex if (decimal_format) vsize = strlen(value_prefix) + 3 + strlen(sepstr); // for decimal int bit_ct = bs256_count(bitset); int reqd_size = (bit_ct*vsize)+1; // +1 for trailing null char * buf = get_thread_dynamic_buffer(&key, &len_key, reqd_size); // char * buf = calloc(1, reqd_size); buf[0] = '\0'; // printf("(%s) feature_ct=%d, vsize=%d, buf size = %d", // __func__, feature_ct, vsize, vsize*feature_ct); for (int ndx = 0; ndx < 256; ndx++) { if ( bs256_contains(bitset, ndx) ) { if (decimal_format) sprintf(buf + strlen(buf), "%s%d%s", value_prefix, ndx, sepstr); else sprintf(buf + strlen(buf), "%s%02x%s", value_prefix, ndx, sepstr); } } if (bit_ct > 0) buf[ strlen(buf)-strlen(sepstr)] = '\0'; // printf("(%s) wolf 4\n", __func__); // DBGMSG("Returned string length: %d", strlen(buf)); // DBGMSG("Returning %p - %s", buf, buf); if (debug) printf("(%s) Returning: len=%d, %s\n", __func__, (int) strlen(buf), buf); return buf; } /** Returns a string representation of a #Bit_Set_256 as a list of hex numbers. * * The value returned is valid until the next call to this function or to * #bs256_to_string_decimal() in the current thread. * * @param bitset value to represent * @param value_prefix prefix for each hex number, typically "0x" or "" * @param sepstr string to insert between each value, typically "", ",", or " " * @return string representation, caller should not free */ char * bs256_to_string( Bit_Set_256 bitset, const char * value_prefix, const char * sepstr) { return bs256_to_string_general(bitset, false, value_prefix, sepstr); } /** Returns a string representation of a #Bit_Set_256 as a list of decimal numbers. * * The value returned is valid until the next call to this function or to * #bs256_to_string() in the current thread. * * @param bitset value to represent * @param value_prefix prefix for each decimal number * @param sepstr string to insert between each value, typically "", ",", or " " * @return string representation, caller should not free */ char * bs256_to_string_decimal( Bit_Set_256 bitset, const char * value_prefix, const char * sepstr) { return bs256_to_string_general(bitset, true, value_prefix, sepstr); } int bs256_to_bytes(Bit_Set_256 flags, Byte * buffer, int buflen) { // printf("(%s) Starting\n", __func__); #ifndef NDEBUG int bit_set_ct = bs256_count(flags); assert(buflen >= bit_set_ct); #endif unsigned int bufpos = 0; unsigned int flagno = 0; // printf("(%s) bs256lags->byte=0x%s\n", __func__, hexstring(flags->byte,32)); for (flagno = 0; flagno < 256; flagno++) { Byte flg = (Byte) flagno; // printf("(%s) flagno=%d, flg=0x%02x\n", __func__, flagno, flg); if (bs256_contains(flags, flg)) { // printf("(%s) Flag is set: %d, 0x%02x\n", __func__, flagno, flg); buffer[bufpos++] = flg; } } // printf("(%s) Done. Returning: %d\n", __func__, bupos); return bufpos; } /** Converts a **Bit_Set_256** instance to a sequence of bytes whose values * correspond to the bits that are set. * The byte sequence is returned in a newly allocated **Buffer**. * * @param bs256lags instance handle * @return pointer to newly allocated **Buffer** */ Buffer * bs256_to_buffer(Bit_Set_256 flags) { int bit_set_ct = bs256_count(flags); Buffer * buf = buffer_new(bit_set_ct, __func__); for (unsigned int flagno = 0; flagno < 256; flagno++) { Byte flg = (Byte) flagno; // printf("(%s) flagno=%d, flg=0x%02x\n", __func__, flagno, flg); if (bs256_contains(flags, flg)) { buffer_add(buf, flg); } } // printf("(%s) Done. Returning: %s\n", __func__, buffer); return buf; } #define BS256_ITER_MARKER "BSIM" typedef struct { char marker[4]; Bit_Set_256 bbflags; int lastpos; } _Bit_Set_256_Iterator; /** Creates an iterator for a #Bit_Set_256 instance. * The iterator is an opaque object. */ Bit_Set_256_Iterator bs256_iter_new(Bit_Set_256 bbflags) { _Bit_Set_256_Iterator * result = malloc(sizeof(_Bit_Set_256_Iterator)); memcpy(result->marker, BS256_ITER_MARKER, 4); result->bbflags = bbflags; // TODO: save pointer to unopaque _BitByteFlags result->lastpos = -1; return result; } /** Free a #Bit_Set_256_Iterator. * * @param bs256_iter handle to iterator (may be NULL) */ void bs256_iter_free( Bit_Set_256_Iterator bs256_iter) { _Bit_Set_256_Iterator * iter = (_Bit_Set_256_Iterator *) bs256_iter; if (bs256_iter) { assert(memcmp(iter->marker, BS256_ITER_MARKER, 4) == 0); iter->marker[3] = 'x'; free(iter); } } /** Reinitializes an iterator. Sets the current position before the first * value. * * @param bs256_iter handle to iterator */ void bs256_iter_reset( Bit_Set_256_Iterator bs256_iter) { _Bit_Set_256_Iterator * iter = (_Bit_Set_256_Iterator *) bs256_iter; assert(iter && memcmp(iter->marker, BS256_ITER_MARKER, 4) == 0); iter->lastpos = -1; } /** Returns the number of the next bit that is set. * * @param bs256_iter handle to iterator * @return number of next bit that is set, -1 if no more */ int bs256_iter_next( Bit_Set_256_Iterator bs256_iter) { _Bit_Set_256_Iterator * iter = (_Bit_Set_256_Iterator *) bs256_iter; assert( iter && memcmp(iter->marker, BS256_ITER_MARKER, 4) == 0); // printf("(%s) Starting. lastpos = %d\n", __func__, iter->lastpos); int result = -1; for (int ndx = iter->lastpos + 1; ndx < 256; ndx++) { if (bs256_contains(iter->bbflags, ndx)) { result = ndx; iter->lastpos = ndx; break; } } // printf("(%s) Returning: %d\n", __func__, result); return result; } // TODO: // Extracted from feature_list.cpp in ddcui. parse_custom_feature_list() // should be rewritten to call this function. /** Parse a string containing a list of hex values. * * @param unparsed_string * @param error_msgs_loc if non-null, return null terminated string array of error messages here, * caller is responsible for freeing * @return #Bit_Set_256, will be EMPTY_BIT_SET_256 if errors * * @remark * If error_msgs_loc is non-null on entry, on return the value it points to * is non-null iff there are error messages, i.e. a 0 length array is never returned */ Bit_Set_256 bs256_from_string( char * unparsed_string, Null_Terminated_String_Array * error_msgs_loc) { assert(unparsed_string); assert(error_msgs_loc); bool debug = true; if (debug) printf("(bs256_from_string) unparsed_string = |%s|\n", unparsed_string ); Bit_Set_256 result = EMPTY_BIT_SET_256; *error_msgs_loc = NULL; GPtrArray * errors = g_ptr_array_new(); // convert all commas to blanks char * x = unparsed_string; while (*x) { if (*x == ',') *x = ' '; x++; } // gchar ** pieces = g_strsplit(features_work, " ", -1); // doesn't handle multiple blanks Null_Terminated_String_Array pieces = strsplit(unparsed_string, " "); int ntsal = ntsa_length(pieces); if (debug) printf("(bs256_from_string) ntsal=%d\n", ntsal ); if (ntsal == 0) { if (debug) printf("(bs256_from_string) Empty string\n"); } else { bool ok = true; int ndx = 0; for (; pieces[ndx] != NULL; ndx++) { // char * token = strtrim_r(pieces[ndx], trimmed_piece, 10); char * token = g_strstrip(pieces[ndx]); if (debug) printf("(parse_features_list) token= |%s|\n", token); Byte hex_value = 0; if ( any_one_byte_hex_string_to_byte_in_buf(token, &hex_value) ) { result = bs256_insert(result, hex_value); } else { if (debug) printf("(bs256_from_string) Invalid hex value: %s\n", token); char * s = g_strdup_printf("Invalid hex value: %s", token); g_ptr_array_add(errors, s); ok = false; } } assert(ndx == ntsal); ntsa_free(pieces, /* free_strings */ true); ASSERT_IFF(ok, errors->len == 0); if (ok) { g_ptr_array_free(errors,true); *error_msgs_loc = NULL; } else { result = EMPTY_BIT_SET_256; *error_msgs_loc = g_ptr_array_to_ntsa(errors, false); g_ptr_array_free(errors, false); } } if (debug) { const char * s = bs256_to_string(result, /*prefix*/ "x", /*sepstr*/ ","); printf("Returning bit set: %s\n", s); if (*error_msgs_loc) { printf("(bs256_from_string) Returning error messages:\n"); ntsa_show(*error_msgs_loc); } } return result; } // // Cross data structure functions bba <-> bs256 // /** Tests if the bit number of every byte in a #Byte_Value_Array is set * in a #Bit_Set_256, and conversely that for every bit set in the * #Bit_Set_256 there is a corresponding byte in the #Byte_Value_Array. * * Note it is possible that the same byte appears more than once in the * #Byte_Value_Array. * * @param bva #Byte_Value_Array to test * @param bs256 #Bit_Set_256 to test * @return true/false */ bool bva_bs256_same_values( Byte_Value_Array bva , Bit_Set_256 bbflags) { bool result = true; int item; for (item = 0; item < 256; item++) { // printf("item=%d\n", item); bool r1 = bva_contains(bva, item); bool r2 = bs256_contains(bbflags, item); if (r1 != r2) { result = false; break; } } return result; } /** Convert a #Byte_Value_Array to a #Bit_Set_256 * * @param bva Byte_Value_Array * @return Bit_Set_256 */ Bit_Set_256 bva_to_bs256(Byte_Value_Array bva) { Bit_Set_256 bitset = EMPTY_BIT_SET_256; for (int ndx = 0; ndx < bva_length(bva); ndx++) { Byte b = bva_get(bva, ndx); bitset = bs256_insert(bitset, b); } return bitset; } /** Function matching signature #Byte_Appender that adds a byte * to a #Byte_Value_Array. * * @param data_struct pointer to #Byte_Value_Array * @param val byte to append */ void bva_appender(void * data_struct, Byte val) { Byte_Value_Array bva = (Byte_Value_Array) data_struct; bva_append(bva, val); } void bs256_appender(void * data_struct, Byte val) { assert(data_struct); Bit_Set_256 * bitset = (Bit_Set_256*) data_struct; *bitset = bs256_insert(*bitset, val); } /** Stores a list of bytehex values in either a **Byte_Value_Array**, or a **Bit_Set_256**. * * @param start starting address of hex values * @param len length of hex values * @param data_struct opaque handle to either a **Byte_Value_Array** or a **Bit_Set_256** * @param appender function to add a value to **data_struct** * * @return false if any input data cannot be parsed, true otherwise */ bool store_bytehex_list(char * start, int len, void * data_struct, Byte_Appender appender){ bool ok = true; char * buf = malloc(len+1); memcpy(buf, start, len); buf[len] = '\0'; char * curpos = buf; char * nexttok; Byte byteVal = 0x00; // initialization logically unnecessary, but makes compiler happy while ( (nexttok = strtok(curpos, " ")) != NULL) { if (curpos) curpos = NULL; // for all calls after first int ln = strlen(nexttok); bool hexok = false; if (ln == 2) { // normal case // byteVal = hhc_to_byte(nexttok); hexok = hhc_to_byte_in_buf(nexttok, &byteVal); } else if (ln == 1) { // on old ultrasharp connected to blackrock (pre v2), values in capabilities // string are single digits. Not clear whether to regard them as decimal or hex, // since all values are < 9. But in that case decimal and single digit hex // give the same value. char buf[2]; buf[0] = '0'; buf[1] = *nexttok; // byteVal = hhc_to_byte(buf); hexok = hhc_to_byte_in_buf(buf, &byteVal); } if (!hexok) { // printf("(%s) Invalid hex value in list: %s\n", __func__, nexttok); ok = false; } // printf("(%s) byteVal=0x%02x \n", __func__, byteVal ); if (hexok) appender(data_struct, byteVal); } free(buf); // printf("(%s) Returning %s\n", __func__, sbool(ok)); return ok; } /** Parses a list of bytehex values and stores the result in a **Byte_Value_Array**. * * @param bva handle of **Byte_Value_Array** instance * @param start starting address of hex values * @param len length of hex values * * @return false if any input data cannot be parsed, true otherwise */ bool bva_store_bytehex_list(Byte_Value_Array bva, char * start, int len) { return store_bytehex_list(start, len, bva, bva_appender); } /** Parses a list of bytehex values and stores the result in a **Bit_Set_256**. * * @param pbitset where to return result **Bit_Set_256** instance * @param start starting address of hex values * @param len length of hex values * * @return false if any input data cannot be parsed, true otherwise */ bool bs256_store_bytehex_list(Bit_Set_256 * pbitset, char * start, int len) { return store_bytehex_list(start, len, pbitset, bs256_appender); } ddcui-0.3.0/src/c_util/data_structures.h000066400000000000000000000165061427175135000202520ustar00rootroot00000000000000/** @file data_structures.h * General purpose data structures */ // Copyright (C) 2014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DATA_STRUCTURES_H #define DATA_STRUCTURES_H #ifdef __cplusplus extern "C" { #endif /** \cond */ #include #include #include /** \endcond */ #include "coredefs_base.h" // for Byte #include "string_util.h" // // Buffer with length management // #define BUFFER_MARKER "BUFR" /** Buffer with length management */ typedef struct { char marker[4]; ///< always "BUFR" Byte * bytes; ///< pointer to internal buffer int buffer_size; ///< size of internal buffer int len; ///< number of bytes in buffer uint16_t size_increment; ///< if > 0, auto-extend increment } Buffer; Buffer * buffer_new(int size, const char * trace_msg); void buffer_set_size_increment(Buffer * buffer, uint16_t increment); Buffer * buffer_dup(Buffer * srcbuf, const char * trace_msg); Buffer * buffer_new_with_value(Byte * bytes, int bytect, const char * trace_msg); int buffer_length(Buffer * buffer); void buffer_set_length(Buffer * buffer, int bytect); void buffer_free(Buffer * buffer, const char * trace_msg); void buffer_put(Buffer * buffer, Byte * bytes, int bytect); void buffer_set_byte(Buffer * buffer, int offset, Byte byte); void buffer_set_bytes(Buffer * buffer, int offset, Byte * bytes, int bytect); void buffer_append(Buffer * buffer, Byte * bytes, int bytect); void buffer_strcat(Buffer * buffer, char * str); void buffer_add(Buffer * buffer, Byte byte); void buffer_dump(Buffer * buffer); void buffer_rpt(Buffer * buffer, int depth); bool buffer_eq(Buffer* buf1, Buffer* buf2); void buffer_extend(Buffer* buf, int addl_bytes); // // Circular String Buffer // typedef struct { char ** lines; int size; int ct; } Circular_String_Buffer; /** Allocates a new #Circular_String_Buffer * * @param size buffer size (number of entries) * @return newly allocated #Circular_String_Buffer */ Circular_String_Buffer * csb_new(int size); void csb_add(Circular_String_Buffer * csb, char * line, bool copy); GPtrArray * csb_to_g_ptr_array(Circular_String_Buffer * csb); // // Identifier id to name and description lookup // /** \def VN(v) * Creates a Value_Name table entry by specifying its symbolic name. * * @param v symbolic name */ #define VN(v) {v,#v,NULL} /** \def VN_END * Terminating entry for a Value_Name table. */ #define VN_END {0xff,NULL,NULL} /** \def VNT(v,t) * Creates a Value_Name_Title table entry by specifying its symbolic name * and description * * @param v symbolic name * @param t symbol description */ #define VNT(v,t) {v,#v,t} /** Terminating entry for a Value_Name_Title table. */ #define VNT_END {0xff,NULL,NULL} /** A Value_Name_Title table is used to map byte values to their * symbolic names and description (title). * Each entry is a value/name/description triple.. * * The table is terminated by an entry whose name and description fields are NULL. */ typedef struct { uint32_t value; ///< value char * name; ///< symbolic name char * title; ///< value description } Value_Name_Title; typedef Value_Name_Title Value_Name_Title_Table[]; typedef Value_Name_Title Value_Name; typedef Value_Name_Title_Table Value_Name_Table; char * vnt_name( Value_Name_Title* table, uint32_t val); #ifdef TRANSITIONAL #define vn_name vnt_name #endif char * vnt_title(Value_Name_Title* table, uint32_t val); uint32_t vnt_find_id( Value_Name_Title_Table table, const char * s, bool use_title, // if false, search by symbolic name, if true, search by title bool ignore_case, uint32_t default_id); #define INTERPRET_VNT_FLAGS_BY_NAME false #define INTERPRET VNT_FLAGS_BY_TITLE true char * vnt_interpret_flags( uint32_t flags_val, Value_Name_Title_Table bitname_table, bool use_title, char * sepstr); // // Byte Value Array // typedef bool *IFilter(int i); /** An opaque structure containing an array of bytes that * can grow dynamically. Note that the same byte value can * appear multiple times. */ typedef void * Byte_Value_Array; Byte_Value_Array bva_create(); void bva_free(Byte_Value_Array bva); void bva_sort(Byte_Value_Array bva); bool bva_sorted_eq(Byte_Value_Array bva1, Byte_Value_Array bva2); int bva_length(Byte_Value_Array bva); bool bva_contains(Byte_Value_Array bva, Byte item); Byte bva_get(Byte_Value_Array bva, guint ndx); void bva_append(Byte_Value_Array bva, Byte item); Byte * bva_bytes(Byte_Value_Array bva); Byte_Value_Array bva_filter(Byte_Value_Array bva, IFilter filter_func); char * bva_as_string(Byte_Value_Array bva, bool as_hex, char * sep); void bva_report(Byte_Value_Array ids, char * title); bool bva_store_bytehex_list(Byte_Value_Array bva, char * start, int len); // void test_value_array(); // for testing // // Bit_Set_256 // typedef struct { uint8_t bytes[32]; } Bit_Set_256; extern const Bit_Set_256 EMPTY_BIT_SET_256; bool bs256_eq(Bit_Set_256 set1, Bit_Set_256 set2); int bs256_count(Bit_Set_256 set); bool bs256_contains(Bit_Set_256 flags, uint8_t val); int bs256_first_bit_set(Bit_Set_256 bitset); Bit_Set_256 bs256_insert(Bit_Set_256 flags, uint8_t val); Bit_Set_256 bs256_or(Bit_Set_256 set1, Bit_Set_256 set2); // union Bit_Set_256 bs256_and(Bit_Set_256 set1, Bit_Set_256 set2); // intersection Bit_Set_256 bs256_and_not(Bit_Set_256 set1, Bit_Set_256 set2); // subtract char * bs256_repr(Bit_Set_256 flags, char * buffer, int buflen); char * bs256_to_string(Bit_Set_256 set, const char * value_prefix, const char * septr); // provides for bbf_to_string() char * bs256_to_string_decimal(Bit_Set_256 set, const char * value_prefix, const char * septr); Bit_Set_256 bs256_from_string(char * unparsed_string, Null_Terminated_String_Array * error_msgs_loc); int bs256_to_bytes(Bit_Set_256 flags, Byte * buffer, int buflen); Buffer * bs256_to_buffer(Bit_Set_256 flags); /** Opaque iterator for Bit_Set_256 */ typedef void * Bit_Set_256_Iterator; Bit_Set_256_Iterator bs256_iter_new(Bit_Set_256 bs256lags); void bs256_iter_free( Bit_Set_256_Iterator iter); void bs256_iter_reset(Bit_Set_256_Iterator iter); int bs256_iter_next( Bit_Set_256_Iterator iter); // // Byte_Value_Array <-> Bit_Set_256 cross-compatibility functions // bool bva_bs256_same_values( Byte_Value_Array bva , Bit_Set_256 bs256); Bit_Set_256 bva_to_bs256(Byte_Value_Array bva); /** Function signature for passing function that appends a value to * either a #Byte_Bit_Flags or a #Byte_Value_Array */ typedef void (*Byte_Appender) (void * data_struct, Byte val); void bva_appender(void * data_struct, Byte val); void bs256_appender(void * data_struct, Byte val); // Store a value in either a Byte_Value_Array or a Byte_Bit_Flag bool store_bytehex_list(char * start, int len, void * data_struct, Byte_Appender appender); #ifdef __cplusplus } // extern "C" #endif #endif /* DATA_STRUCTURES_H */ ddcui-0.3.0/src/c_util/ddcutil_config_file.c000066400000000000000000000264651427175135000210120ustar00rootroot00000000000000/** \file ddcutil_config_file.c * Processes an INI file used for ddcutil options * * This is not a generic utility file, but is included in * the util directory to simplify its copying unmodified into * the ddcui source tree. */ // Copyright (C) 2021-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include "debug_util.h" #include "simple_ini_file.h" #include "string_util.h" #include "xdg_util.h" #include "ddcutil_config_file.h" /** Tokenize a string as per the command line * * \param string to tokenize * \param tokens_loc where to return the address of a null-terminated list of tokens * \return number of tokens * * \remark * The caller is responsible for freeing the list of tokens */ int tokenize_options_line(char * string, char ***tokens_loc) { bool debug = false; if (debug) printf("(%s) string -> |%s|\n", __func__, string); wordexp_t p; int flags = WRDE_NOCMD; if (debug) flags |= WRDE_SHOWERR; int rc = wordexp(string, &p, flags); if (debug) printf("(%s) wordexp returned %d\n", __func__, rc); *tokens_loc = p.we_wordv; if (debug) { printf("(%s) Tokens:\n", __func__); ntsa_show(*tokens_loc); printf("(%s) Returning: %zd\n", __func__, p.we_wordc); } return p.we_wordc; } /** Processes a ddcutil configuration file, returning an options string obtained * both the global and applictation-specific sections of the configuration file.nd * * \param ddcutil_application "ddcutil", "libddcutil", "ddcui" * \param config_filename_loc where to return fully qualified name of configuration file * \param untokenized_option_string_loc * where to return untokenized string of options obtained from * the configuration file * \param errmsgs collects error messages if non-NULL * \param verbose issue error messages if true * \retval 0 success * \retval -ENOENT config file not found * \retval < 0 other error * * An untokenized option string is returned iff rc == 0. */ int read_ddcutil_config_file( const char * ddcutil_application, char ** config_fn_loc, char ** untokenized_option_string_loc, GPtrArray * errmsgs, bool verbose) { bool debug = false; if (debug) verbose = true; if (debug) printf("(%s) Starting. ddcutil_application=%s, errmsgs=%p, verbose=%s\n", __func__, ddcutil_application, (void*)errmsgs, SBOOL(verbose)); int result = 0; *untokenized_option_string_loc = NULL; *config_fn_loc = NULL; char * config_fn = find_xdg_config_file("ddcutil", "ddcutilrc"); if (!config_fn) { if (debug) printf("(%s) Configuration file not found\n", __func__); result = -ENOENT; goto bye; } if (debug) printf("(%s) Found configuration file: %s\n", __func__, config_fn); *config_fn_loc = config_fn; Parsed_Ini_File * ini_file = NULL; int load_rc = ini_file_load(config_fn, errmsgs, verbose, &ini_file); ASSERT_IFF(load_rc==0, ini_file); if (debug) fprintf(stderr, "ini_file_load() returned %d\n", load_rc); if (verbose) { if (errmsgs && errmsgs->len > 0) { fprintf(stderr, "Error(s) processing configuration file: %s\n", config_fn); for (guint ndx = 0; ndx < errmsgs->len; ndx++) { fprintf(stderr, " %s\n", (char*) g_ptr_array_index(errmsgs, ndx)); } } } if (load_rc == 0) { if (debug) { ini_file_dump(ini_file); } char * global_options = ini_file_get_value(ini_file, "global", "options"); char * ddcutil_options = ini_file_get_value(ini_file, ddcutil_application, "options"); char * s = g_strdup_printf("%s %s", (global_options) ? global_options : "", (ddcutil_options) ? ddcutil_options : ""); char * combined_options = strtrim(s); free(s); if (debug) printf("(%s) combined_options= |%s|\n", __func__, combined_options); *untokenized_option_string_loc = combined_options; ini_file_free(ini_file); } else result = load_rc; bye: ASSERT_IFF(result==0, *untokenized_option_string_loc); if (debug) { // check for null to avoid -Wstringop-overflow printf("(%s) Done. untokenized options: |%s|, *config_fn_loc=%s, returning: %d\n", __func__, (*untokenized_option_string_loc) ? *untokenized_option_string_loc : "(null)", (*config_fn_loc) ? *config_fn_loc : "(null)", result); } return result; } /** Merges the tokenized command string passed to the program with tokens * obtained from the configuration file. * * \param old_argc original argument count * \param old_argv original argument list * \param config_token_ct number of tokens to insert * \param config_tokens list of tokens * \param merged_argv_loc where to return address of merged argument list * \return length of merged argument list * * \remark * old_argc/old_argv are argc/argv as passed on the command line */ static int merge_command_tokens( int old_argc, char ** old_argv, int config_token_ct, char ** config_tokens, char *** merged_argv_loc) { bool debug = false; DBGF(debug, "Starting. old_argc=%d, old_argc=%p, config_token_ct=%d, config_tokens=%p, merged_argv_loc=%p", old_argc, old_argv, config_token_ct, config_tokens, merged_argv_loc); *merged_argv_loc = NULL; int merged_argc = 0; if (config_token_ct > 0) { int new_ct = config_token_ct + old_argc + 1; DBGF(debug, "config_token_ct = %d, argc=%d, new_ct=%d", config_token_ct, old_argc, new_ct); char ** combined = calloc(new_ct, sizeof(char *)); DBGF(debug, "Allocated combined=%p", combined); combined[0] = strdup(old_argv[0]); // command if (debug) printf("%s) Allocated combined[0] = %p -> |%s|\n", __func__, combined[0], combined[0] ); DBGF(debug, "Copying config_token_ct=%d config file tokens", config_token_ct); int new_ndx = 1; for (int prefix_ndx = 0; prefix_ndx < config_token_ct; prefix_ndx++, new_ndx++) { combined[new_ndx] = strdup(config_tokens[prefix_ndx]); if(debug) printf("(%s) Allocated combined[%d]=%p -> |%s|\n", __func__, new_ndx, combined[new_ndx], combined[new_ndx]); } DBGF(debug, "Copying %d arguments from old_argv", old_argc-1); for (int old_ndx = 1; old_ndx < old_argc; old_ndx++, new_ndx++) { combined[new_ndx] = strdup(old_argv[old_ndx]); if (debug) printf("(%s) Allocated combined[%d] = %p -> |%s|\n", __func__, new_ndx, combined[new_ndx], combined[new_ndx]); } combined[new_ndx] = NULL; if (debug) printf("(%s) Final new_ndx = %d\n", __func__, new_ndx); *merged_argv_loc = combined; merged_argc = new_ct - 1; assert(merged_argc == ntsa_length(combined)); } else { *merged_argv_loc = ntsa_copy(old_argv, true); merged_argc = old_argc; } if (debug) { printf("(%s) Returning %d, *merged_argv_loc=%p\n", __func__, merged_argc, (void*)*merged_argv_loc); printf("(%s) *merged_arv_loc tokens:\n", __func__); ntsa_show(*merged_argv_loc); } return merged_argc; } /** Reads and tokenizes the appropriate options entries in the config file, * then combines the tokenized options from the ddcutil configuration file * with the command line arguments, returning a new argument list * * \param application_name for selecting config file segment * \param old_argc argc as passed on the command line * \param old_argv argv as passed on the command line * \param new_argc_loc where to return length of updated argv, * contains old_argc if error * \param new_argv_loc where to return the address of the updated argv * as a Null_Terminated_String_Array, contains old_argv if error * \param untokenized_config_options_loc * where to return untokenized option string obtained from ini file * \param configure_fn_loc where to return name of configuration file, * NULL if not found * \param errmsgs collects error messages, if non-NULL * \retval 0 success. * \retval < 0 error reading or parsing the configuration file. * n. it is not an error if the configuration file does not exist. */ int apply_config_file( const char * application_name, // "ddcutil", "ddcui", "libddcutil" int old_argc, char ** old_argv, int * new_argc_loc, char *** new_argv_loc, char** untokenized_config_options_loc, char** configure_fn_loc, GPtrArray * errmsgs) { bool debug = false; DBGF(debug, "Starting. application_name=%s, errmsgs=%p", application_name, (void*)errmsgs); *untokenized_config_options_loc = NULL; *configure_fn_loc = NULL; *new_argv_loc = NULL; *new_argc_loc = 0; int result = 0; int read_config_rc = read_ddcutil_config_file( application_name, configure_fn_loc, untokenized_config_options_loc, errmsgs, debug); // verbose ASSERT_IFF(read_config_rc==0, *untokenized_config_options_loc); DBGF(debug, "read_ddcutil_config_file() returned %d, configure_fn: %s", read_config_rc, *configure_fn_loc); if (read_config_rc == -ENOENT) { *new_argv_loc = ntsa_copy(old_argv, true); *new_argc_loc = old_argc; result = 0; } else if (read_config_rc < 0) { result = read_config_rc; } else { char ** cmd_prefix_tokens = NULL; int prefix_token_ct = tokenize_options_line(*untokenized_config_options_loc, &cmd_prefix_tokens); DBGF(debug, "prefix_token_ct = %d, cmd_prefix_tokens: ", prefix_token_ct); if (debug) ntsa_show(cmd_prefix_tokens); *new_argc_loc = merge_command_tokens( old_argc, old_argv, prefix_token_ct, cmd_prefix_tokens, new_argv_loc); assert(*new_argc_loc == ntsa_length(*new_argv_loc)); DBGF(debug, "calling ntsa_free() for cmd_prefix_tokens=%p ...", cmd_prefix_tokens); ntsa_free(cmd_prefix_tokens, true); // ntsa_free(old_argv, false); // can't free system's argv } if (debug) { DBGF(debug, "Done. *new_argc_loc=%d, *new_argv_loc=%p, returning %d", *new_argc_loc, *new_argv_loc, result); printf("(%s) *new_argv_loc tokens:\n", __func__); ntsa_show(*new_argv_loc); printf("(%s) *untokenized_config_options_loc=%p->|%s|\n", __func__, *untokenized_config_options_loc, *untokenized_config_options_loc); } return result; } ddcui-0.3.0/src/c_util/ddcutil_config_file.h000066400000000000000000000014751427175135000210110ustar00rootroot00000000000000// ddcutil_config_file.h // Copyright (C) 2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUTIL_CONFIG_FILE_H_ #define DDCUTIL_CONFIG_FILE_H_ #include int read_ddcutil_config_file( const char * ddcutil_application, char ** config_fn_loc, char ** untokenized_option_string_loc, GPtrArray * errmsgs, bool verbose); int apply_config_file( const char * ddcutil_application, // "ddcutil", "ddcui", "libddcutil" int old_argc, char ** old_argv, int * new_argc_loc, char *** new_argv_loc, char ** untokenized_option_string_loc, char ** configure_fn_loc, GPtrArray * errmsgs); #endif /* DDCUTIL_CONFIG_FILE_H_ */ ddcui-0.3.0/src/c_util/debug_util.c000066400000000000000000000140001427175135000171370ustar00rootroot00000000000000/** @file debug_util.c * * Functions for debugging */ // Copyright (C) 2016-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "config.h" /** \cond */ #ifdef HAVE_EXECINFO_H #include #endif #include #include #include #include #include #include #ifdef UNUSED #ifdef TARGET_BSD #include #else #include #include #include #endif #endif /** \endcond */ #include "string_util.h" #include "debug_util.h" // HACK #ifdef TARGET_BSD #undef HAVE_EXECINFO_H #endif #ifdef HAVE_EXECINFO_H /* Extracts the function name and offset from a backtrace line * * \param bt_line line returned by backtrace() * \param name_only if true, return only the name * \return string of form "name+offset" or just "name". * It is the responsibility of the caller to free this string. */ static char * extract_function(char * bt_line, bool name_only) { bool debug = false; if (debug) printf("\n(%s) bt_line = |%s|\n", __func__, bt_line); char * result = NULL; char * start = strchr(bt_line, '('); if (!start) { result = strdup("???"); } else { start++; // character after paren char * end = strchr(start, ')'); if (!end) end = bt_line + strlen(bt_line); int len = end - start; if (debug) { printf("(%s) start=%p, end=%p, len=%d\n", __func__, start, end, len); printf("(%s) extract is |%.*s|\n", __func__, len, start); } result = malloc(len+1); memcpy(result, start, len); result[len] = '\0'; } if (name_only) { char *p = strchr(result, '+'); if (p) *p = '\0'; } if (debug) printf("(%s) Returning |%s|\n", __func__, result); return result; } #endif #ifdef OLD /** Show the call stack. * * @param stack_adjust number of initial stack frames to ignore, to hide this * function and possibly some number of immediate callers * * @remark * Note that the call stack is approximate. The underlying system function, backtrace() * relies on external symbols, so static functions will not be properly shown. */ void show_backtrace(int stack_adjust) { bool debug = false; if (debug) printf("(%s) Starting. stack_adjust = %d\n", __func__, stack_adjust); int j, nptrs; const int MAX_ADDRS = 100; void *buffer[MAX_ADDRS]; char **strings; nptrs = backtrace(buffer, MAX_ADDRS); if (debug) printf("(%s) backtrace() returned %d addresses\n", __func__, nptrs); strings = backtrace_symbols(buffer, nptrs); if (strings == NULL) { perror("backtrace_symbols unavailable"); } else { printf("Current call stack\n"); for (j = 0; j < nptrs; j++) { if (j < stack_adjust) { if (debug) printf("(%s) Suppressing %s\n", __func__, strings[j]); } else { // printf(" %s\n", strings[j]); char * s = extract_function(strings[j], true); printf(" %s\n", s); bool final = (streq(s, "main")) ? true : false; free(s); if (final) break; } } free(strings); } } #endif GPtrArray * get_backtrace(int stack_adjust) { #ifdef HAVE_EXECINFO_H bool debug = false; if (debug) printf("(%s) Starting. stack_adjust = %d\n", __func__, stack_adjust); GPtrArray * result = NULL; int j, nptrs; const int MAX_ADDRS = 100; void *buffer[MAX_ADDRS]; char **strings; nptrs = backtrace(buffer, MAX_ADDRS); if (debug) printf("(%s) backtrace() returned %d addresses\n", __func__, nptrs); strings = backtrace_symbols(buffer, nptrs); if (strings == NULL) { if (debug) perror("backtrace_symbols unavailable"); } else { result = g_ptr_array_sized_new(nptrs-stack_adjust); if (debug) printf("Current call stack\n"); for (j = 0; j < nptrs; j++) { if (j < stack_adjust) { if (debug) printf("(%s) Suppressing %s\n", __func__, strings[j]); } else { // printf(" %s\n", strings[j]); char * s = extract_function(strings[j], true); if (debug) printf(" %s\n", s); g_ptr_array_add(result, s); bool final = (streq(s, "main")) ? true : false; if (final) break; } } free(strings); } return result; #else return NULL; #endif } void show_backtrace(int stack_adjust) { GPtrArray * callstack = get_backtrace(stack_adjust); if (!callstack) { perror("backtrace unavailable"); } else { printf("Current call stack:\n"); for (int ndx = 0; ndx < callstack->len; ndx++) { printf(" %s\n", (char *) g_ptr_array_index(callstack, ndx)); } g_ptr_array_free(callstack, true); } } bool simple_dbgmsg( bool debug_flag, const char * funcname, const int lineno, const char * filename, char * format, ...) { bool debug_func = false; if (debug_func) printf("(simple_dbgmsg) Starting. debug_flag=%s, funcname=%s filename=%s, lineno=%d\n", sbool(debug_flag), funcname, filename, lineno); #ifdef UNUSED char thread_prefix[15] = ""; int tid = pthread_getthreadid_np(); pid_t pid = syscall(SYS_getpid); snprintf(thread_prefix, 15, "[%7jd]", (intmax_t) pid); // is this proper format for pid_t #endif bool msg_emitted = false; if ( debug_flag ) { va_list(args); va_start(args, format); char * buffer = g_strdup_vprintf(format, args); va_end(args); char * buf2 = g_strdup_printf("(%-32s) %s", funcname, buffer); f0puts(buf2, stdout); f0putc('\n', stdout); fflush(stdout); free(buffer); free(buf2); msg_emitted = true; } return msg_emitted; } ddcui-0.3.0/src/c_util/debug_util.h000066400000000000000000000016641427175135000171600ustar00rootroot00000000000000/** @file debug_util.h * * Functions for debugging */ // Copyright (C) 2016-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DEBUG_UTIL_H_ #define DEBUG_UTIL_H_ #include #include #include #define ASSERT_WITH_BACKTRACE(_condition) \ do { \ if ( !(_condition) ) { \ show_backtrace(2); \ assert(_condition); \ } \ } while(0) GPtrArray * get_backtrace(int stack_adjust); void show_backtrace(int stack_adjust); bool simple_dbgmsg( bool debug_flag, const char * funcname, const int lineno, const char * filename, char * format, ...); #define DBGF(debug_flag, format, ...) \ do { if (debug_flag) simple_dbgmsg(debug_flag, __func__, __LINE__, __FILE__, format, ##__VA_ARGS__); } while(0) #endif /* DEBUG_UTIL_H_ */ ddcui-0.3.0/src/c_util/file_util_base.c000066400000000000000000000055101427175135000177700ustar00rootroot00000000000000/** \file file_util_base.c * Core file utility functions. * Factored out of file_util.h so that includes in directory util form * a directed graph. */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ #include #include #include #include #include #include #include #include /** \endcond */ #include "data_structures.h" #include "string_util.h" #include "file_util_base.h" /** Reads the lines of a text file into a GPtrArray. * * @param fn file name * @param line_array pointer to GPtrArray of strings where lines will be saved * @param verbose if true, write message to stderr if unable to open file or other error * * @retval >=0: number of lines added to line_array * @retval <0 -errno from fopen() or getline() * * The caller is responsible for freeing the lines added to line_array. * * Strings are appended to #line_array. It is not cleared at start of * function execution. */ int file_getlines( const char * fn, GPtrArray* line_array, bool verbose) { bool debug = false; if (debug) printf("(%s) Starting. fn=%s \n", __func__, fn ); int rc = 0; FILE * fp = fopen(fn, "r"); if (!fp) { int errsv = errno; rc = -errno; if (verbose || debug) fprintf(stderr, "Error opening file %s: %s\n", fn, strerror(errsv)); } else { // if line == NULL && len == 0, then getline allocates buffer for line char * line = NULL; size_t len = 0; int linectr = 0; errno = 0; // int getline_rc = 0; while ( getline(&line, &len, fp) >= 0) { linectr++; rtrim_in_place(line); // strip trailing newline g_ptr_array_add(line_array, line); // line will be freed when line_array is freed if (debug) { printf("(%s) Retrieved line of length %zu, trimmed length %zu: %s\n", __func__, len, strlen(line), line); } line = NULL; // reset for next getline() call len = 0; } // From the getline() man page: // If *lineptr is set to NULL and *n is set 0 before the call, // then getline() will allocate a buffer for storing the line. // This buffer should be freed by the user program even if getline() failed. free(line); // assert(getline_rc < 0); if (errno != 0) { // was it an error or eof?file_getlines rc = -errno; if (verbose || debug) fprintf(stderr, "Error reading file %s: %s\n", fn, strerror(-rc)); } else rc = linectr; fclose(fp); } if (debug) printf("(%s) Done. returning: %d\n", __func__, rc); return rc; } ddcui-0.3.0/src/c_util/file_util_base.h000066400000000000000000000011151427175135000177720ustar00rootroot00000000000000/** \file file_util_base.h * Core file utility functions. * This file exists so that includes in util directory can form * a directed graph. */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FILE_UTIL_BASE_H_ #define FILE_UTIL_BASE_H_ #include #include #ifdef __cplusplus extern "C" { #endif int file_getlines( const char * fn, GPtrArray* line_array, bool verbose) ; #ifdef __cplusplus } // extern "C" #endif #endif /* FILE_UTIL_BASE_H_ */ ddcui-0.3.0/src/c_util/glib_util.c000066400000000000000000000250041427175135000167740ustar00rootroot00000000000000/** @file glib_util.c * * Utility functions for glib. */ // Copyright (C) 2014-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ #include #include #include #include #include /** \endcond */ #include "glib_util.h" #include "string_util.h" #ifdef ALTERNATIVE // create private copy of g_hash_table_get_keys_as_array() /** * g_hash_table_get_keys_as_array: * @hash_table: a #GHashTable * @length: (out): the length of the returned array * * Retrieves every key inside @hash_table, as an array. * * The returned array is %NULL-terminated but may contain %NULL as a * key. Use @length to determine the true length if it's possible that * %NULL was used as the value for a key. * * Note: in the common case of a string-keyed #GHashTable, the return * value of this function can be conveniently cast to (gchar **). * * You should always free the return result with g_free(). In the * above-mentioned case of a string-keyed hash table, it may be * appropriate to use g_strfreev() if you call g_hash_table_steal_all() * first to transfer ownership of the keys. * * Returns: (array length=length) (transfer container): a * %NULL-terminated array containing each key from the table. * * Since: 2.40 **/ gpointer * g_hash_table_get_keys_as_array_local (GHashTable *hash_table, guint *length) { gpointer *result; guint i, j = 0; result = g_new(gpointer, hash_table->nnodes + 1); for (i = 0; i < hash_table->size; i++) { if (HASH_IS_REAL (hash_table->hashes[i])) result[j++] = hash_table->keys[i]; } g_assert_cmpint (j, ==, hash_table->nnodes); result[j] = NULL; if (length) *length = j; return result; } #endif /** Converts a doubly linked list of pointers into a null-terminated array * of pointers. * * @param glist pointer to doubly linked list * @param length where to return number of items in the allocated array, * (not including the final NULL terminating entry * * @return pointer to the newly allocated gpointer array * * @remark The pointers in the linked list are copied to the newly allocated array. * The data pointed to is not duplicated. * @remark This function is needed because glib function g_hash_table_get_keys_as_array() * does not exist in glib versions less than 2.40 */ gpointer * g_list_to_g_array( GList * glist, guint * length) { int len = 0; gpointer * result = NULL; guint ndx = 0; GList * lptr; len = g_list_length(glist); result = g_new(gpointer, len+1); for (lptr = glist; lptr!=NULL; lptr=lptr->next) { result[ndx++] = lptr->data; } result[ndx] = NULL; *length = len; return result; } // GCompareFunc functions // signature: // gint // (* GCompareFunc) ( // gconstpointer a, // gconstpointer b // ) /** String comparison function with signature GCompareFunc * * @param a pointer to first string * @param b pointer to second string * @return -1, 0, +1 in the usual way * * @remark Used by g_ptr_array_sort() */ gint gaux_ptr_scomp( gconstpointer a, gconstpointer b) { char ** ap = (char **) a; char ** bp = (char **) b; // printf("(%s) ap = %p -> -> %p -> |%s|\n", __func__, ap, *ap, *ap); // printf("(%s) bp = %p -> -> %p -> |%s|\n", __func__, bp, *bp, *bp); return g_ascii_strcasecmp(*ap,*bp); } /** Integer comparison function with signature GCompareFunc */ gint gaux_ptr_intcomp( gconstpointer a, gconstpointer b) { int ia = GPOINTER_TO_INT(a); int ib = GPOINTER_TO_INT(b); gint result = 0; if (ia < ib) result = -1; else if (ia > ib) result = 1; // printf("(%s) a=%p, ia=%d, b=%p, ib=%d, returning %d\n", __func__, a, ia, b, ib, result); return result; } GPtrArray * gaux_ptr_array_truncate( GPtrArray * gpa, int limit) { assert(gpa); bool debug = false; if (debug) printf("(%s) Starting. gpa->len=%d, limit=%d\n", __func__, gpa->len, limit); if (limit > 0) { int removect = gpa->len - limit; if (removect > 0) { g_ptr_array_remove_range(gpa, limit, removect); } } else if (limit < 0) { int removect = gpa->len + limit; if (removect > 0) { g_ptr_array_remove_range(gpa, 0, removect); } } if (debug) printf("(%s) Done. gpa->len=%d\n", __func__, gpa->len); return gpa; } // Future: GPtrArray * gaux_ptr_array_append_array( GPtrArray * dest, GPtrArray * src, GAuxDupFunc dup_func) { assert(dest); if (src) { for (guint ndx = 0; ndx < src->len; ndx++) { gpointer v = g_ptr_array_index(src,ndx); if (dup_func) v = dup_func(v); g_ptr_array_add(dest, v); } } return dest; } GPtrArray * gaux_ptr_array_join( GPtrArray * gpa1, GPtrArray * gpa2, GAuxDupFunc dup_func, GDestroyNotify element_free_func) { int new_len = gpa1->len + gpa2->len; GPtrArray * dest = g_ptr_array_sized_new(new_len); if (element_free_func) g_ptr_array_set_free_func(dest,element_free_func); for (guint ndx = 0; ndx < gpa1->len; ndx++) { gpointer v = g_ptr_array_index(gpa1,ndx); if (dup_func) v = dup_func(v); g_ptr_array_add(dest, v); } for (guint ndx = 0; ndx < gpa2->len; ndx++) { gpointer v = g_ptr_array_index(gpa2,ndx); if (dup_func) v = dup_func(v); g_ptr_array_add(dest, v); } return dest; } GPtrArray * gaux_ptr_array_copy( GPtrArray * src, GAuxDupFunc dup_func, GDestroyNotify element_free_func) { GPtrArray * dest = g_ptr_array_sized_new(src->len); if (element_free_func) g_ptr_array_set_free_func(dest, element_free_func); for (guint ndx = 0; ndx < src->len; ndx++) { gpointer v = g_ptr_array_index(src,ndx); if (dup_func) v = dup_func(v); g_ptr_array_add(dest, v); } return dest; } GPtrArray * gaux_ptr_array_from_null_terminated_array( gpointer * src, GAuxDupFunc dup_func, GDestroyNotify element_free_func) { GPtrArray * result = g_ptr_array_new(); if (dup_func) g_ptr_array_set_free_func(result, element_free_func); gpointer* p = src; while (*p) { gpointer v = (dup_func) ? dup_func(*p) : *p; g_ptr_array_add(result, v); } return result; } // GEqualFunc gboolean gaux_streq(gconstpointer a, gconstpointer b) { gboolean result = streq((const char *) a, (const char *) b); // printf("(%s) a=|%s|, b=|%s|, returning %s\n", __func__, (const char * )a, (const char *) b, sbool(result)); return result; } /** Implements g_ptr_array_find_with_equal_func(), which requires glib 2.54. * */ gboolean gaux_ptr_array_find_with_equal_func( GPtrArray * haystack, gconstpointer needle, GEqualFunc equal_func, guint * index_loc) { bool result = false; if (index_loc) *index_loc = -1; if (haystack && (haystack->len > 0) && needle) { for (guint ndx = 0; ndx < haystack->len; ndx++) { if (equal_func) result = equal_func(g_ptr_array_index(haystack,ndx), needle); else result = g_ptr_array_index(haystack,ndx) == needle; if (result) { if (index_loc) *index_loc = ndx; break; } } } return result; } // // Thread utilities // /** Handles the boilerplate of obtaining a thread specific buffer that can * change size. * * If parm **bufsz_key_ptr** is NULL, the buffer is reallocated with the * specified size with each call to this function. * * If parm **bufsz_key_ptr** is non-NULL, then the buffer is reallocated * only if the requested size is larger than the current size. That is, * the buffer can grow in size but never shrink. * * \param buf_key_ptr address of a **GPrivate** used as the identifier * for the buffer * \param bufsz_key_ptr address of **GPrivate** used as an identifier for * the current buffer size * \param required_size size of buffer to allocate * \return pointer to thread specific buffer */ void * get_thread_dynamic_buffer( GPrivate * buf_key_ptr, GPrivate * bufsz_key_ptr, guint16 required_size) { // printf("(%s) buf_key_ptr=%p, bufsz_key_ptr=%p, required_size=%d\n", // __func__, buf_key_ptr, bufsz_key_ptr, required_size); char * buf = g_private_get(buf_key_ptr); int * bufsz_ptr = NULL; if (bufsz_key_ptr) bufsz_ptr = g_private_get(bufsz_key_ptr); // GThread * this_thread = g_thread_self(); // printf("(%s) this_thread=%p, buf=%p, bufsz_ptr=%p\n", __func__, this_thread, buf, bufsz_ptr); // if (bufsz_ptr) // printf("(%s) *bufsz_ptr = %d\n", __func__, *bufsz_ptr); // unnecessary if use g_private_replace() instead of g_private_set() // if (buf) // g_free(buf); if ( !bufsz_ptr || *bufsz_ptr < required_size) { buf = g_new(char, required_size); // printf("(%s) Calling g_private_set()\n", __func__); g_private_replace(buf_key_ptr, buf); if (bufsz_key_ptr) { if (!bufsz_ptr) { bufsz_ptr = g_new(int, 1); g_private_set(bufsz_key_ptr, bufsz_ptr); } *bufsz_ptr = required_size; } } // printf("(%s) Returning: %p\n", __func__, buf); return buf; } /** Handles the boilerplate of obtaining a thread specific fixed size buffer. * The first call to this function in a thread with a given key address * allocates the buffer. Subsequent calls in the thread for the same key * address return the same buffer. * * \param buf_key_ptr address of a **GPrivate** used as the identifier * for the buffer * \param buffer_size size of buffer to allocate * \return pointer to thread specific buffer * * \remark * When the buffer is first allocated, all bytes are set to 0. */ void * get_thread_fixed_buffer( GPrivate * buf_key_ptr, guint16 buffer_size) { // printf("(%s) buf_key_ptr=%p, buffer_size=%d\n", __func__, buf_key_ptr, buffer_size); assert(buffer_size > 0); char * buf = g_private_get(buf_key_ptr); // GThread * this_thread = g_thread_self(); // printf("(%s) this_thread=%p, buf=%p\n", __func__, this_thread, buf); if (!buf) { buf = g_new0(char, buffer_size); //g_new0 initializes to 0 g_private_set(buf_key_ptr, buf); } // printf("(%s) Returning: %p\n", __func__, buf); return buf; } ddcui-0.3.0/src/c_util/glib_util.h000066400000000000000000000035001427175135000167760ustar00rootroot00000000000000/** @file glib_util.h * * Utility functions for glib. */ // Copyright (C) 2014-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef GLIB_UTIL_H_ #define GLIB_UTIL_H_ /** \cond */ #include #include /** \endcond */ #ifdef __cplusplus extern "C" { #endif gpointer * g_list_to_g_array( GList * glist, guint * length); gint gaux_ptr_scomp( gconstpointer a, gconstpointer b); gint gaux_ptr_intcomp( gconstpointer a, gconstpointer b); void * get_thread_dynamic_buffer( GPrivate * buf_key_ptr, GPrivate * bufsz_key_ptr, guint16 required_size); void * get_thread_fixed_buffer( GPrivate * buf_key_ptr, guint16 required_size); GPtrArray * gaux_ptr_array_truncate( GPtrArray * gpa, int limit); // Future: typedef gpointer (*GAuxDupFunc)(gpointer src); GPtrArray * gaux_ptr_array_append_array( GPtrArray * dest, GPtrArray * src, GAuxDupFunc dup_func); GPtrArray * gaux_ptr_array_join( GPtrArray * gpa1, GPtrArray * gpa2, GAuxDupFunc dup_func, GDestroyNotify element_free_func); GPtrArray * gaux_ptr_array_copy( GPtrArray * src, GAuxDupFunc dup_func, GDestroyNotify element_free_func); GPtrArray * gaux_ptr_array_from_null_terminated_array( gpointer * src, GAuxDupFunc dup_func, GDestroyNotify element_free_func); gboolean gaux_streq( // alternative to g_str_equal(), has GEqualFunc signature gconstpointer a, gconstpointer b); gboolean gaux_ptr_array_find_with_equal_func( GPtrArray * haystack, gconstpointer needle, GEqualFunc equal_func, guint * index_); #ifdef __cplusplus } #endif #endif /* GLIB_UTIL_H_ */ ddcui-0.3.0/src/c_util/report_util.c000066400000000000000000000600761427175135000174020ustar00rootroot00000000000000/** @file report_util.c * * Functions for creating messages in a standardized format, with flexible * indentation. * * The functions in this source file are thread safe. * * TODO: describe * - indentation depth * - indentation stack * - destination stack */ // Copyright (C) 2014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ #include #include #include #include #include #include #include #include /** \endcond */ #include "coredefs_base.h" #include "file_util_base.h" #include "string_util.h" #include "report_util.h" #define DEFAULT_INDENT_SPACES_PER_DEPTH 3 #define INDENT_SPACES_STACK_SIZE 16 #define OUTPUT_DEST_STACK_SIZE 8 #ifdef OLD static int indent_spaces_stack[INDENT_SPACES_STACK_SIZE]; static int indent_spaces_stack_pos = -1; static FILE* output_dest_stack[OUTPUT_DEST_STACK_SIZE]; static int output_dest_stack_pos = -1; // work around for fact that can't initialize the initial stack entry to stdout static FILE* alt_initial_output_dest = NULL; static bool initial_output_dest_changed = false; #endif static FILE* default_output_dest; /** Sets the initial report output destination for newly created threads. * * Note this does not change the report output destination for existing threads. * * @param output_dest default output destination */ void rpt_set_default_output_dest(FILE* output_dest) { default_output_dest = output_dest; } //* Thread specific state */ typedef struct { uint8_t indent_spaces_stack[INDENT_SPACES_STACK_SIZE]; int indent_spaces_stack_pos; // initial -1; FILE* output_dest_stack[OUTPUT_DEST_STACK_SIZE]; int output_dest_stack_pos; // initial -1; // work around for fact that can't initialize the initial stack entry to stdout FILE* alt_initial_output_dest; // initial NULL; bool initial_output_dest_changed; // initial false; } Per_Thread_Settings; /** Returns a struct for maintaining thread-specific settings * @return thread-specific struct of global settings */ static Per_Thread_Settings * get_thread_settings() { static GPrivate per_thread_settings_key = G_PRIVATE_INIT(g_free); Per_Thread_Settings* settings = g_private_get(&per_thread_settings_key); // GThread * this_thread = g_thread_self(); // printf("(%s) this_thread=%p, settings=%p\n", __func__, this_thread, settings); if (!settings) { settings = g_new0(Per_Thread_Settings, 1); settings->indent_spaces_stack_pos = -1; settings->output_dest_stack_pos = -1; if (default_output_dest) settings->output_dest_stack[++settings->output_dest_stack_pos] = default_output_dest; g_private_set(&per_thread_settings_key, settings); } // printf("(%s) Returning: %p\n", __func__, settings); return settings; } // // Indentation // // Functions that allow for temporarily changing the number of indentation // spaces per logical indentation depth on the current thread. // 10/16/15: not currently used /** Sets the spaces-per-indentation-depth to be used for report functions. * The current spaces-per-depth is saved on the thread-specific spaces-per-depth stack. * * @param new_dest new output destination */ void rpt_push_indent(int new_spaces_per_depth) { Per_Thread_Settings * settings = get_thread_settings(); assert(settings->indent_spaces_stack_pos < INDENT_SPACES_STACK_SIZE-1); settings->indent_spaces_stack[++settings->indent_spaces_stack_pos] = new_spaces_per_depth; } /** Pops the space-per-indentation-depth stack. * * @remark * No effect if stack is empty. */ void rpt_pop_indent() { Per_Thread_Settings * settings = get_thread_settings(); if (settings->indent_spaces_stack_pos >= 0) settings->indent_spaces_stack_pos--; } /** Empties the space-per-indentation-depth stack. * * The effect is to reset the per-thread spaces-per-indentation-depth * to its default value. */ void rpt_reset_indent_stack() { Per_Thread_Settings * settings = get_thread_settings(); settings->indent_spaces_stack_pos = -1; } /** Given a logical indentation depth, returns the number of spaces * of indentation to be used. * * @param depth logical indentation depth, if < 0 perform no indentation * @return number of indentation spaces */ int rpt_get_indent(int depth) { if (depth < 0) depth = 0; Per_Thread_Settings * settings = get_thread_settings(); int spaces_ct = DEFAULT_INDENT_SPACES_PER_DEPTH; if (settings->indent_spaces_stack_pos >= 0) spaces_ct = settings->indent_spaces_stack[settings->indent_spaces_stack_pos]; return depth * spaces_ct; } // Functions that allow for temporarily changing the output destination // on the current thread. /** Sets the output destination to be used for report functions. * The current output destination is saved on the output destination stack. * * @param new_dest new output destination */ void rpt_push_output_dest(FILE* new_dest) { Per_Thread_Settings * settings = get_thread_settings(); assert(settings->output_dest_stack_pos < OUTPUT_DEST_STACK_SIZE-1); settings->output_dest_stack[++settings->output_dest_stack_pos] = new_dest; } /** Pops the output destination stack, and sets the output destination * to be used for report functions to the new top of the stack. */ void rpt_pop_output_dest() { Per_Thread_Settings * settings = get_thread_settings(); if (settings->output_dest_stack_pos >= 0) settings->output_dest_stack_pos--; } /** Clears the output destination stack. * The output destination to be used for report functions to the default (stdout). */ void rpt_reset_output_dest_stack() { Per_Thread_Settings * settings = get_thread_settings(); settings->output_dest_stack_pos = -1; } /** Gets the current output destination. * * @return current output destination */ FILE * rpt_cur_output_dest() { Per_Thread_Settings * settings = get_thread_settings(); // special handling for unpushed case because can't statically initialize // output_dest_stack[0] to stdout FILE * result = NULL; if (settings->output_dest_stack_pos < 0) result = (settings->initial_output_dest_changed) ? settings->alt_initial_output_dest : stdout; else result = settings->output_dest_stack[settings->output_dest_stack_pos]; return result; } /** Debugging function to show output destination. */ void rpt_debug_output_dest() { Per_Thread_Settings * settings = get_thread_settings(); FILE * dest = rpt_cur_output_dest(); char * addl = (dest == stdout) ? " (stdout)" : ""; printf("(%s) output_dest_stack[%d] = %p %s\n", __func__, settings->output_dest_stack_pos, (void*)dest, addl); } /** Changes the current output destination, without saving * the current output destination on the destination stack. * * @param new_dest new output destination * * @remark Needed for set_fout() in core.c */ void rpt_change_output_dest(FILE* new_dest) { Per_Thread_Settings * settings = get_thread_settings(); if (settings->output_dest_stack_pos >= 0) settings->output_dest_stack[settings->output_dest_stack_pos] = new_dest; else { settings->initial_output_dest_changed = true; settings->alt_initial_output_dest = new_dest; } } // should not be needed, for diagnosing a problem void rpt_flush() { fflush(rpt_cur_output_dest()); } /** Writes a newline to the current output destination. */ void rpt_nl() { f0printf(rpt_cur_output_dest(), "\n"); } /** Writes a constant string to the current output destination. * * A newline is appended to the string specified. * * The output is indented per the specified indentation depth. * * @param title string to write * @param depth logical indentation depth. * * @remark This is the core function through which all output is funneled. */ void rpt_title(const char * title, int depth) { bool debug = false; if (debug) printf("(%s) Writing to %p\n", __func__, (void*)rpt_cur_output_dest()); f0printf(rpt_cur_output_dest(), "%*s%s\n", rpt_get_indent(depth), "", title); } /** Writes a constant string to the current output destination. * * A newline is appended to the string specified. * * The output is indented per the specified indentation depth. * * @param depth logical indentation depth. * @param title string to write * * @remark * This function is logically equivalent to #rpt_title(), except that * the **depth** parameter is first, not last. * Experience wih the API has shown that #rpt_title() tends not to be * used along with #rpt_vstring() because the different position of the * **depth** parameter makes the code harder to read. */ void rpt_label(int depth, const char * text) { rpt_title(text, depth); } /** Writes a formatted string to the current output destination. * * A newline is appended to the string specified * * @param depth logical indentation depth * @param format format string (normal printf) * @param ... arguments * * @remark Note that the depth parm is first on this function because of variable args */ void rpt_vstring(int depth, char * format, ...) { int buffer_size = 200; char buffer[buffer_size]; char * buf = buffer; va_list(args); va_start(args, format); int reqd_size = vsnprintf(buffer, buffer_size, format, args); // if buffer wasn't sufficiently large, allocate a temporary buffer if (reqd_size >= buffer_size) { // printf("(%s) Allocating temp buffer, reqd_size=%d\n", __func__, reqd_size); buf = malloc(reqd_size+1); va_start(args, format); vsnprintf(buf, reqd_size+1, format, args); } va_end(args); rpt_title(buf, depth); if (buf != buffer) free(buf); } /** Convenience function that writes multiple constant strings. * * @param depth logical indentation depth * @param ... pointers to constant strings, * last pointer is NULL to terminate list */ void rpt_multiline(int depth, ...) { va_list args; va_start(args, depth); char * s = NULL; while( (s = va_arg(args, char *)) != NULL) { rpt_title(s, depth); } va_end(args); } /** Writes all strings in a GPtrArray to the current report destination * * @param depth logical indentation depth * @param strings pointer to GPtrArray of strings */ void rpt_g_ptr_array(int depth, GPtrArray * strings) { for (int ndx = 0; ndx < strings->len; ndx++) { char * s = g_ptr_array_index(strings, ndx); rpt_title(s, depth); } } /** Writes a hex dump with indentation. * Output is written to the current report destination * * @param data start of bytes to dump * @param size number of bytes to dump * @param depth logical indentation depth */ void rpt_hex_dump(const Byte * data, int size, int depth) { fhex_dump_indented(rpt_cur_output_dest(), data, size, rpt_get_indent(depth)); } /** Writes a Null_Terminated_String_Array with indentation. * Output is written to the current report destination. * * @param ntsa array to report * @param depth logical indentation depth */ void rpt_ntsa(Null_Terminated_String_Array ntsa, int depth) { assert(ntsa); for (int ndx=0; ntsa[ndx]; ndx++) { rpt_vstring(depth, "%s", ntsa[ndx]); } } /** Writes a string to the current output destination, describing a pointer * to a named data structure. * * The output is indented per the specified indentation depth. * * @param name struct name * @param ptr pointer to struc * @param depth logical indentation depth */ void rpt_structure_loc(const char * name, const void * ptr, int depth) { // fprintf(rpt_cur_output_dest(), "%*s%s at: %p\n", rpt_indent(depth), "", name, ptr); rpt_vstring(depth, "%s at: %p", name, ptr); } /** Writes a pair of strings to the current output destination. * * If offset_absolute is true, then the s2 value will start in the same column, * irrespective of the line indentation. This may make some reports easier to read. * * @param s1 first string * @param s2 second string * @param col2offset offset from start of line where s2 starts * @param offset_absolute if true, col2offset is relative to the start of the line, before indentation * if false, col2offset is relative to the indented start of s1 * @param depth logical indentation depth */ void rpt_2col(char * s1, char * s2, int col2offset, bool offset_absolute, int depth) { int col1sz = col2offset; int indentct = rpt_get_indent(depth); if (offset_absolute) col1sz = col1sz - indentct; rpt_vstring(depth, "%-*s%s", col1sz, s1, s2 ); } /** Reports the contents of a file. * * @param fn name of file * @param verbose if true, emit message if error reading file * @param depth logical indentation depth * @retval >=0 number of lines read * @retval <0 -errno from fopen() or getline() */ int rpt_file_contents(const char * fn, bool verbose, int depth) { GPtrArray * line_array = g_ptr_array_new(); g_ptr_array_set_free_func(line_array, g_free); int rc = file_getlines(fn, line_array, false); if (rc < 0) { if (verbose) rpt_vstring(depth, "Error reading file %s: %s", fn, strerror(-rc)); } else if (rc == 0) { if (verbose) rpt_vstring(depth, "Empty file: %s", fn); } else if (rc > 0) { int ndx = 0; for (; ndx < line_array->len; ndx++) { char * curline = g_ptr_array_index(line_array, ndx); // trim_in_place(curline); // strip trailing newline - now done in file_getlines() rpt_title(curline, depth); } } g_ptr_array_free(line_array, true); return rc; } /* The remaining rpt_ functions various data types share a common formatting so that they can * be use together. All channel their output through rpt_str(). * * Depending on whether the info parm is null, output takes one of the following forms: * name (info) : value * name : value */ /** Writes a string to the current output destination describing a named character string value. * * The output is indented per the specified indentation depth. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The string value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val string value * @param depth logical indentation depth */ void rpt_str(const char * name, char * info, const char * val, int depth) { bool debug = false; if (debug) printf("(%s) Writing to %p\n", __func__, (void*)rpt_cur_output_dest()); char infobuf[100]; if (info) snprintf(infobuf, 99, "(%s)", info); else infobuf[0] = '\0'; rpt_vstring(depth, "%-25s %30s : %s", name, infobuf, val); } /** Writes a string to the current output destination describing a boolean value. * * The value is displayed as "true" or "false". * * The output is indented per the specified indentation depth. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val value to show * @param depth logical indentation depth * * The value is formatted as "true" or "false". */ void rpt_bool(char * name, char * info, bool val, int depth) { char * valName = (val) ? "true" : "false"; rpt_str(name, info, valName, depth); } /** Writes a string to the current output destination, describing a named integer value. * * The output is indented per the specified indentation depth. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val integer value * @param depth logical indentation depth */ void rpt_int(char * name, char * info, int val, int depth) { char buf[10]; snprintf(buf, 9, "%d", val); rpt_str(name, info, buf, depth); } /** Writes a string to the current output destination, describing a named unsigned integer value. * * The output is indented per the specified indentation depth. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val unsigned integer value * @param depth logical indentation depth */ void rpt_unsigned(char * name, char * info, int val, int depth) { char buf[10]; snprintf(buf, 9, "%u", val); rpt_str(name, info, buf, depth); } /** Writes a string to the current output destination describing a 4 byte integer value, * indented per the specified indentation depth. * * The integer value is formatted as printable hex. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val integer value * @param depth logical indentation depth */ void rpt_int_as_hex(char * name, char * info, int val, int depth) { char buf[16]; snprintf(buf, 15, "0x%08x", val); rpt_str(name, info, buf, depth); } /** Writes a string to the current output destination describing a single byte value, * indented per the specified indentation depth. * * The value is formatted as printable hex. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val value * @param depth logical indentation depth */ void rpt_uint8_as_hex(char * name, char * info, unsigned char val, int depth) { char buf[16]; snprintf(buf, 15, "0x%02x", val); rpt_str(name, info, buf, depth); } /** Writes a string to the current output destination describing a named integer * value having a symbolic string representation. * * The output is indented per the specified indentation depth. * * The integer value is converted to a string using the specified function. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val integer value * @param func interpretation function * @param depth logical indentation depth */ void rpt_mapped_int(char * name, char * info, int val, Value_To_Name_Function func, int depth) { char * valueName = func(val); char buf[100]; snprintf(buf, 100, "%d - %s", val, valueName); rpt_str(name, info, buf, depth); } /** Writes a string to the current output destination describing a sequence of bytes, * indented per the specified indentation depth. * * The value is formatted as printable hex. * * Optionally, a description string can be specified along with the name. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param bytes pointer to start of bytes to show * @param ct number of bytes to show * @param hex_prefix_flag if true, the printable hex value will begin with "0x" * @param depth logical indentation depth */ void rpt_bytes_as_hex( const char * name, char * info, Byte * bytes, int ct, bool hex_prefix_flag, int depth) { // printf("(%s) bytes=%p, ct=%d\n", __func__, bytes, ct); int bufsz = 2*ct + 1; bufsz++; // hack if (hex_prefix_flag) bufsz += 2; char * buf = malloc(bufsz); char * hex_prefix = (hex_prefix_flag) ? "0x" : ""; char * hs = hexstring(bytes, ct); snprintf(buf, bufsz-1, "%s%s", hex_prefix, hs); rpt_str(name, info, buf, depth); free(buf); free(hs); } // Functions for reporting integers that are collections of named bits #ifdef DEBUG static void report_flag_info( Flag_Info* pflag_info, int depth) { assert(pflag_info); rpt_structure_loc("FlagInfo", pflag_info, depth); int d1 = depth+1; rpt_str( "flag_name", NULL, pflag_info->flag_name, d1); rpt_str( "flag_info", NULL, pflag_info->flag_info, d1); rpt_int_as_hex("flag_val", NULL, pflag_info->flag_val, d1); } /* Function for debugging findFlagInfoDictionary. * * Reports the contents of a FlagDictionay record. */ static void report_flag_info_dictionary(Flag_Dictionary* pDict, int depth) { assert(pDict); rpt_structure_loc("Flag_Dictionary", pDict, depth); int d1 = depth+1; rpt_int("flag_info_ct", NULL, pDict->flag_info_ct, d1); int ndx=0; for(;ndx < pDict->flag_info_ct; ndx++) { report_flag_info(&pDict->flag_info_recs[ndx], d1); } } #endif static Flag_Info * find_flag_info_in_dictionary(char * flag_name, Flag_Dictionary * pdict) { Flag_Info * result = NULL; // printf("(%s) Starting. flag_name=%s, pdict=%p \n", __func__, flagName, pdict ); // printf("(%s) pdict->flag_info_ct=%d \n", __func__, pdict->flag_info_ct ); // report_flag_info_dictionary(pdict, 2); int ndx; for (ndx=0; ndx < pdict->flag_info_ct; ndx++) { // printf("(%s) ndx=%d \n", __func__, ndx ); // Flag_Info pcur_info = &(pdict->flag_info_recs[ndx]); // printf("(%s) pdict->flag_info_recs[ndx].flag_name=%s \n", __func__, pdict->flag_info_recs[ndx].flag_name ); if ( streq(flag_name, pdict->flag_info_recs[ndx].flag_name)) { // printf("(%s) Match \n", __func__ ); result = &pdict->flag_info_recs[ndx]; break; } } // printf("(%s) Returning: %p \n", __func__, result ); return result; } static void char_buf_append(char * buffer, int bufsize, char * val_to_append) { assert(strlen(buffer) + strlen(val_to_append) < bufsize); strcat(buffer, val_to_append); } static void flag_val_to_string_using_dictionary( int flags_val, Flag_Name_Set * pflag_name_set, Flag_Dictionary * pdict, char * buffer, int bufsize ) { // printf("(%s) flagsVal=0x%02x, pflagNameSet=%p, pDict=%p \n", __func__, flagsVal, pflagNameSet, pDict ); // printf("(%s) pflagNameSet->flagNameCt=%d \n", __func__, pflagNameSet->flagNameCt ); // printf("(%s) pDict->flagInfoCt=%d \n", __func__, pDict->flagInfoCt ); assert(buffer && bufsize > 1); buffer[0] = '\0'; int ndx; bool first = true; for (ndx=0; ndx < pflag_name_set->flag_name_ct; ndx++) { Flag_Info * pflag_info = find_flag_info_in_dictionary(pflag_name_set->flag_names[ndx], pdict); // printf("(%s) ndx=%d, pFlagInfp=%p \n", __func__, ndx, pFlagInfo ); if (flags_val & pflag_info->flag_val) { if (first) first = false; else char_buf_append(buffer, bufsize, ", "); char_buf_append(buffer, bufsize, pflag_info->flag_name); } } // printf("(%s) Returning |%s|\n", __func__, buffer ); } /** Writes a string to the current output destination describing an integer * that is to be interpreted as a named collection of named bits. * * Output is indented per the specified indentation depth. * The description string will be surrounded by parentheses. * * The value is prefixed with a colon. * * @param name name of value * @param info if non-null, description of value * @param val value to interpret * @param p_flag_name_set * @param p_dict * @param depth logical indentation depth */ void rpt_ifval2(char* name, char* info, int val, Flag_Name_Set* p_flag_name_set, Flag_Dictionary* p_dict, int depth) { char buf[1000]; buf[0] = '\0'; snprintf(buf, 7, "0x%04x", val); char_buf_append(buf, sizeof(buf), " - "); flag_val_to_string_using_dictionary(val, p_flag_name_set, p_dict, buf, sizeof(buf)); rpt_str(name, info, buf, depth); } ddcui-0.3.0/src/c_util/report_util.h000066400000000000000000000050101427175135000173720ustar00rootroot00000000000000/** @file report_util.h * * Report utility package */ // Copyright (C) 2014-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef REPORT_UTIL_H_ #define REPORT_UTIL_H_ /** \cond */ #include #include #include /** \endcond */ #include "coredefs_base.h" #include "string_util.h" void rpt_set_default_output_dest(FILE* output_dest); void rpt_push_output_dest(FILE* new_dest); void rpt_pop_output_dest(); FILE * rpt_cur_output_dest(); void rpt_reset_output_dest_stack(); void rpt_change_output_dest(FILE* new_dest); void rpt_debug_output_dest(); int rpt_get_indent(int depth); void rpt_flush(); void rpt_nl(); void rpt_title(const char * title, int depth); void rpt_label(int depth, const char * text); void rpt_multiline(int depth, ...); void rpt_g_ptr_array(int depth, GPtrArray * strings); void rpt_vstring(int depth, char * format, ...) ; void rpt_2col(char * s1, char * s2, int col2offset, bool offset_absolute, int depth); void rpt_structure_loc(const char * name, const void * ptr, int depth); void rpt_hex_dump(const Byte * data, int size, int depth); void rpt_ntsa(Null_Terminated_String_Array ntsa, int depth); int rpt_file_contents(const char * fn, bool verbose, int depth); // Remaining rpt_ functions share common formatting void rpt_str(const char * name, char * info, const char * val, int depth); void rpt_int(char * name, char * info, int val, int depth); void rpt_unsigned(char * name, char * info, int val, int depth); void rpt_bool(char * name, char * info, bool val, int depth); /** Interpretation function used by rpt_mapped_int() */ typedef char * (*Value_To_Name_Function)(int val); void rpt_mapped_int(char * name, char * info, int val, Value_To_Name_Function func, int depth); void rpt_int_as_hex(char * name, char * info, int val, int depth); void rpt_uint8_as_hex(char * name, char * info, unsigned char val, int depth) ; void rpt_bytes_as_hex(const char * name, char * info, Byte * bytes, int ct, bool hex_prefix_flag, int depth); typedef struct { char * flag_name; char * flag_info; int flag_val; } Flag_Info; typedef struct { int flag_info_ct; Flag_Info * flag_info_recs; } Flag_Dictionary; typedef struct { int flag_name_ct; char ** flag_names; } Flag_Name_Set; void rpt_ifval2(char * name, char * info, int val, Flag_Name_Set * pflagNameSet, Flag_Dictionary * pDict, int depth); #endif /* REPORT_UTIL_H_ */ ddcui-0.3.0/src/c_util/simple_ini_file.c000066400000000000000000000235661427175135000201640ustar00rootroot00000000000000/** \file simple_ini_file.c * * Reads an INI style configuration file */ // Copyright (C) 2021-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #include #include #include "file_util_base.h" #include "string_util.h" #include "xdg_util.h" #include "simple_ini_file.h" static bool is_comment(char * s) { bool debug = false; bool result = false; if (strlen(s) == 0) result = true; else { char ch = s[0]; // DBGMSF(debug, "ch=%c=%d, 0x%02x", ch, (int)ch, ch); // DBGMSF(debug, " %c=%d 0x%02x", ';', (int)';', ';'); if (ch == ';' || ch == '*' || ch == '#') { // DBGMSF(debug, "WTF!"); result = true; } } if (debug) printf("(%s) s: %s, Returning %s\n", __func__, s, SBOOL(result)); return result; } static bool is_segment(char * s, char ** seg_name_loc) { bool debug = false; bool result = false; if (strlen(s) > 0 && *s == '[' && s[strlen(s)-1] == ']') { char * untrimmed = substr(s, 1, strlen(s)-2); // DBGMSF(debug, "untrimmed=|%s|", untrimmed); char * seg_name = strtrim(untrimmed); for (char * p = seg_name; *p; p++) {*p = tolower(*p);} // DBGMSF(debug, "seg_name=|%s|", seg_name); if (strlen(seg_name) > 0) { *seg_name_loc = seg_name; result = true; } else free(seg_name); free(untrimmed); } if (debug) printf("(%s) s: %s, Returning %s\n", __func__, s, SBOOL(result)); return result; } static bool is_kv(char * s, char ** key_loc, char ** value_loc) { bool debug = false; if (debug) printf("(%s) Starting. s->|%s|\n", __func__, s); bool result = false; char * colon = strchr(s,':'); if (!colon) colon = strchr(s,'='); if (colon) { char * untrimmed_key = substr(s, 0, colon-s); // allocates untrimmed_key char * key = strtrim( untrimmed_key ); // allocates key for (char *p = key; *p; p++) {*p=tolower(*p);} // DBGMSF(debug, "untrimmed_key = |%s|, key = |%s|", untrimmed_key, key); char * s_end = s + strlen(s); char * v_start = colon+1; char * untrimmed_value = substr(v_start, 0, s_end-v_start); // allocates untrimmed_value char * value = strtrim( untrimmed_value); // allocates value // DBGMSF(debug, "untrimmed_value = |%s|, value = |%s|", untrimmed_value, value); // DBGMSF(debug, "key=|%s|, value=|%s|", key, value); if (strlen(key) > 0) { *key_loc = key; *value_loc = value; result = true; } else { free(key); free(value); } free(untrimmed_key); free(untrimmed_value); } if (debug) printf("(%s) s: |%s|, Returning %s\n", __func__, s, SBOOL(result)); return result; } static void emit_error_msg(char * msg, GPtrArray * errmsgs, bool verbose) { if (verbose) printf("%s\n", msg); if (errmsgs) g_ptr_array_add(errmsgs, msg); else free(msg); } /** Loads an INI style configuration file into a newly allocated #Parsed_Ini_File. * Keys of the hash table in the struct have the form /. * * \param config_file_name file name * \param errmsgs if non-null, collects per-line error messages * \param verbose if true, write error messages to terminal * \param parsed_ini_loc where to return newly allocated parsed ini file * \retval 0 success * \retval -ENOENT configuration file not found * \retval -EBADMSG errors parsing configuration file * \retval < 0 errors reading configuration file * * If the configuration file is not found (-ENOENT), or there are errors reading * or parsing the configuration file, *hash_table_loc is NULL. * * If errors occur reading or interpreting the file, messages will be added * to **errmsgs**. * * \remark * There's really no appropriate errno value for errors parsing the file, * which is a form of bad data. EBADMSG has been hijacked for this purpose. */ int ini_file_load( const char * ini_file_name, GPtrArray* errmsgs, bool verbose, Parsed_Ini_File** parsed_ini_loc) { bool debug = false; if (debug) verbose = true; assert(ini_file_name); int result = 0; *parsed_ini_loc = NULL; char * cur_segment = NULL; GHashTable * ini_file_hash = NULL; GPtrArray * config_lines = g_ptr_array_new_with_free_func(g_free); int getlines_rc = file_getlines(ini_file_name, config_lines, verbose); if (debug) printf("(%s) file_getlines() returned %d\n", __func__, getlines_rc); if (getlines_rc < 0) { result = getlines_rc; if (getlines_rc != -ENOENT) { char * msg = g_strdup_printf("Error reading configuration file %s: %s", ini_file_name, strerror(-getlines_rc) ); emit_error_msg(msg, errmsgs, verbose); } } // error reading lines else { //process the lines ini_file_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); int error_ct = 0; if (debug) printf("(%s) config_lines->len = %d\n", __func__, config_lines->len); for (guint ndx = 0; ndx < config_lines->len; ndx++) { char * line = g_ptr_array_index(config_lines, ndx); if (debug) printf("(%s) Processing line %d: |%s|\n", __func__, ndx+1, line); char * trimmed = trim_in_place(line); // DBGMSF(debug, "line=%d. trimmed=|%s|", ndx+1, trimmed); char * seg_name; char * key; char * value; if (is_comment(trimmed)) { } else if (is_segment(trimmed, &seg_name)) { if (cur_segment) free(cur_segment); cur_segment = seg_name; } else if ( is_kv(trimmed, &key, &value) ) { if (cur_segment) { char * full_key = g_strdup_printf("%s/%s", cur_segment, key); // allocates full_key if (debug) printf("(%s) Inserting %s -> %s\n", __func__, full_key, value); g_hash_table_insert(ini_file_hash, full_key, value); } else { if (debug) printf("(%s) trimmed: |%s|\n", __func__, trimmed); char * msg = g_strdup_printf("Line %d: Invalid before section header: %s", ndx+1, trimmed); emit_error_msg(msg, errmsgs, verbose); error_ct++; free(value); } free(key); } else { char * msg = (cur_segment) ? g_strdup_printf("Line %d: invalid: %s", ndx+1, trimmed) : g_strdup_printf("Line %d: invalid before section header: %s", ndx+1, trimmed); emit_error_msg(msg, errmsgs, verbose); error_ct++; } } // for loop if (debug) printf("(%s) Freeing config_lines\n", __func__); g_ptr_array_free(config_lines, true); if (cur_segment) free(cur_segment); if ( error_ct > 0 ) { result = -EBADMSG; g_hash_table_destroy(ini_file_hash); ini_file_hash = NULL; } } // process the lines if (debug) { if (errmsgs && errmsgs->len > 0) { for (guint ndx = 0; ndx < errmsgs->len; ndx++) printf(" %s\n", (char *) g_ptr_array_index(errmsgs, ndx)); } } ASSERT_IFF(result==0, ini_file_hash); if (result == 0) { Parsed_Ini_File * ini_file = calloc(1, sizeof(Parsed_Ini_File)); memcpy(ini_file->marker, PARSED_INI_FILE_MARKER, 4); ini_file->config_fn = strdup(ini_file_name); ini_file->hash_table = ini_file_hash; *parsed_ini_loc = ini_file; } if (debug) { printf("(%s) Done.*parsed_ini_loc=%p, returning %d\n", __func__, (void*)*parsed_ini_loc, result); fflush(stdout); } ASSERT_IFF(result==0, *parsed_ini_loc); return result; } void ini_file_dump(Parsed_Ini_File * parsed_ini_file) { printf("(%s) Parsed_Ini_File at %p:\n", __func__, (void*)parsed_ini_file); if (parsed_ini_file) { assert(memcmp(parsed_ini_file->marker, PARSED_INI_FILE_MARKER, 4) == 0); printf("(%s) File name: %s\n", __func__, parsed_ini_file->config_fn); if (parsed_ini_file->hash_table) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, parsed_ini_file->hash_table); while (g_hash_table_iter_next(&iter, &key, &value)) { printf(" %s -> %s\n", (char *) key, (char *) value); } } } } char * ini_file_get_value( Parsed_Ini_File * parsed_ini_file, const char * segment, const char * id) { bool debug = false; assert(parsed_ini_file); assert(memcmp(parsed_ini_file->marker, PARSED_INI_FILE_MARKER, 4) == 0); assert(segment); assert(id); char * result = NULL; if (parsed_ini_file->hash_table) { char * full_key = g_strdup_printf("%s/%s", segment, id); strlower(full_key); result = g_hash_table_lookup(parsed_ini_file->hash_table, full_key); free(full_key); } if (debug) printf("(%s) segment=%s, id=%s, returning: %s\n", __func__, segment, id, result); return result; } void ini_file_free(Parsed_Ini_File * parsed_ini_file) { if (parsed_ini_file) { assert(memcmp(parsed_ini_file->marker, PARSED_INI_FILE_MARKER, 4) == 0); if (parsed_ini_file->config_fn) free(parsed_ini_file->config_fn); if (parsed_ini_file->hash_table) g_hash_table_destroy(parsed_ini_file->hash_table); parsed_ini_file->marker[3] = 'x'; free(parsed_ini_file); } } ddcui-0.3.0/src/c_util/simple_ini_file.h000066400000000000000000000016471427175135000201650ustar00rootroot00000000000000/** \file simple_ini_file.h * Reads an INI style configuration file */ // Copyright (C) 2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef SIMPLE_INI_FILE_H_ #define SIMPLE_INI_FILE_H_ #include #include #define PARSED_INI_FILE_MARKER "INIF" typedef struct { char marker[4]; char * config_fn; GHashTable * hash_table; } Parsed_Ini_File; int ini_file_load( const char * ini_filename, GPtrArray* errmsgs, bool verbose, Parsed_Ini_File** ini_file_loc); char * ini_file_get_value( Parsed_Ini_File * ini_file, const char * segment, const char * id); void ini_file_dump( Parsed_Ini_File * ini_file); void ini_file_free( Parsed_Ini_File * parsed_ini_file); #endif /* SIMPLE_INI_FILE_H_ */ ddcui-0.3.0/src/c_util/string_util.c000066400000000000000000001400351427175135000173670ustar00rootroot00000000000000/** @file string_util.c * String utility functions */ // Copyright (C) 2014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ // for strcasestr() // #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include /** \endcond */ #include "glib_util.h" #include "string_util.h" // Direct writes to stdout/stderr: // debug messages // stderr: hhs_to_byte() before terminating execution because of bad value // // General // #ifdef NOT_INLINE /** Returns a character string representation of an integer as a boolean value. * * @param value value to represent * @return "true" or "false" */ char * sbool(int value) { return (value) ? "true" : "false"; } #endif // // String functions (other than hex) // /** Compares 2 strings for equality, handling nulls * * @param s1 first string * @param s2 second string * @return true if the strings match, false if not */ bool streq(const char * s1, const char * s2) { bool result = false; if ( (s1 == NULL && s2 == NULL) || (s1 != NULL && s2 != NULL && (strcmp(s1, s2) == 0) ) ) result = true; return result; } /** Tests if one string is a valid abbreviation of another. * * @param value is this string an abbreviation? * @param longname unabbreviated value * @param minchars minimum number of characters that must match * @return true/false */ bool is_abbrev(const char * value, const char * longname, size_t minchars) { bool result = false; if (value && longname) { size_t vlen = strlen(value); if ( vlen >= minchars && vlen <= strlen(longname) && memcmp(value, longname, vlen) == 0 // n. returns 0 if vlen == 0 ) { result = true; } } // printf("(%s) value=|%s|, longname=|%s| returning %d\n", __func__, value, longname, result); return result; } /** Tests if string starts with a string. * * @param value_to_test value to examine * @param prefix prefix to check for * @return true/false * * @remark Consider using lib function g_str_prefix() ?? instead * * @remark * Returns **false** if either **value_to_test** or **prefix** are null */ bool str_starts_with(const char * value_to_test, const char * prefix) { return value_to_test && prefix && is_abbrev(prefix, value_to_test, strlen(prefix)); } /** Tests if string ends with a string. * * @param value_to_test value to examine * @param suffix substring to check for * @return true/false * * @remark Consider using lib function g_str_suffix() ?? instead */ bool str_ends_with(const char * value_to_test, const char * suffix) { bool debug = false; if (debug) printf("(%s) value_to_test=|%s|, end_part=|%s|\n", __func__, value_to_test, suffix); int value_len = strlen(value_to_test); int end_part_len = strlen(suffix); bool result = false; if (end_part_len <=value_len) { int startpos = value_len-end_part_len; result = streq(value_to_test+startpos, suffix); } if (debug) printf("(%s) returning: %d\n", __func__, result); return result; } /** Tests if a string contains a substring. * @param value to test string to examine * @param segment substring to look for * @return starting position of substring, -1 if not found */ int str_contains(const char * value_to_test, const char * segment) { int result = -1; if (value_to_test && segment) { int seglen = strlen(segment); int laststart = strlen(value_to_test) - seglen; for (int ndx = 0; ndx < laststart; ndx++) { if (str_starts_with(value_to_test+ndx, segment)) { result = ndx; break; } } } return result; } /** Are all characters in the string printable? * * @param s string to test * @return true/false (true if s==NULL) */ bool str_all_printable(const char * s) { bool result = true; if (s) { for (size_t ndx = 0; ndx < strlen(s); ndx++) { if (!isprint(s[ndx])) { result = false; break; } } } return result; } /** Compares a string to a null-terminated array of strings, using a specified * comparison function. * * @param s string to test * @param match_list null terminated array of strings to test against * @param comp_func comparison function * * @retval >= 0 index of first entry in list for which the comparison function succeeds * @retval -1 no match */ int matches_by_func(const char * s, const char ** match_list, String_Comp_Func comp_func) { int result = -1; int ndx = 0; for (ndx=0; match_list[ndx] != NULL; ndx++) { if ( (*comp_func)(s, match_list[ndx])) { result = ndx; break; } } return result; } /** Tests if a string exactly matches any string in a null-terminated * array of strings. (Null_Terminated_String_Array). * * @param s string to test for * @param match_list null terminated array of pointers to strings * * @retval >= 0 index of matching array entry * @retval -1 no match */ int exactly_matches_any(const char * s, const char ** match_list) { return matches_by_func(s, match_list, streq); } /** Finds the first entry in a null terminated array of strings * that is the initial portion of a specified string. * * @param s string to test against * @param match_list array of prefix strings (null-terminated) * * @retval >= 0 index of matching prefix * @retval -1 not found */ int starts_with_any(const char * s, const char ** match_list) { return matches_by_func(s, match_list, str_starts_with); } /** Trims leading and trailing whitespace from a string and * returns the result in a buffer provided by the caller. * If the buffer is insufficiently large, the result string * is truncated. * * The result is always null terminated. * * @param s string to trim (not modified) * @param buffer where to return result * @param bufsz buffer size * * @return pointer to truncated string (i.e. buffer) */ char * strtrim_r(const char * s, char * buffer, int bufsz) { bool debug = false; if (debug) printf("(%s) s=|%s|\n", __func__, s); int slen = strlen(s); int startpos = 0; int lastpos = slen-1; // n. -1 for 1 length string while ( startpos < slen && isspace(s[startpos]) ) startpos++; if (startpos < slen) { while ( lastpos >= startpos && isspace(s[lastpos])) lastpos--; } int tlen = 1 + lastpos - startpos; if (debug) printf("(%s) startpos=%d, lastpos=%d, tlen=%d\n", __func__, startpos, lastpos, tlen); if (tlen > (bufsz-1)) tlen = bufsz-1; memcpy(buffer, s+startpos, tlen); buffer[tlen] = '\0'; if (debug) printf("(%s) returning |%s|\n", __func__, buffer); return buffer; } /** Returns a pointer to the first non-whitespace character in a string. * * @param string to trim * @return pointer to first non-whitespace character, * to the ending \0 if all characters are whitespace */ char * ltrim_in_place(char * s) { char * p = s; while (*p && isspace(*p)) p++; return p; } /** Trims trailing whitespace from a string. * * @param s string to trim * @return s * * @remark * Particularly useful for stripping trailing newlines. */ char * rtrim_in_place(char * s) { int len = strlen(s); while(len > 0 && isspace(s[len-1])) { len--; s[len] = '\0'; } return s; } /** Trims leading and trailing whitespace from a string. * Trailing whitespace characters are replaced by \0. * * @param s string to trim * @return pointer to first non-whitespcace character */ char * trim_in_place(char * s) { char * p = s; while (*p && isspace(*p)) p++; int len = strlen(p); while (len > 0 && isspace(p[len-1])) s[--len] = '\0'; return p; } /** Trims leading and trailing whitespace from a string and * returns the result in newly allocated memory. * It is the caller's responsibility to free this memory. * The result string is null terminated. * * @param s string to trim (not modified) * @return truncated string in newly allocated memory */ char * strtrim(const char * s) { int bufsz = strlen(s)+1; char * buffer = calloc(1,bufsz); strtrim_r(s, buffer, bufsz); return buffer; } /** Extracts a substring from a string * * @param s string to process * @param startpos starting position (0 based) * @param ct number of characters; if ct + startpos is greater than * the string length, ct is reduced accordingly * @return extracted substring, in newly allocated memory */ char * substr(const char * s, size_t startpos, size_t ct) { if (startpos + ct > strlen(s)) ct = strlen(s) - startpos; char * result = calloc(ct+1, sizeof(char)); strncpy(result, s+startpos, ct); result[ct] = '\0'; return result; } /** Returns the initial portion of a string * * @param s string to process * @param ct number of characters; if ct is greater than * the string length, ct is reduced accordingly * @return extracted substring, in newly allocated memory */ char * lsub(const char * s, size_t ct) { return substr(s, 0, ct); } /** Joins an array of strings into a single string, using a separator string. * * @param pieces array of strings * @param ct0 number of strings, if < 0 the array is null terminated * @param sepstr separator string, if NULL then no separator string * * @return joined string (null terminated) * * The returned string has been malloc'd. It is the responsibility of * the caller to free it. * * @remark * If ct < 0, i.e. pieces is null terminated, at most the first 9999 strings in * the pieces array are joined. */ char * strjoin( const char ** pieces, const int ct0, const char * sepstr) { // printf("(%s) ct0=%d, sepstr=|%s|\n", __func__, ct0, sepstr); int total_length = 0; int ndx; int seplen = (sepstr) ? strlen(sepstr) : 0; // sepstr may be null int max_ct = (ct0 < 0) ? 9999 : ct0; for (ndx=0; ndx < max_ct && pieces[ndx]; ndx++) { total_length += strlen(pieces[ndx]); if (ndx > 0) total_length += seplen; } total_length += 1; // for terminating null int ct = ndx; // printf("(%s) ct=%d, total_length=%d\n", __func__, ct, total_length); char * result = malloc(total_length); result[0] = '\0'; char * end = result; for (ndx=0; ndx 0 && seplen > 0) { strcpy(end, sepstr); end += strlen(sepstr); } strcpy(end, pieces[ndx]); end += strlen(pieces[ndx]); } // printf("(%s) result=%p, end=%p\n", __func__, result, end); assert(end == result + total_length -1); return result; } #ifdef FUTURE // YAGNI: String_Array typedef struct { int max_ct; int cur_ct; char** s; } String_Array; String_Array* new_string_array(int size) { String_Array * result = calloc(1, sizeof(String_Array)); result->max_ct = size; result->cur_ct = 0; result->s = calloc(sizeof(char*), size); return result; } #endif /** Splits a string based on a list of delimiter characters. * * @param str_to_split string to be split * @param delims string of delimiter characters * @return null terminated array of pieces * * Note: Each character in delims is used as an individual test. * The full string is NOT a delimiter string. */ Null_Terminated_String_Array strsplit(const char * str_to_split, const char * delims) { bool debug = false; size_t max_pieces = (strlen(str_to_split)+1); if (debug) printf("(%s) str_to_split=|%s|, delims=|%s|, max_pieces=%zu\n", __func__, str_to_split, delims, max_pieces); char** workstruct = calloc(sizeof(char *), max_pieces+1); int piecect = 0; char * str_to_split_dup = strdup(str_to_split); char * rest = str_to_split_dup; char * token; // originally token assignment was in while() clause, but valgrind // complaining about uninitialized variable, trying to figure out why token = strsep(&rest, delims); // n. overwriteedid.cs character found while (token) { if (debug) printf("(%s) token: |%s|\n", __func__, token); if (strlen(token) > 0) workstruct[piecect++] = strdup(token); token = strsep(&rest, delims); } if (debug) printf("(%s) piecect=%d\n", __func__, piecect); char ** result = calloc(sizeof(char *), piecect+1); // n. workstruct[piecect] == NULL because we used calloc() memcpy(result, workstruct, (piecect+1)*sizeof(char*) ); if (debug) { int ndx = 0; char * curpiece = result[ndx]; while (curpiece != NULL) { printf("(%s) curpiece=%p |%s|\n", __func__, curpiece, curpiece); ndx++; curpiece = result[ndx]; } } free(workstruct); free(str_to_split_dup); return result; } /** Splits a string into segments, each of which is no longer * that a specified number of characters. If delimiters are * specified, then they are used to split the string into segments. * Otherwise all segments, except possibly the last, are * **max_piece_length** in length. * * @param str_to_split string to be split * @param max_piece_length maximum length of each segment * @param delims string of delimiter characters * @return null terminated array of pieces * * @remark * Each character in **delims** is used as an individual test. * The full string is NOT a delimiter string. */ Null_Terminated_String_Array strsplit_maxlength( const char * str_to_split, uint16_t max_piece_length, const char * delims) { bool debug = false; if (debug) printf("(%s) max_piece_length=%u, delims=|%s|, str_to_split=|%s|\n", __func__, max_piece_length, delims, str_to_split); GPtrArray * pieces = g_ptr_array_sized_new(20); char * str_to_split2 = strdup(str_to_split); // work around constness char * start = str_to_split2; char * str_to_split2_end = str_to_split2 + strlen(str_to_split); if (debug) printf("(%s)x start=%p, str_to_split2_end=%p\n", __func__, (void*)start, (void*)str_to_split2_end); while (start < str_to_split2_end) { if (debug) printf("(%s) start=%p, str_to_split2_end=%p\n", __func__, (void*)start, (void*)str_to_split2_end); char * end = start + max_piece_length; if (end > str_to_split2_end) end = str_to_split2_end; // int cursize = end-start; // printf("(%s) end=%p, start=%p, cursize=%d, max_piece_length=%d\n", // __func__, end, start, cursize, max_piece_length); if ( end < str_to_split2_end) { // printf("(%s) Need to split. \n", __func__); if (delims) { char * last = end-1; while(last >= start) { // printf("(%s) last = %p\n", __func__, last); if (strchr(delims, *last)) { end = last+1; break; } last--; } } } char * piece = strndup(start, end-start); g_ptr_array_add(pieces, piece); start = start + strlen(piece); } // for some reason, if g_ptr_array_to_ntsa() is called with duplicate=false and // g_ptr_array(pieces, false) is called, valgrind complains about memory leak Null_Terminated_String_Array result = g_ptr_array_to_ntsa(pieces, /*duplicate=*/ true); g_ptr_array_set_free_func(pieces, g_free); g_ptr_array_free(pieces, true); free(str_to_split2); if (debug) ntsa_show(result); return result; } /** Frees a null terminated array of strings. * * @param string_array null terminated array of pointers to strings * @param free_strings if set, each string in the array is freed as well * * @remark * g_strfreev(string_array) equivalent to ntsa_free(string_array, true) */ void ntsa_free(Null_Terminated_String_Array string_array, bool free_strings) { bool debug = false; if (debug) printf("(%s) Freeing NTSA %p, free_strings=%s\n", __func__, (void*) string_array, sbool(free_strings) ); if (string_array) { if (free_strings) { int ndx = 0; while (string_array[ndx] != NULL) { if (debug) printf("(%s) Freeing string %d, %p->%s\n", __func__, ndx, string_array[ndx], string_array[ndx]); free(string_array[ndx++]); } } if (debug) printf("(%s) Freeing string_array=%p\n", __func__, (void*) string_array); free(string_array); } } /** Returns the number of strings in a null terminated array of strings. * * @param string_array null terminated array of pointers to strings * @return number of strings in the array * * @remark * Equivalent to g_strv_length() */ int ntsa_length(Null_Terminated_String_Array string_array) { assert(string_array); int ndx = 0; while (string_array[ndx] != NULL) { ndx++; } return ndx; } /** Creates a new #Null_Terminated_String_Array from 2 existing instances. * The result contains all the strings of the first array, followed by all * the strings of the second. * * @param a1 first instance * @param a2 second instance * @param dup if true, the pointers in the output array point to newly * allocated strings * if false, the pointers in the output array point to the * original strings. * * @return newly allocated #Null_Terminated_String_Array */ Null_Terminated_String_Array ntsa_join( Null_Terminated_String_Array a1, Null_Terminated_String_Array a2, bool dup) { assert(a1); assert(a2); int ct = ntsa_length(a1) + ntsa_length(a2); Null_Terminated_String_Array result = calloc((ct+1), sizeof(char *)); char ** to = result; char ** from = a1; while (*from) { if (dup) *to = strdup(*from); else *to = *from; to++; from++; } from = a2; while (*from) { if (dup) *to = strdup(*from); else *to = *from; to++; from++; } return result; } /** Creates copy of a #Null_Terminated_String_Array. * * The pointers in the new array point to newly allocated copies of the * original array. * * @param a1 instance to copy * @param dup if true, copy the strings as well as pointer array * @return newly allocated #Null_Terminated_String_Array */ Null_Terminated_String_Array ntsa_copy(Null_Terminated_String_Array a1, bool dup) { assert(a1); int ct = ntsa_length(a1); Null_Terminated_String_Array result = calloc((ct+1), sizeof(char *)); char ** to = result; char ** from = a1; while (*from) { if (dup) *to = strdup(*from); else *to = *from; to++; from++; } return result; } Null_Terminated_String_Array ntsa_prepend( char * value, Null_Terminated_String_Array old_array, bool dup) { int old_ct = ntsa_length(old_array); int new_ct = old_ct + 1; Null_Terminated_String_Array new_array = calloc((new_ct+1), sizeof(char *)); char ** to = new_array; *to++ = (dup) ? strdup(value) : value; char ** from = old_array; while (*from) { *to++ = (dup) ? strdup(*from) : *from; from++; } *to = NULL; // ntsa_show(argv); return new_array; } Null_Terminated_String_Array ntsa_create_empty_array() { Null_Terminated_String_Array new_array = calloc(1, sizeof(char *)); *new_array = NULL; return new_array; } /** Searches a #Null_Terminated_String_Array for an entry that matches a given * value using a match function provided. * * @param string_array null-terminated string array * @param value value to look for * @param func comparison function * @return index of first matching entry, -1 if not found */ int ntsa_findx( Null_Terminated_String_Array string_array, char * value, String_Comp_Func func) { assert(string_array); int result = -1; int ndx = 0; char * s = NULL; while ( (s=string_array[ndx]) ) { // printf("(%s) checking ndx=%d |%s|\n", __func__, ndx, s); if (func(s,value)) { result = ndx; break; } ndx++; } // printf("(%s) Returning: %d\n", __func__, result); return result; } /** Searches a #Null_Terminated_String_Array for an entry equal to a * specified value. * * @param string_array null-terminated string array * @param value value to look for * @return index of first matching entry, -1 if not found */ int ntsa_find( Null_Terminated_String_Array string_array, char * value) { return ntsa_findx(string_array, value, streq); } /* Reports the contents of a #Null_Terminated_String_Array. * * @param string_array null-terminated string array * * @remark This is not a **report** function as that would make string_util * depend on report_util, creating a circular dependency within util */ void ntsa_show(Null_Terminated_String_Array string_array) { assert(string_array); printf("Null_Terminated_String_Array at %p:\n", (void*) string_array); int ndx = 0; while (string_array[ndx]) { printf(" %p: |%s|\n", string_array[ndx], string_array[ndx]); ndx++; } printf("Total entries: %d\n", ndx); } /** Converts a #Null_Terminated_String_Array to a GPtrArray of pointers to strings. * The underlying strings are referenced, not duplicated. * * @param ntsa null-terminated array of strings * @return newly allocate GPtrArray */ GPtrArray * ntsa_to_g_ptr_array(Null_Terminated_String_Array ntsa) { int len = ntsa_length(ntsa); GPtrArray * garray = g_ptr_array_sized_new(len); int ndx; for (ndx=0; ndxlen+1, sizeof(char *)); for (guint ndx=0; ndx < gparray->len; ndx++) { if (duplicate) ntsa[ndx] = strdup(g_ptr_array_index(gparray,ndx)); else ntsa[ndx] = g_ptr_array_index(gparray,ndx); } return ntsa; } /** Converts an ASCII string to upper case. The original string is converted in place. * * @param s string to force to upper case */ void strupper(char * s) { if (s) { // check s not a null pointer char * p = s; while(*p) { *p = toupper(*p); p++; } } } /** Converts an ASCII string to lower case. The original string is converted in place. * * @param s string to force to lower case */ void strlower(char * s) { if (s) { // check s not a null pointer char * p = s; while(*p) { *p = tolower(*p); p++; } } } /** Creates an upper case copy of an ASCII string * * @param s string to copy * @return newly allocated string, NULL if s is NULL */ char * strdup_uc(const char* s) { if (!s) return NULL; char * us = strdup( s ); char * p = us; while (*p) {*p=toupper(*p); p++; } return us; } /* Replaces all instances of a character in a string with a different character. * The original string is converted in place. * * @param s string to modify * @param old_char character to replace * @param new_char replacement character * @return **s** */ char * str_replace_char(char * s, char old_char, char new_char) { if (s) { char * p = s; while (*p) { if (*p == old_char) *p = new_char; p++; } } return s; } /** Concatenates 2 strings into a newly allocated buffer. * * @param s1 first string * @param s2 second string * @return newly allocated string */ char * strcat_new(char * s1, char * s2) { assert(s1); assert(s2); char * result = malloc(strlen(s1) + strlen(s2) + 1); strcpy(result, s1); strcpy(result+strlen(s1), s2); return result; } /** Converts a sequence of characters into a (null-terminated) string. * * @param start pointer to first character * @param len number of characters * @return newly allocated string, * NULL if start was NULL (is this the most useful behavior?) */ char * chars_to_string(const char * start, int len) { assert(len >= 0); char * strbuf = NULL; if (start) { strbuf = malloc(len+1); memcpy(strbuf, start, len); *(strbuf + len) = '\0'; } return strbuf; } /** qsort() style string comparison function * * @param a pointer to a pointer to a string * @param b pointer to a pointer to a string * @return -1 if the first string sorts before the second * 0 if the strings are identical * 1 if the first string sorts after the second * * @remark * Satisfies GCompareFunc */ int indirect_strcmp(const void * a, const void * b) { char * alpha = *(char **) a; char * beta = *(char **) b; return strcmp(alpha, beta); } /** Appends a value to a string in a buffer. * * @param buf pointer to character buffer * @param bufsz buffer size * @param sepstr if non-null, separator string to insert * @param nextval value to append * * @retval true string was truncated * @retval false normal append * * @remark * Consider allowing the truncation maker, currently "..." to be * specified as a parameter. */ bool sbuf_append(char * buf, int bufsz, char * sepstr, char * nextval) { assert(buf && (bufsz > 4) ); //avoid handling pathological case bool truncated = false; size_t seplen = (sepstr) ? strlen(sepstr) : 0; size_t maxchars = bufsz-1; size_t newlen = ( strlen(buf) == 0 ) ? strlen(nextval) : ( strlen(buf) + seplen + strlen(nextval)); if (newlen <= maxchars) { if (strlen(buf) > 0 && sepstr) strcat(buf, sepstr); strcat(buf, nextval); } else { if ( strlen(buf) < (maxchars-3) ) strcat(buf, "..."); else strcpy(buf+(maxchars-3), "..."); truncated = true; } return truncated; } // // Numeric conversion // /** Converts a decimal or hexadecimal string to an integer value. * * @param sval string representing an integer * @param p_ival address at which to store integer value * @param base 10, 16, or 0 (see below) * @return true if conversion succeeded, false if it failed * * @remark * If base=10, this a normal integer conversion. * If base=16, **sval** contains a hex value, optionally * beginning with "x" or "0x". * If base=0, then either a decimal or hexadecimal conversion is performed. * If the value begins with "x" or "0x", it is treated as a hex value. * Otherwise it is treated as a decimal value. * \remark * If conversion fails, the value pointed to by **p_ival** is unchanged. * @remark * This function wraps system function strtol(), hiding the ugly details. */ bool str_to_int(const char * sval, int * p_ival, int base) { assert (base == 0 || base == 10 || base == 16); bool debug = false; if (debug) printf("(%s) sval->|%s|\n", __func__, sval); char * endptr; bool ok = false; if (sval) { if ( *sval != '\0') { long result = strtol(sval, &endptr, base); // allow hex // printf("(%s) sval=%p, endptr=%p, *endptr=|%c| (0x%02x), result=%ld\n", // __func__, sval, endptr, *endptr, *endptr, result); if (*endptr == '\0') { *p_ival = result; ok = true; } } } if (debug) { if (ok) printf("(%s) sval=%s, Returning: %s, *ival = %d\n", __func__, sval, sbool(ok), *p_ival); else printf("(%s) sval=%s, Returning: %s\n", __func__, sval, sbool(ok)); } return ok; } /** Converts a string to a float value. * * @param sval string representing an integer * @param p_fval address at which to store float value * @return true if conversion succeeded, false if it failed * * @remark * \remark * If conversion fails, the value pointed to by **p_fval** is unchanged. * @remark * This function wraps system function strtof(), hiding the ugly details. */ bool str_to_float(const char * sval, float * p_fval) { bool debug = false; if (debug) printf("(%s) sval->|%s|\n", __func__, sval); bool ok = false; if ( *sval != '\0') { char * tailptr; float result = strtof(sval, &tailptr); if (*tailptr == '\0') { *p_fval = result; ok = true; } } if (debug) { if (ok) printf("(%s) sval=%s, Returning: %s, *p_fval = %16.7f\n", __func__, sval, sbool(ok), *p_fval); else printf("(%s) sval=%s, Returning: %s\n", __func__, sval, sbool(ok)); } return ok; } // // Hex value conversion. // /** Converts a (null terminated) string of 2 hex characters to * its byte value. * * @param s pointer to hex string * @param result pointer to byte in which converted value will be returned * @retval **true** successful conversion, * @retval **false** string does not consist of hex characters, * or is not 2 characters in length. */ bool hhs_to_byte_in_buf(const char * s, Byte * result) { // printf("(%s) Starting s=%s, strlen(s)=%zd\n", __func__, s, strlen(s) ); // consider changing to fail if len != 2, or perhaps len != 1,2 //assert(strlen(s) == 2); bool ok = true; if (strlen(s) != 2) ok = false; else { char * endptr = NULL; errno = 0; long longtemp = strtol(s, &endptr, 16 ); int errsv = errno; // printf("(%s) After strtol, longtemp=%ld \n", __func__, longtemp ); // printf("errno=%d, s=|%s|, s=0x%02x &s=%p, longtemp = %ld, endptr=%p, *endptr=0x%02x\n", // errsv, s, s, &s, longtemp, endptr,*endptr); // if (*endptr != '\0' || errsv != 0) { if (endptr != s+2 || errsv != 0) { ok = false; } else *result = (Byte) longtemp; } // printf("(%s) Returning ok=%d\n", __func__, ok); return ok; } /** Converts a hex string representing a single byte into its byte value. * This is a more lenient version of hhs_to_byte_in_buf(), allowing * the value to begin with "0x" or "x", or end with "h". The allowed * prefix or suffix is case-insensitive. * * Note that if the string need not be prefixed with "0X" or suffixed with "h" * to be regarded as a hex value. * * @param s pointer to hex string * @param result pointer to byte in which result will be returned * @retval **true** successful conversion, * @retval **false** conversion unsuccessful */ bool any_one_byte_hex_string_to_byte_in_buf(const char * s, Byte * result) { // printf("(%s) s = |%s|\n", __func__, s); char * suc = strdup_uc(s); char * suc0 = suc; if (str_starts_with(suc, "0X")) suc = suc + 2; else if (*suc == 'X') suc = suc + 1; else if (str_ends_with(suc, "H")) *(suc+strlen(suc)-1) = '\0'; bool ok = hhs_to_byte_in_buf(suc, result); free(suc0); // printf("(%s) returning %d, *result=0x%02x\n", __func__, ok, *result); return ok; } /** Converts 2 hex characters to their corresponding byte value. * The characters need not be null terminated. * * @param p_hh pointer to hex characters. * @param converted pointer go byte in which converted value will be returned * @retval **true** successful conversion * @retval **false** **s** does not point to hex characters */ bool hhc_to_byte_in_buf(const char * p_hh, Byte * converted) { // printf("(%s) Starting p_hh=%.2s \n", __func__, hh ); char hhs[3]; hhs[0] = p_hh[0]; // hhs[1] = cc[1]; // why does compiler complain? hhs[1] = *(p_hh+1); hhs[2] = '\0'; return hhs_to_byte_in_buf(hhs, converted); } /** Converts a string of hex characters (null terminated) to an array of bytes. * * @param hhs string of hex characters * @param pBa address at which to return pointer to byte array * @retval >= 0 number of bytes in array, * @retval -1 string could not be converted * * If successful, the byte array whose address is returned in pBa has * been malloc'd. It is the responsibility of the caller to free it. */ int hhs_to_byte_array(const char * hhs, Byte** pBa) { if ( strlen(hhs) % 2) // if odd number of characters return -1; char xlate[] = "0123456789ABCDEF"; int bytect = strlen(hhs)/2; Byte * ba = malloc(bytect); bool ok = true; const char * h = hhs; Byte * b = ba; for (; *h && ok; b++) { char ch0 = toupper(*h++); char ch1 = toupper(*h++); char * pos0 = strchr(xlate, ch0); char * pos1 = strchr(xlate, ch1); if (pos0 && pos1) { *b = (pos0-xlate) * 16 + (pos1-xlate); } else { ok = false; } } if (!ok) { free(ba); bytect = -1; } else { *pBa = ba; } return bytect; } /** Converts a sequence of bytes to its representation as a string of hex characters. * * @param bytes pointer to bytes * @param len number of bytes * @return pointer to newly allocated hex string * * The value returned by this function has been malloc'd. It is the * responsibility of the caller to free the memory. */ char * hexstring(const unsigned char * bytes, int len) { int alloc_size = 3*len + 1; char* str_buf = malloc(alloc_size); int i; for (i = 0; i < len; i++) { // printf("(%s) 3*i = %d, alloc_size-3*i = %d\n", __func__, 3*i, alloc_size-3*i); snprintf(str_buf+3*i, alloc_size-3*i, "%02x ", bytes[i]); } // printf ("(%s) Final null offset: %d\n", __func__, 3*len-1); str_buf[3*len-1] = 0x00; // printf("(%s) Returning: |%s|\n", __func__, str_buf); return str_buf; } /** Converts a sequence of bytes to its representation as a string of hex characters. * * @param bytes pointer to bytes * @param len number of bytes * @param sepstr string to separate each 2 hex character pairs representing a byte, * if NULL then no separators will be inserted * @param uppercase if true, use uppercase hex characters, * if false, use lower case hex characters * @param buffer pointer to buffer in which hex string will be returned, * if NULL, then a buffer will be allocated * @param bufsz size of buffer * if 0, then a buffer will be allocated * @return pointer to hex string * * If this function allocates a buffer, it is the responsibility of the caller * to free the memory. */ char * hexstring2( const unsigned char * bytes, int len, const char * sepstr, bool uppercase, char * buffer, size_t bufsz) { // if (len > 1) // printf("(%s) bytes=%p, len=%d, sepstr=|%s|, uppercase=%s, buffer=%p, bufsz=%d\n", __func__, // bytes, len, sepstr, sbool(uppercase), buffer, bufsz); int sepsize = 0; if (sepstr) { sepsize = strlen(sepstr); } size_t required_size = 2*len // hex rep of bytes + (len-1)*sepsize // for separators + 1; // terminating null // if (len > 1) // printf("(%s) required_size=%d\n", __func__, required_size); // special case: if (len == 0) required_size = 1; if (!buffer) bufsz = 0; assert (bufsz == 0 || bufsz >= required_size); if (bufsz == 0) { buffer = malloc(required_size); // printf("(%s) allocate buffer at %p, length=%d\n", __func__, buffer, required_size); } char * pattern = (uppercase) ? "%02X" : "%02x"; int incr1 = 2 + sepsize; int i; if (len == 0) *buffer = '\0'; for (i=0; i < len; i++) { // printf("(%s) i=%d, buffer+i*incr1=%p\n", __func__, i, buffer+i*incr1); sprintf(buffer+i*incr1, pattern, bytes[i]); if (i < (len-1) && sepstr) strcat(buffer, sepstr); } // printf("(%s) strlen(buffer) = %ld, required_size=%d \n", __func__, strlen(buffer), required_size ); // printf("(%s) buffer=|%s|\n", __func__, buffer ); assert(strlen(buffer) == required_size-1); return buffer; } /** Thread safe version of #hexstring2(). * * This function allocates a thread specific buffer in which the hex string is built. * The buffer is valid until the next call of this function in the same thread. * * @param bytes pointer to bytes * @param len number of bytes * @param sepstr string to separate each segment of 2 hex character pairs representing bytes * if NULL then no separators will be inserted * @param hunk_size separator string frequency * @param uppercase if true, use uppercase hex characters, * if false, use lower case hex characters * @return pointer to hex string * * Note that if the returned pointer is referenced after another call to * this function, the results are unpredictable. * * This function is intended to simplify formatting of diagnostic messages. * The caller needn't be concerned with buffer size and allocation. */ char * hexstring3_t( const unsigned char * bytes, // bytes to convert int len, // number of bytes const char * sepstr, // separator string between hex digits uint8_t hunk_size, // separator string frequency bool uppercase) // use upper case hex characters { bool debug = false; static GPrivate hexstring3_key = G_PRIVATE_INIT(g_free); static GPrivate hexstring3_len_key = G_PRIVATE_INIT(g_free); if (debug) printf("(%s) bytes=%p, len=%d, sepstr=|%s|, uppercase=%s\n", __func__, bytes, len, sepstr, sbool(uppercase)); if (hunk_size == 0) sepstr = NULL; else if (sepstr == NULL) hunk_size = 0; int sepsize = 0; if (sepstr) { sepsize = strlen(sepstr); } size_t required_size = 1; // special case if len == 0 // excessive if hunk_size > 1, but not worth the effort to be accurate if (len > 0) required_size = 2*len // hex rep of bytes + (len-1)*sepsize // for separators + 1; // terminating null if (debug) printf("(%s) sepstr=|%s|, hunk_size=%d, required_size=%zu\n", __func__, sepstr, hunk_size, required_size); char * buf = get_thread_dynamic_buffer(&hexstring3_key, &hexstring3_len_key, required_size); // char * buf = get_thread_private_buffer(&hexstring3_key, NULL, required_size); char * pattern = (uppercase) ? "%02X" : "%02x"; // int incr1 = 2 + sepsize; *buf = '\0'; for (int i=0; i < len; i++) { // printf("(%s) i=%d, strlen(buf)=%ld\n", __func__, i, strlen(buf)); sprintf(buf+strlen(buf), pattern, bytes[i]); bool insert_sepstr = (hunk_size == 0) ? (i < (len-1) && sepstr) : (i < (len-1) && sepstr && (i+1)%hunk_size == 0); if (insert_sepstr) strcat(buf, sepstr); } if (debug) { printf("(%s) strlen(buf) = %ld, required_size=%zu\n", __func__, strlen(buf), required_size ); printf("(%s) buf=|%s|\n", __func__, buf ); } assert(strlen(buf) <= required_size-1); if (debug) printf("(%s) Returning: %p -> |%s|\n", __func__, buf, buf); return buf; } /** Thread safe version of #hexstring(). * * This function allocates a thread specific buffer in which the hex string is built. * The buffer is valid until the next call of this function in the same thread. * * @param bytes pointer to bytes * @param len number of bytes * @return pointer to hex string * * Note that if the returned pointer is referenced after another call to * this function, the results are unpredictable. * * This function is intended to simplify formatting of diagnostic messages, since * the caller needn't be concerned with buffer size and allocation. */ char * hexstring_t( const unsigned char * bytes, int len) { return hexstring3_t(bytes, len, " ", 1, false); } /** Dump a region of memory as hex characters and their ASCII values. * The output is indented by the specified number of spaces. * * @param fh where to write output, if NULL, write nothing * @param data start of region to show * @param size length of region * @param indents number of spaces to indent the output */ void fhex_dump_indented(FILE * fh, const Byte* data, int size, int indents) { if (fh) { int i; // index in data... int j; // index in line... char temp[10]; // was 8, compiler complains that too small char buffer[128]; char *ascii; char indentation[100]; snprintf(indentation, 100, "%*s", indents, ""); memset(buffer, 0, 128); // printf("\n"); // Printing the ruler... fprintf(fh, "%s +0 +4 +8 +c 0 4 8 c \n", indentation); ascii = buffer + 58; memset(buffer, ' ', 58 + 16); buffer[58 + 16] = '\n'; buffer[58 + 17] = '\0'; buffer[0] = '+'; buffer[1] = '0'; buffer[2] = '0'; buffer[3] = '0'; buffer[4] = '0'; for (i = 0, j = 0; i < size; i++, j++) { if (j == 16) { fprintf(fh, "%s%s", indentation, buffer); memset(buffer, ' ', 58 + 16); sprintf(temp, "+%04x", i); memcpy(buffer, temp, 5); j = 0; } sprintf(temp, "%02x", 0xff & data[i]); memcpy(buffer + 8 + (j * 3), temp, 2); if ((data[i] > 31) && (data[i] < 127)) ascii[j] = data[i]; else ascii[j] = '.'; } if (j != 0) fprintf(fh, "%s%s", indentation, buffer); } } /** Dump a region of memory as hex characters and their ASCII values. * Output is written to the location specified by parameter fh. * * @param fh where to write output * @param data start of region to show * @param size length of region */ void fhex_dump(FILE * fh, const Byte* data, int size) { fhex_dump_indented(fh, data, size, 0); } /** Dump a region of memory as hex characters and their ASCII values. * Output is written to stdout. * * @param data start of region to show * @param size length of region */ void hex_dump(const Byte* data, int size) { fhex_dump(stdout, data, size); } /** Extension of fputc() that allows a NULL stream argument, * in which case no output is written. * * @param c character to write * @param stream if null do nothing * * @return result of underlying fputs(), or 0 if stream is NULL */ int f0putc(int c, FILE * stream) { int rc = 0; if (stream) rc = fputc(c, stream); return rc; } /** Extension of fputs() that allows a NULL stream argument, * in which case no output is written. * * @param msg text to write * @param stream if null do nothing * * @return result of underlying fputs(), or 0 if stream is NULL */ int f0puts(const char * msg, FILE * stream) { int rc = 0; if (stream) rc = fputs(msg, stream); return rc; } /** Extension of fprintf() that allows a NULL stream argument, * in which case no output is written. * * @param stream if null do nothing * @param format format string * * @return result of underlying vfprintf(), or 0 if stream is NULL */ int f0printf(FILE * stream, const char * format, ...) { int rc = 0; // printf("(%s) stream=%p\n", __func__, stream); if (stream) { va_list(args); va_start(args, format); rc = vfprintf(stream, format, args); va_end(args); } return rc; } /** Extension of vfprintf() that allows a NULL stream argument, * in which case no output is written. * * @param stream if null do nothing * @param format format string * @param ap pointer to variable argument list * * @return result of underlying vfprintf(), or 0 if stream is NULL */ int vf0printf(FILE * stream, const char * format, va_list ap) { int rc = 0; if (stream) rc = vfprintf(stream, format, ap); return rc; } // // Miscellaneous // /** Tests if a range of bytes is entirely 0 * * @param bytes pointer to first byte * @param bytect number of bytes * @return **true** if all bytes are zero, **false** if not */ bool all_bytes_zero(Byte * bytes, int bytect) { Byte sum = 0; for (int ndx=0; ndx < bytect; ndx++) { sum |= bytes[ndx]; } return !sum; } // Private version of strcasestr(), avoids needing to set _GNU_SOURCE char * ascii_strcasestr(const char * haystack, const char * needle) { char * result = NULL; if (haystack && needle) { char * uhaystack = g_ascii_strup(haystack, /*len=*/ -1); // -1: null-terminated char * uneedle = g_ascii_strup(needle, /*len=*/ -1); // -1: null-terminated char * ustart = strstr(uhaystack, uneedle); if (ustart) { int offset = ustart-uhaystack; char * h2 = (char *) haystack; // cast to avoid warning re discarding const qualifier result = h2+offset; } free(uhaystack); free(uneedle); } return result; } /** Tests if any of a set of strings is a substring of a given string * * @param test string to check, must not be NULL * @param terms pointer to array of substring to check * @param ignore_case if true, test is case-insensitive * @return true if a substring is found * * @remark * If **terms** is NULL, returns **false** * @remark * Consider converting ignore_case to a flags byte of options */ bool apply_filter_terms(const char * text, char ** terms, bool ignore_case) { assert(text); bool debug = false; bool result = true; char ** term = NULL; if (terms) { // printf("(%s) filter_terms:\n", __func__); // ntsa_show(terms); result = false; term = terms; while (*term) { // printf("(%s) Comparing |%s|\n", __func__, *term); if (ignore_case) { // if (strcasestr(text,*term)) { if (ascii_strcasestr(text,*term)) { result = true; break; } } else { if (strstr(text, *term)) { result = true; break; } } term++; } } if (debug) { if (result) { printf("(%s) text=|%s|, term=|%s|, Returning: true\n", __func__, text, *term); } else { printf("(%s) text=|%s|, Returning: false\n", __func__, text); } } return result; } /** Converts a string containing a (possible) hex value to canonical form. * * If the value starts with "x" or "X", or ends with "h" or "H", or starts * with "0X", it is modified to start with "0x". * Otherwise, the returned value is identical to the input value. * * @param string_value value to convert * @return canonicalized value (caller is responsible for freeing) * * @remark * Consider converting to a function that uses a thread-specific buffer, making * the returned value valid until the next call to this function on the current * thread. Would relieve the caller of responsibility for freeing the value. */ char * canonicalize_possible_hex_value(char * string_value) { assert(string_value); int bufsz = strlen(string_value) + 1 + 1; // 1 for possible increased length, 1 for terminating null char * buf = calloc(1, bufsz); if (*string_value == 'X' || *string_value == 'x' ) { // increases string size by 1 snprintf(buf, bufsz, "0x%s", string_value+1); } else if (*(string_value + strlen(string_value)-1) == 'H' || *(string_value + strlen(string_value)-1) == 'h' ) { // increases string size by 1 int newlen = strlen(string_value)-1; snprintf(buf, bufsz, "0x%.*s", newlen, string_value); } else if (str_starts_with(string_value, "0X")) { snprintf(buf, bufsz, "0x%s", string_value+2); } else strcpy(buf, string_value); // DBGMSG("string_value=|%s|, returning |%s|", string_value, buf); return buf; } ddcui-0.3.0/src/c_util/string_util.h000066400000000000000000000132331427175135000173730ustar00rootroot00000000000000/** @file string_util.h * String utility functions header file */ // Copyright (C) 2014-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef STRINGUTIL_H_ #define STRINGUTIL_H_ /** \cond */ #include #include #include #include /** \endcond */ #include "coredefs_base.h" #include "glib_util.h" #ifdef __cplusplus extern "C" { #endif // // General // static inline const char * sbool(uint64_t val) { return (val) ? "true" : "false"; } // A macro alternative to sbool() #define SBOOL(val) ( (val) ? "true" : "false" ) // // String functions (other than hex) // bool streq(const char * s1, const char * s2); bool is_abbrev(const char * value, const char * longname, size_t minchars); bool str_starts_with(const char * value_to_test, const char * start_part); bool str_ends_with(const char * value_to_test, const char * end_part); int str_contains(const char * value_to_test, const char * segment); bool str_all_printable(const char * s); void strupper(char * s); void strlower(char * s); char * strdup_uc(const char* s); char * strjoin( const char ** pieces, const int ct, const char * sepstr); char * chars_to_string(const char * start, int len); char * strtrim(const char * s); char * strtrim_r(const char * s, char * buffer, int bufsz); char * ltrim_in_place(char * s); char * rtrim_in_place(char * s); char * trim_in_place(char * s); char * substr(const char * s, size_t startpos, size_t ct); char * lsub(const char * s, size_t ct); char * str_replace_char(char * s, char old_char, char new_char); char * strcat_new(char * s1, char * s2); bool sbuf_append(char * buf, int bufsz, char * sepstr, char * nextval); char * ascii_strcasestr(const char * haystack, const char * needle); int indirect_strcmp(const void * a, const void * b); typedef bool (*String_Comp_Func)(const char * a, const char * b); int matches_by_func( const char * word, const char ** match_list, String_Comp_Func comp_func); int exactly_matches_any(const char * word, const char ** match_list); int starts_with_any( const char * word, const char ** match_list); /** pointer to null-terminated array of strings */ typedef char** Null_Terminated_String_Array; // equivalent to GStrv void ntsa_free( Null_Terminated_String_Array string_array, bool free_strings); int ntsa_length(Null_Terminated_String_Array string_array); void ntsa_show( Null_Terminated_String_Array string_array); int ntsa_findx( Null_Terminated_String_Array string_array, char * value, String_Comp_Func func); int ntsa_find( Null_Terminated_String_Array string_array, char * value); Null_Terminated_String_Array ntsa_join( Null_Terminated_String_Array a1, Null_Terminated_String_Array a2, bool dup); Null_Terminated_String_Array ntsa_copy(Null_Terminated_String_Array a1, bool dup); Null_Terminated_String_Array ntsa_prepend(char * value, Null_Terminated_String_Array string_array, bool dup); Null_Terminated_String_Array ntsa_create_empty_array(); Null_Terminated_String_Array strsplit(const char * str_to_split, const char* delims); Null_Terminated_String_Array strsplit_maxlength( const char * str_to_split, uint16_t max_piece_length, const char * delims); GPtrArray * ntsa_to_g_ptr_array(Null_Terminated_String_Array ntsa); Null_Terminated_String_Array g_ptr_array_to_ntsa(GPtrArray * garray, bool duplicate); // // Numeric conversion // bool str_to_int(const char * sval, int * p_ival, int base); bool str_to_float(const char * sval, float * p_fval); // // Hex value conversion. // char * canonicalize_possible_hex_value(char * string_value); bool hhs_to_byte_in_buf(const char * s, Byte * result); // converts null terminated string into buffer bool any_one_byte_hex_string_to_byte_in_buf(const char * s, Byte * result); bool hhc_to_byte_in_buf(const char * hh, Byte * result); // converts 2 characters at hh into buffer int hhs_to_byte_array(const char * hhs, Byte** pBa); char * hexstring(const Byte * bytes, int size); // buffer returned must be freed char * hexstring_t( const unsigned char * bytes, int len); char * hexstring2( const unsigned char * bytes, // bytes to convert int len, // number of bytes const char * sepstr, // separator string between hex digits bool uppercase, // use upper case hex characters char * buffer, // buffer in which to return hex string size_t bufsz); // buffer size char * hexstring3_t( const unsigned char * bytes, // bytes to convert int len, // number of bytes const char * sepstr, // separator string between hex digits uint8_t hunk_size, // separator string frequency bool uppercase); // use upper case hex characters void fhex_dump_indented(FILE * fh, const Byte* data, int size, int indents); void fhex_dump( FILE * fh, const Byte* bytes, int size); void hex_dump( const Byte* bytes, int size); // // Standard function variants that handle stream == NULL // int f0putc(int c, FILE * stream); int f0puts(const char * s, FILE * stream); int f0printf( FILE * stream, const char * format, ...); int vf0printf(FILE * stream, const char * format, va_list ap); // // Miscellaneous // bool all_bytes_zero(Byte * bytes, int bytect); bool apply_filter_terms(const char * text, char ** terms, bool ignore_case); #ifdef __cplusplus } #endif #endif /* STRINGUTIL_H_ */ ddcui-0.3.0/src/c_util/xdg_util.c000066400000000000000000000344441427175135000166510ustar00rootroot00000000000000/** \file xdg_util.c * Implement XDG Base Directory Specification * * See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html */ // Copyright (C) 2020-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #define _GNU_SOURCE #include #include "xdg_util.h" /** Checks if a regular file exists. * * @param fqfn fully qualified file name * @return true/false * @remark * Trivial function copied from file_util.c to avoid dependency. */ static bool regular_file_exists(const char * fqfn) { bool result = false; struct stat stat_buf; int rc = stat(fqfn, &stat_buf); if (rc == 0) { result = S_ISREG(stat_buf.st_mode); } return result; } /** Returns the name of the base data, configuration, or cache directory. * First the specified environment variable is checked. * If no value is found the name is constructed from $HOME and * the specified sub-directory. * * The returned value is guaranteed to end in '/'. * * Caller is responsible for freeing the returned memory. */ static char * xdg_home_dir( const char * envvar_name, const char * home_subdir_name) { bool debug = false; char * xdg_home = getenv(envvar_name); // do not free if (xdg_home && strlen(xdg_home) > 0) { xdg_home = (xdg_home[strlen(xdg_home)-1] == '/') ? strdup(xdg_home) : g_strdup_printf("%s/", xdg_home); } else { char * home = getenv("HOME"); if (home && strlen(home) > 0) xdg_home = g_strdup_printf("%s/%s/", home, home_subdir_name); else xdg_home = NULL; } if (debug) printf("(%s) envvar_name=|%s|, home_subdir_name=|%s|, returning: %s\n", __func__, envvar_name, home_subdir_name, xdg_home); return xdg_home; } /** Returns the name of the xdg base directory for data files * * Caller is responsible for freeing the returned memory. */ char * xdg_data_home_dir() { bool debug = false; char * result = xdg_home_dir("XDG_DATA_HOME", ".local/share"); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the name of the xdg base directory for configuration files * * Caller is responsible for freeing the returned memory. */ char * xdg_config_home_dir() { bool debug = false; char * result = xdg_home_dir("XDG_CONFIG_HOME", ".config"); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the name of the xdg base directory for cached files * * Caller is responsible for freeing the returned memory. */ char * xdg_cache_home_dir() { bool debug = false; char * result = xdg_home_dir("XDG_CACHE_HOME", ".cache"); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the name of the xdg base directory for state files * * Caller is responsible for freeing the returned memory. */ char * xdg_state_home_dir() { bool debug = false; char * result = xdg_home_dir("XDG_STATE_HOME", ".local/state"); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the value of the specified environment variable, * If the value is blank, return default_dirs. * * Caller is responsible for freeing the returned memory. */ static char * xdg_dirs( const char * envvar_name, const char * default_dirs) { bool debug = false; char * xdg_dirs = getenv(envvar_name); // do not free if (xdg_dirs && strlen(xdg_dirs) > 0) xdg_dirs = strdup(xdg_dirs); else { xdg_dirs = strdup(default_dirs); } if (debug) printf("(%s) Returning: %s\n", __func__, xdg_dirs); assert(xdg_dirs); return xdg_dirs; } /** Returns the value of $XDG_DATA_DIRS or the default "/usr/local/share:/usr/share" * * Caller is responsible for freeing the returned memory. */ char * xdg_data_dirs() { return xdg_dirs("XDG_DATA_DIRS", "/usr/local/share/:/usr/share"); } /** Returns the value of $XDG_CONFIG_DIRS, or the default "/etc/xdg" * * Caller is responsible for freeing the returned memory. */ char * xdg_config_dirs() { return xdg_dirs("XDG_CONFIG_DIRS", "/etc/xdg"); } /** Returns a path string containing value of the XDG data home directory, * followed by the XDG data dirs string. * * Caller is responsible for freeing the returned memory. */ char * xdg_data_path() { bool debug = false; char * result = NULL; char * home_dir = xdg_data_home_dir(); char * dirs = xdg_data_dirs(); assert(dirs); if (home_dir) { result = g_strdup_printf("%s:%s", home_dir, dirs); free(home_dir); free(dirs); } else result = dirs; if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns a path string containing value of the XDG configuration home directory, * followed by the XDG config dirs string. * * Caller is responsible for freeing the returned memory. */ char * xdg_config_path() { bool debug = false; char * result = NULL; char * home_dir = xdg_config_home_dir(); char * dirs = xdg_config_dirs(); assert(dirs); if (home_dir) { result = g_strdup_printf("%s:%s", home_dir, dirs); free(home_dir); free(dirs); } else result = dirs; if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the fully qualified name of a file in the application * sub-directory of $XDG_DATA_HOME. * Does not check for the file's existence * * Caller is responsible for freeing the returned memory. */ char * xdg_data_home_file(const char * application, const char * simple_fn) { bool debug = false; char * result = NULL; char * dir = xdg_data_home_dir(); if (dir && strlen(dir) > 0) result = g_strdup_printf("%s%s/%s", dir, application, simple_fn); free(dir); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the fully qualified name of a file in the application * sub-directory of $XDG_CONFIG_HOME. * Does not check for the file's existence * * Caller is responsible for freeing the returned memory. */ char * xdg_config_home_file(const char * application, const char * simple_fn) { bool debug = false; char * result = NULL; char * dir = xdg_config_home_dir(); if (dir && strlen(dir) > 0) result = g_strdup_printf("%s%s/%s", dir, application, simple_fn); free(dir); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the fully qualified name of a file in the application * sub-directory of $XDG_CACHE_HOME. * Does not check for the file's existence * * Caller is responsible for freeing the returned memory. */ char * xdg_cache_home_file(const char * application, const char * simple_fn) { bool debug = false; char * result = NULL; char * dir = xdg_cache_home_dir(); if (dir && strlen(dir) > 0) result = g_strdup_printf("%s%s/%s", dir, application, simple_fn); free(dir); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } /** Returns the fully qualified name of a file in the application * sub-directory of $XDG_STATE_HOME. * Does not check for the file's existence * * Caller is responsible for freeing the returned memory. */ char * xdg_state_home_file(const char * application, const char * simple_fn) { bool debug = false; char * result = NULL; char * dir = xdg_state_home_dir(); if (dir && strlen(dir) > 0) result = g_strdup_printf("%s%s/%s", dir, application, simple_fn); free(dir); if (debug) printf("(%s) Returning: %s\n", __func__, result); return result; } typedef struct { char * iter_start; char * iter_end; } Iter_State; static void xdg_dirs_iter_init(char * dir_list, Iter_State * state) { state->iter_start = dir_list; // to avoid const warnings state->iter_end = state->iter_start + strlen(dir_list); } static char * xdg_dirs_iter_next(Iter_State * state) { bool debug = false; if (state->iter_start >= state->iter_end) return NULL; char * p = state->iter_start; while (p < state->iter_end && *p != ':') p++; if (p == state->iter_end) { return NULL; } int len = p - state->iter_start; char * buf = calloc(len + 1, 1); memcpy(buf, state->iter_start, len); state->iter_start = p + 1; if (debug) printf("(%s) Returning: %s\n", __func__, buf); return buf; } /* Caller is responsible for freeing the returned memory. */ static char * find_xdg_path_file( const char * path, const char * application, const char * simple_fn) { bool debug = false; if (debug) { printf("(%s) Starting. application = %s, simple_fn=%s\n", __func__, application, simple_fn); printf("(%s) Starting. path=%s\n", __func__, path); } if (!path) return NULL; Iter_State iter_state; char * next_dir = NULL; char * fqfn = NULL; char *path2 = strdup(path); xdg_dirs_iter_init(path2, &iter_state); while ( !fqfn && (next_dir = xdg_dirs_iter_next(&iter_state)) ) { int lastndx = strlen(next_dir) - 1; if (next_dir[lastndx] == '/') next_dir[lastndx] = '\0'; fqfn = g_strdup_printf("%s/%s/%s", next_dir, application, simple_fn); free(next_dir); if (debug) printf("(%s) Checking: %s\n", __func__, fqfn); // if (access(fqfn, R_OK)) { if (regular_file_exists(fqfn)) { continue; } free(fqfn); fqfn = NULL; } free(path2); if (debug) printf("(%s) Done. Returning: %s\n", __func__, fqfn); return fqfn; } /** Looks for a file first in the $XDG_DATA_HOME directory, * then in the $XDG_DATA_DIRS directories. * * \param application subdirectory name * \param simple_fn file name within subdirectory * \return fully qualified file name, or NULL if not found. * * Caller is responsible for freeing the returned memory. */ char * find_xdg_data_file( const char * application, const char * simple_fn) { bool debug = false; if (debug) printf("(%s) Starting. application=%s, simple_fn=%s\n", __func__, application, simple_fn); char * result = NULL; char * path = xdg_data_path(); result = find_xdg_path_file( path, application, simple_fn); free(path); if (debug) printf("(%s) Done. Returning: %s\n", __func__, result); return result; } /** Searches $XDG_CONFIG_HOME and then $XDG_CONFIG_DIRS for * a specified file in a particular application sub-directory. * * \param application subdirectory name * \param simple_fn file name within subdirectory * \return fully qualified file name, or NULL if not found. * * Caller is responsible for freeing the returned string. */ char * find_xdg_config_file( const char * application, const char * simple_fn) { bool debug = false; char * result = NULL; char * path = xdg_config_path(); result = find_xdg_path_file( path, application, simple_fn); free(path); if (debug) printf("(%s) application=%s, simple_fn=%s, returning: %s\n", __func__, application, simple_fn, result); return result; } /** Looks for a file in the specified subdirectory of $XDG_CACHE_HOME * * \param application subdirectory name * \param simple_fn file name within subdirectory * \return fully qualified file name, or NULL if not found. * * Caller is responsible for freeing the returned string. */ char * find_xdg_cache_file( const char * application, const char * simple_fn) { bool debug = false; char * result = NULL;; char * path = xdg_cache_home_dir(); assert(path); // will be null if $HOME not set, how to handle? result = find_xdg_path_file( path, application, simple_fn); free(path); if (debug) printf("(%s) application=%s, simple_fn=%s, returning: %s\n", __func__, application, simple_fn, result); return result; } /** Looks for a file in the specified subdirectory of $XDG_STATE_HOME * * \param application subdirectory name * \param simple_fn file name within subdirectory * \return fully qualified file name, or NULL if not found. * * Caller is responsible for freeing the returned string. */ char * find_xdg_state_file( const char * application, const char * simple_fn) { bool debug = false; char * result = NULL;; char * path = xdg_state_home_dir(); assert(path); // will be null if $HOME not set, how to handle? result = find_xdg_path_file( path, application, simple_fn); free(path); if (debug) printf("(%s) application=%s, simple_fn=%s, returning: %s\n", __func__, application, simple_fn, result); return result; } #ifdef TESTS void xdg_tests() { printf( "xdg_data_home_dir(): %s\n", xdg_data_home_dir() ); printf( "xdg_data_config_dir(): %s\n", xdg_config_home_dir() ); printf( "xdg_data_cache_dir(): %s\n", xdg_cache_home_dir() ); printf( "xdg_data_dirs(): %s\n", xdg_data_dirs() ); printf( "xdg_config_dirs(): %s\n", xdg_config_dirs() ); printf( "xdg_data_path(): %s\n", xdg_data_path() ); printf( "xdg_config_path(): %s\n", xdg_config_path() ); printf( "xdg_cache_path(): %s\n", xdg_cache_path() ); printf( "xdg_data_home_file(\"ddcutil\", \"something.mccs\"): %s", xdg_data_home_file("ddcutil", "something.mccs")); printf( "xdg_config_home_file(\"ddcutil\", \"ddcutilrc\" ): %s", xdg_config_home_file("ddcutil", "ddcutilrc")); printf( "xdg_cache_home_file(\"ddcutil\", \"capabilities\" ): %s", xdg_cache_home_file("ddcutil", "capabilities")); printf( "find xdg_data_file(\"ddcutil\", \"something.mccs\"): %s", find_xdg_data_file("ddcutil", "something.mccs")); printf( "find_xdg_config_file(\"ddcutil\", \"ddcutilrc\"): %s", find_xdg_config_file("ddcutil", "ddcutilrc")); printf( "find_xdg_cache_file(\"ddcutil\", \"capabilities\"): %s", find_xdg_cache_file("ddcutil", "capabilities")); } #endif ddcui-0.3.0/src/c_util/xdg_util.h000066400000000000000000000027641427175135000166560ustar00rootroot00000000000000/** \file xdg_util.h * Implement XDG Base Directory Specification */ // Copyright (C) 2020-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef XDG_UTIL_H_ #define XDG_UTIL_H_ char * xdg_data_home_dir(); // $XDG_DATA_HOME or $HOME/.local/share char * xdg_config_home_dir(); // $XDG_CONFIG_HOME or $HOME/.config char * xdg_cache_home_dir(); // $XDG_CACHE_HOME or $HOME/.cache char * xdg_state_home_dir(); // $XDG_STATE_HOME or $HOME/.local/state char * xdg_data_dirs(); // $XDG_DATA_DIRS or /usr/local/share:/usr/share char * xdg_config_dirs(); // $XDG_CONFIG_DIRS or /etc/xdg char * xdg_data_path(); // XDG_DATA_HOME directory, followed by XDG_DATA_DIRS char * xdg_config_path(); // XDG_CONFIG_HOME directory, followed by XDG_CONFIG_DIRS char * xdg_data_home_file( const char * application, const char * simple_fn); char * xdg_config_home_file(const char * application, const char * simple_fn); char * xdg_cache_home_file( const char * application, const char * simple_fn); char * xdg_state_home_file( const char * application, const char * simple_fn); char * find_xdg_data_file( const char * application, const char * simple_fn); char * find_xdg_config_file(const char * application, const char * simple_fn); char * find_xdg_cache_file( const char * application, const char * simple_fn); char * find_xdg_state_file( const char * application, const char * simple_fn); void xdg_tests(); #endif /* XDG_UTIL_H_ */ ddcui-0.3.0/src/cmdline/000077500000000000000000000000001427175135000150115ustar00rootroot00000000000000ddcui-0.3.0/src/cmdline/ddcui_cmd_parser.c000066400000000000000000000511061427175135000204470ustar00rootroot00000000000000/* \file ddcui_cmd_parser.c * ddcui command line parser */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #include #include #include #include #include "c_util/string_util.h" #include "base/ddcui_parms.h" #include "base/feature_list.h" #include "ddcui_cmd_parser.h" #include "ddcui_cmd_parser_aux.h" #include "ddcui_parsed_cmd.h" // Variables used by callback function static DDCA_Stats_Type stats_work = DDCA_STATS_NONE; // static char * maxtrywork = NULL; // Callback function for processing --stats gboolean stats_arg_func(const gchar* option_name, const gchar* value, gpointer data, GError** error) { bool debug = false; // DBGMSF(debug,"option_name=|%s|, value|%s|, data=%p", option_name, value, data); if (debug) printf("(%s) option_name=|%s|, value|%s|, data=%p\n", __func__, option_name, value, data); bool ok = true; if (value) { char * v2 = g_ascii_strup(value, -1); // n. returns newly allocated string if ( strcmp(v2,"ALL") == 0 ) { stats_work |= DDCA_STATS_ALL; } else if (strcmp(v2,"TRY") == 0 || is_abbrev(v2, "TRIES",3)) { stats_work |= DDCA_STATS_TRIES; } else if ( is_abbrev(v2, "CALLS",3)) { stats_work |= DDCA_STATS_CALLS; } else if (strcmp(v2,"ERRS") == 0 || is_abbrev(v2, "ERRORS",3)) { stats_work |= DDCA_STATS_ERRORS; } else if ( is_abbrev(v2,"ELAPSED",3) || is_abbrev(v2, "TIME",3)) { stats_work |= DDCA_STATS_ELAPSED; } else ok = false; free(v2); } else { stats_work = DDCA_STATS_ALL; } if (!ok) { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "invalid stats type: %s", value ); } return ok; } // signature GOptionParseFunc() gboolean pre_parse_hook( GOptionContext * context, GOptionGroup * group, gpointer data, GError** error) { // printf("(%s) data = %d\n", __func__, GPOINTER_TO_INT(data)); return true; } gboolean post_parse_hook( GOptionContext * context, GOptionGroup * group, gpointer data, GError** error) { // printf("(%s) data = %d\n", __func__, GPOINTER_TO_INT(data)); return true; } /** Primary parsing function * * \param argc number of command line arguments * \param argv array of pointers to command line arguments * \return pointer to a Parsed_Cmd struct if parsing successful * NULL if execution should be terminated */ Parsed_Ddcui_Cmd * parse_ddcui_command(int argc, char * argv[]) { bool debug = false; char * s = getenv("DDCUTIL_DEBUG_PARSE"); if (s && strlen(s) > 0) debug = true; if (debug) { printf("(%s) Starting\n", __func__ ); printf("argc=%d\n", argc); for (int ndx=0; ndx < argc; ndx++) { printf("argv[%d] = |%s|\n", ndx, argv[ndx]); } printf("(%s) prgname = %s, application_name = %s\n", __func__, g_get_prgname(), g_get_application_name() ); } // g_set_application_name("ddcui1"); Parsed_Ddcui_Cmd * parsed_cmd = new_parsed_ddcui_cmd(); gboolean ddc_flag = false; // gboolean nousb_flag = false; gboolean report_freed_excp_flag = false; gboolean timestamp_trace_flag = false; gboolean thread_id_trace_flag = false; gboolean version_flag = false; gboolean show_styles_flag = false; gboolean show_active_style_flag = false; // gboolean use_latest_nc_values_true_set = false; // gboolean use_latest_nc_values_false_set = false; gboolean hidpi_flag = false; //currently used only for testing gchar** cmd_and_args = NULL; gchar** trace_classes = NULL; gchar** trace_filenames = NULL; gchar** trace_functions = NULL; #ifdef DISABLE_VIEW_OPTION gchar* view_work = NULL; #endif gchar* nc_values_source_work = NULL; gchar* feature_set_work = NULL; gchar* custom_feature_set_work = NULL; gboolean control_key_required = false; gboolean show_unsupported_features = false; gboolean only_capabilities_true_set = false; // gboolean only_capabilities_false_set = false; gboolean all_capabilities_true_set = false; // gboolean all_capabilities_false_set = false; gboolean force_slave_address_true_set = false; gboolean force_slave_address_false_set = false; gboolean debug_parse = false; gboolean parse_only = false; gboolean f1_flag = false; gboolean f2_flag = false; gboolean f3_flag = false; gboolean f4_flag = false; gboolean f5_flag = false; gboolean f6_flag = false; GOptionEntry public_option_entries[] = { // long_name short flags option-type gpointer description arg description // monitor selection options // output control #ifdef DISABLED_LIBDDCUTIL_ONLY {"nousb", '\0', 0, G_OPTION_ARG_NONE, &nousb_flag, "Do not detect USB devices", NULL}, #endif // Options dialog #ifdef DISABLE_VIEW_OPTION {"view", '\0', 0, G_OPTION_ARG_STRING, &view_work, "Initial view", "Summary|Capabilities|Features"}, #endif {"require-control-key", '\0', 0, G_OPTION_ARG_NONE, &control_key_required, "Control key must be pressed to move slider", NULL}, {"nc-values-source", '\0', 0, G_OPTION_ARG_STRING, &nc_values_source_work, "Initial NC values source", "MMCS|Capabilities|Both"}, {"feature-set", '\0', 0, G_OPTION_ARG_STRING, &feature_set_work, "Feature set selection", "MMCS|Capabilities|Manufacturer|Color|Scan"}, // {"use-latest-nc-values", // '\0', 0, G_OPTION_ARG_NONE, &use_latest_nc_values_true_set, "Use NC values from the latest MCCS version", NULL}, {"custom-feature-set", '\0', 0, G_OPTION_ARG_STRING, &custom_feature_set_work, "User feature set definition", "comma separated list of feature codes"}, {"show-unsupported", '\0', 0, G_OPTION_ARG_NONE, &show_unsupported_features, "Show unsupported features", NULL}, {"only-capabilities", '\0', 0, G_OPTION_ARG_NONE, &only_capabilities_true_set, "Include only values in capabilities", NULL}, // {"not-only-capabilities", // '\0', 0, G_OPTION_ARG_NONE, &only_capabilities_false_set, "Do not exclude values only in MCCS", NULL}, {"all-capabilities", '\0', 0, G_OPTION_ARG_NONE, &all_capabilities_true_set, "Include all values in capabilities", NULL}, // {"not-all-capabilities", // '\0', 0, G_OPTION_ARG_NONE, &all_capabilities_false_set, "Negate include all values in capabilities", NULL}, // Display selection {"model", '\0', 0, G_OPTION_ARG_STRING, &parsed_cmd->model, "Model of default display", NULL}, // {"bus", '\0', 0, G_OPTION_ARG_INT, &parsed_cmd->busno, "I2C bus number", "integer"}, // Tuning {"stats", 's', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, stats_arg_func, "Show performance statistics", "TRIES|ERRORS|CALLS|ALL"}, {"ddc", '\0', 0, G_OPTION_ARG_NONE, &ddc_flag, "Report DDC protocol and data errors", NULL}, {"force-slave-address", '\0', 0, G_OPTION_ARG_NONE, &force_slave_address_true_set, "Deprecated", NULL}, {"disable-force-slave-address", '\0', 0, G_OPTION_ARG_NONE, &force_slave_address_false_set, "Deprecated", NULL}, // Pre-GUI queries {"styles", '\0', 0, G_OPTION_ARG_NONE, &show_styles_flag, "List known styles", NULL}, {"show-style", '\0', 0, G_OPTION_ARG_NONE, &show_active_style_flag, "Show active style", NULL}, {"version", 'V', 0, G_OPTION_ARG_NONE, &version_flag, "Show version information", NULL}, { NULL } }; GOptionEntry development_options[] = { // debugging {"excp", '\0', 0, G_OPTION_ARG_NONE, &report_freed_excp_flag, "Report freed exceptions", NULL}, {"trace", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &trace_classes, "Trace a group", "trace group name" }, // {"trace", '\0', 0, G_OPTION_ARG_STRING, &tracework, "Trace a group", "comma separated list" }, {"trcfunc", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &trace_functions, "Trace a function", "function name" }, {"trcfile", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &trace_filenames, "Trace a file", "file name" }, {"timestamp",'\0', 0, G_OPTION_ARG_NONE, ×tamp_trace_flag, "Prepend trace msgs with elapsed time", NULL}, {"ts", '\0', 0, G_OPTION_ARG_NONE, ×tamp_trace_flag, "Prepend trace msgs with elapsed time", NULL}, {"thread-id",'\0', 0, G_OPTION_ARG_NONE, &thread_id_trace_flag, "Prepend trace msgs with thread id", NULL}, {"tid", '\0', 0, G_OPTION_ARG_NONE, &thread_id_trace_flag, "Prepend trace msgs with thread id", NULL}, // Debug parser {"debug-parse", '\0', 0, G_OPTION_ARG_NONE, &debug_parse, "Show parse result", NULL}, {"parse-only", '\0', 0, G_OPTION_ARG_NONE, &parse_only, "Exit after parsing", NULL}, // Other {"hidpi", '\0', 0, G_OPTION_ARG_NONE, &hidpi_flag, "Test hidpi code", NULL}, // Undocumented library flag options {"f1", '\0', 0, G_OPTION_ARG_NONE, &f1_flag, "Special flag 1", NULL}, {"f2", '\0', 0, G_OPTION_ARG_NONE, &f2_flag, "Special flag 2", NULL}, {"f3", '\0', 0, G_OPTION_ARG_NONE, &f3_flag, "Special flag 3", NULL}, {"f4", '\0', 0, G_OPTION_ARG_NONE, &f4_flag, "Special flag 4", NULL}, {"f5", '\0', 0, G_OPTION_ARG_NONE, &f5_flag, "Special flag 5", NULL}, {"f6", '\0', 0, G_OPTION_ARG_NONE, &f6_flag, "Special flag 6", NULL}, { NULL } }; #ifdef UNUSED GOptionEntry final_options[] = { // collect to verify that does not exist {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &cmd_and_args, NULL, NULL}, // if there were arguments: // {G_OPTION_REMAINING, // '\0', 0, G_OPTION_ARG_STRING_ARRAY, &cmd_and_args, "ARGUMENTS description", "command [arguments...]"}, { NULL } }; #endif GOptionGroup * development_option_group = g_option_group_new("development", "Development related options", "Not for general use", GINT_TO_POINTER(3), NULL); g_option_group_add_entries(development_option_group, development_options); g_option_group_set_parse_hooks(development_option_group, pre_parse_hook, post_parse_hook); GError* error = NULL; GOptionContext* context = g_option_context_new("- graphical interface to ddcutil"); g_option_context_add_main_entries(context, public_option_entries, NULL); g_option_context_add_group(context, development_option_group); g_option_context_set_help_enabled(context, true); // bool ok = false; char * help_description = g_strjoin("\n", tracing_multiple_call_option_help, trcfunc_multiple_call_option_help, trcfile_multiple_call_option_help, stats_multiple_call_option_help, NULL ); // on --help, comes at end after option detail // g_option_context_set_description(context, help_description); free(help_description); char ** mangleable_argv = argv; if (debug) { printf("(%s) Before g_option_context_parse_strv(), mangleable_argv:\n", __func__); ntsa_show(mangleable_argv); } bool ok = g_option_context_parse_strv(context, &mangleable_argv, &error); if (!ok) { if (error) { fprintf(stderr, "ddcui option parsing failed: %s\n", error->message); g_error_free(error); } else { fprintf(stderr, "ddcui option parsing failed.\n"); } } if (debug) { printf("(%s) Freeing mangleable_argv=%p:\n", __func__, (void*)mangleable_argv); ntsa_show(mangleable_argv); } ntsa_free(mangleable_argv, true); if (force_slave_address_true_set) fprintf(stderr, "Deprecated option ignored: --force_slave_address\n"); if (force_slave_address_false_set) fprintf(stderr, "Deprecated option ignored: --disable-force_slave_address\n"); #define SET_CMDFLAG(_bit, _flag) \ do { \ if (_flag) \ parsed_cmd->flags |= _bit; \ } while(0) parsed_cmd->stats_types = stats_work; SET_CMDFLAG(CMD_FLAG_DDCDATA, ddc_flag); SET_CMDFLAG(CMD_FLAG_TIMESTAMP_TRACE, timestamp_trace_flag); SET_CMDFLAG(CMD_FLAG_THREAD_ID_TRACE, thread_id_trace_flag); SET_CMDFLAG(CMD_FLAG_REPORT_FREED_EXCP, report_freed_excp_flag); // SET_CMDFLAG(CMD_FLAG_NOUSB, nousb_flag); SET_CMDFLAG(CMD_FLAG_SHOW_STYLES, show_styles_flag); SET_CMDFLAG(CMD_FLAG_SHOW_ACTIVE_STYLE, show_active_style_flag); SET_CMDFLAG(CMD_FLAG_UI_REQUIRE_CONTROL_KEY, control_key_required); SET_CMDFLAG(CMD_FLAG_SHOW_UNSUPPORTED, show_unsupported_features); // SET_CMDFLAG(CMD_FLAG_LATEST_NC_VALUE_NAMES, use_latest_nc_values_true_set); // n. not handling case where default is true SET_CMDFLAG(CMD_FLAG_F1, f1_flag); SET_CMDFLAG(CMD_FLAG_F2, f2_flag); SET_CMDFLAG(CMD_FLAG_F3, f3_flag); SET_CMDFLAG(CMD_FLAG_F4, f4_flag); SET_CMDFLAG(CMD_FLAG_F5, f5_flag); SET_CMDFLAG(CMD_FLAG_F6, f6_flag); SET_CMDFLAG(CMD_FLAG_HIDPI, hidpi_flag); #undef SET_CMDFLAG if (all_capabilities_true_set) parsed_cmd->include_all_capabilities_features = TRIVAL_TRUE; #ifdef TRIVAL else if (all_capabilities_false_set) parsed_cmd->include_all_capabilities_features = TRIVAL_FALSE; #endif else parsed_cmd->include_all_capabilities_features = TRIVAL_UNSET; if (only_capabilities_true_set) parsed_cmd->include_only_capabilities_features = TRIVAL_TRUE; #ifdef TRIVAL else if (only_capabilities_false_set) parsed_cmd->include_only_capabilities_features = TRIVAL_FALSE; #endif else parsed_cmd->include_only_capabilities_features = TRIVAL_UNSET; if (custom_feature_set_work) { char ** error_msgs; // Null_Terminated_String_Array error_msgs; DDCA_Feature_List flist = parse_custom_feature_list(custom_feature_set_work, &error_msgs); parsed_cmd->custom_feature_list = flist; if (ddca_feature_list_count(flist) == 0) { ok = false; if (error_msgs) { fprintf(stderr, "Errors in --custom-feature-set:\n"); for (int ndx = 0; error_msgs[ndx]; ndx++) { fprintf(stderr, " %s\n", error_msgs[ndx]); } ntsa_free(error_msgs, true); } else { fprintf(stderr, "Empty --custom-feature-set\n"); } } } // #ifdef MULTIPLE_TRACE if (trace_classes) { DDCA_Trace_Group traceClasses = 0x00; int ndx = 0; for (;trace_classes[ndx] != NULL; ndx++) { char * token = g_ascii_strup(trace_classes[ndx], -1); // n g_ascii_strup returns newly allocated string // DBGMSG("token=|%s|", token); if (strcmp(token, "ALL") == 0 || strcmp(token, "*") == 0) { traceClasses = DDCA_TRC_ALL; // 0xff } else { // DBGMSG("token: |%s|", token); DDCA_Trace_Group tg = ddca_trace_group_name_to_value(token); // DBGMSG("tg=0x%02x", tg); if (tg) { traceClasses |= tg; } else { fprintf(stderr, "Invalid trace group: %s\n", token); ok = false; } } free(token); } // DBGMSG("traceClasses = 0x%02x", traceClasses); parsed_cmd->traced_groups = traceClasses; } // #endif if (trace_functions) { parsed_cmd->traced_functions = trace_functions; } if (trace_filenames) { parsed_cmd->traced_files = trace_filenames; } #ifdef DISABLE_VIEW_OPTION if (view_work) { // printf("view_work = %p -> |%s|\n", view_work, view_work); Parsed_View pv = find_view_table_value(view_work); if (pv == VIEW_UNSET) { fprintf(stderr, "Unrecognized: %s\n", view_work); ok = false; } else{ parsed_cmd->view = pv; } } #endif if (nc_values_source_work) { // printf("nc_values_source_work = %p -> |%s|\n", nc_values_source_work, nc_values_source_work); Parsed_NC_Values_Source src = find_nc_values_source_table_value(nc_values_source_work); if (src == NC_VALUES_SOURCE_UNSET) { fprintf(stderr, "Unrecognized: %s\n", nc_values_source_work); ok = false; } else{ parsed_cmd->nc_values_source = src; } } // Does this macro make code cleaner or more obscure? #define VALUE_LOOKUP(_ENUM, _NAME, _NOT_FOUND_VALUE) \ if (_NAME ## _work) { \ _ENUM src = find_ ## _NAME ##_table_value(_NAME ## _work); \ if (src == _NOT_FOUND_VALUE) { \ fprintf(stderr, "Unrecognized: %s\n", _NAME ## _work); \ ok = false; \ } \ else{ \ parsed_cmd->_NAME = src; \ } \ } VALUE_LOOKUP(Parsed_Feature_Set, feature_set, FS_UNSET); #undef VALUE_LOOKUP if (parsed_cmd->feature_set != FS_UNSET && ddca_feature_list_count(parsed_cmd->custom_feature_list) > 0) { fprintf(stderr, "--feature-set and --custom-feature-set are mutually exclusive\n"); ok = false; } if (all_capabilities_true_set && only_capabilities_true_set) { if (parsed_cmd->feature_set != FS_CAPABILITIES) { fprintf(stderr, "--all-capabilities and --only-capabilities are mutually exclusive" " except when --feature-set = CAPABILITIES\n"); ok = false; } } if (cmd_and_args && cmd_and_args[0]) { // int rest_ct = 0; // unused // don't pull debug into the if clause, need rest_ct to be set // if (cmd_and_args) { // for (; cmd_and_args[rest_ct] != NULL; rest_ct++) { // DBGMSF(debug, "cmd_and_args[%d]: %s", rest_ct, cmd_and_args[rest_ct]); // } // } char * s = g_strjoinv(" ",cmd_and_args); fprintf(stderr, "Unrecognized: %s\n", s); free(s); ok = false; } if (version_flag) { printf("ddcui %s\n\n", DDCUI_VSTRING); printf("Built using libddcutil version %d.%d.%d, Qt version %s\n", DDCUTIL_VMAJOR, DDCUTIL_VMINOR, DDCUTIL_VMICRO, QT_VERSION_STR); printf("Executing using libddcutil %s, Qt %s\n\n", ddca_ddcutil_extended_version_string(), qVersion()); puts("Copyright (C) 2018-2022 Sanford Rockowitz"); puts("License GPLv2: GNU GPL version 2 or later "); puts("This is free software: you are free to change and redistribute it."); puts("There is NO WARRANTY, to the extent permitted by law."); exit(0); } // DBGMSF(debug, "Calling g_option_context_free(), context=%p...", context); g_option_context_free(context); if (debug || debug_parse) { dbgrpt_parsed_ddcui_cmd(parsed_cmd); } if (!ok || parse_only) { free_parsed_ddcui_cmd(parsed_cmd); parsed_cmd = NULL; } if (debug) printf("(%s) ddcui parser returning: %p\n", __func__, (void*) parsed_cmd); return parsed_cmd; } ddcui-0.3.0/src/cmdline/ddcui_cmd_parser.h000066400000000000000000000005101427175135000204450ustar00rootroot00000000000000/* \file cmd_parser.h */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUI_CMD_PARSER_H_ #define DDCUI_CMD_PARSER_H_ #include "ddcui_parsed_cmd.h" Parsed_Ddcui_Cmd * parse_ddcui_command(int argc, char * argv[]); #endif /* DDCUI_CMD_PARSER_H_ */ ddcui-0.3.0/src/cmdline/ddcui_cmd_parser_aux.c000066400000000000000000000057041427175135000213270ustar00rootroot00000000000000/** \file cmd_parser_aux.c * * Functions and strings that are independent of the parser package used. */ // Copyright (C) 2014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // #include /** \cond */ #include #include #include #include #include // #include "util/string_util.h" /** \endcond */ // #include "base/parms.h" #include "ddcui_cmd_parser_aux.h" bool all_digits(char * val, int ct) { // bool debug = false; // DBGMSF(debug, "ct-%d, val -> |%.*s|", ct, ct, val ); bool ok = true; int ndx; for (ndx = 0; ndx < ct; ndx++) { if ( !isdigit(*(val+ndx)) ) { ok = false; break; } } // DBGMSF(debug, "Returning: %d ", ok ); return ok; } bool parse_int_arg(char * val, int * pIval) { int ct = sscanf(val, "%d", pIval); return (ct == 1); } char * tracing_comma_separated_option_help = "Tracing:\n" " The argument to --trace is a comma separated list of trace classes, surrounded by \n" " quotation marks if necessary." " e.g. --trace all, --trace \"I2C,ADL\"\n" " Valid trace classes are: BASE, SLEEP, I2C, ADL, DDC, DDCIO, VCP, TOP, ENV, API, UDF, ALL.\n" " Trace class names are not case sensitive.\n" " (Some trace classes are more useful than others.)\n" // "\n" ; char * tracing_multiple_call_option_help = "Trace by trace class:\n" " The argument to --trace is a trace class. Use the --trace option multiple\n" " times to activate multiple trace classes, e.g. \"--trace i2c --trace ddc\"\n" " Valid trace classes are: BASE, I2C, ADL, DDC, DDCIO, VCP, TOP, ENV, API, UDF, ALL.\n" " Trace class names are not case sensitive.\n" " (Some trace classes are more useful than others.)\n" // "\n" ; char * trcfunc_multiple_call_option_help = "Trace by function name:\n" " The argument to --trcfunc is a function name. Use the --trcfunc option multiple\n" " times to trace multiple functions, e.g. \"--trcfunc func1 --trcfunc func2\"\n" ; char * trcfile_multiple_call_option_help = "Trace by file name:\n" " The argument to --trcfile is a simple file name. Use the --trcfile option multiple\n" " times to trace multiple functions, e.g. \"--trcfile ddc_edid.c --trcfile ddc_output.c\"\n" ; char * stats_multiple_call_option_help = "Stats:\n" " The argument to --stats is a statistics class. Use the --stats option multiple\n" " times to activate multiple statistics classes, e.g. \"--stats calls --stats errors\"\n" " Valid statistics classes are: TRY, TRIES, ERRS, ERRORS, CALLS, ALL.\n" " Statistics class names are not case sensitive and can abbreviated to 3 characters.\n" " If no argument is specified, or ALL is specified, then all statistics classes are\n" " output.\n" ; ddcui-0.3.0/src/cmdline/ddcui_cmd_parser_aux.h000066400000000000000000000013051427175135000213250ustar00rootroot00000000000000/** \file cmd_parser_aux.h * * Functions and strings that are independent of the parser package used. */ // Copyright (C) 20014-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUI_CMD_PARSER_AUX_H_ #define DDCUI_CMD_PARSER_AUX_H_ #include #include "ddcui_parsed_cmd.h" bool all_digits(char * val, int ct); bool parse_int_arg(char * val, int * pIval); extern char * tracing_comma_separated_option_help; extern char * tracing_multiple_call_option_help; extern char * trcfunc_multiple_call_option_help; extern char * trcfile_multiple_call_option_help; extern char * stats_multiple_call_option_help; #endif /* DDCUI_CMD_PARSER_AUX_H_ */ ddcui-0.3.0/src/cmdline/ddcui_parsed_cmd.c000066400000000000000000000157471427175135000204440ustar00rootroot00000000000000/** @file ddcui_parsed_cmd.c - parsed ddcui command line */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later /** \cond */ #include #include #include #include #include #include /** \endcond */ #include "ddcutil_c_api.h" #include "c_util/data_structures.h" #include "ddcui_parsed_cmd.h" // // all uses of this local function are safe, // static inline char * sbool(int b) { // return (b) ? "true" : "false"; // } const char * trival_repr(Optional_True_False value) { char * result = NULL; switch(value) { case TRIVAL_TRUE: result = "true"; break; case TRIVAL_FALSE: result = "false"; break; case TRIVAL_UNSET: result = "not set"; break; } return result; } /** Allocates new Parsed_Cmd data structure, sets default values. * * @return initialized #Parsed_Cmd */ Parsed_Ddcui_Cmd * new_parsed_ddcui_cmd() { Parsed_Ddcui_Cmd * parsed_cmd = (Parsed_Ddcui_Cmd*) calloc(1, sizeof(Parsed_Ddcui_Cmd)); memcpy(parsed_cmd->marker, PARSED_CMD_MARKER, 4); // n. all flags are false, byte values 0, integers 0, pointers NULL because of calloc // parsed_cmd->flags |= CMD_FLAG_ENABLE_UDF; // parsed_cmd->sleep_multiplier = 1.0; parsed_cmd->busno = -1; return parsed_cmd; } // VNT tables for enums Value_Name_Title view_table[] = { VNT(VIEW_UNSET, NULL), VNT(VIEW_SUMMARY, "Summary"), VNT(VIEW_CAPABILITIES, "Capabilities"), VNT(VIEW_FEATURES, "Features"), VN_END }; Value_Name_Title feature_set_table[] = { VNT(FS_UNSET, NULL), VNT(FS_MCCS, "MCCS"), VNT(FS_CAPABILITIES, "Capabilities"), VNT(FS_MANUFACTURER, "Manufacturer"), VNT(FS_COLOR, "Color"), VNT(FS_SCAN, "Scan"), VNT(FS_CUSTOM, "Custom"), VNT_END }; Value_Name_Title nc_values_source_table[] = { VNT( NC_VALUES_SOURCE_UNSET, NULL), VNT( NC_VALUES_SOURCE_MCCS, "MCCS"), VNT( NC_VALUES_SOURCE_CAPABILITIES, "Capabilities"), VNT( NC_VALUES_SOURCE_BOTH, "Both"), VNT_END }; // VNT access functions const char * get_feature_set_table_symbol(Parsed_Feature_Set value) { return vnt_name(feature_set_table, value); } const char * get_view_table_symbol(Parsed_View pv) { return vnt_name(view_table, pv); } Parsed_View find_view_table_value(const char * value) { return vnt_find_id( view_table, value, true, // search by description, not symbolic name true, // ignore case VIEW_UNSET); } const char * get_nc_values_source_table_symbol(Parsed_NC_Values_Source src) { return vnt_name(nc_values_source_table, src); } Parsed_NC_Values_Source find_nc_values_source_table_value(const char * value) { return vnt_find_id( nc_values_source_table, value, true, // search by description, not symbolic name true, // ignore case NC_VALUES_SOURCE_UNSET); } Parsed_Feature_Set find_feature_set_table_value(char * value) { return vnt_find_id( feature_set_table, value, true, // search by description, not symbolic name true, // ignore case FS_UNSET); } /** Debugging report of #Parsed_Cmd struct * * \param parsed_cmd instance to report */ void dbgrpt_parsed_ddcui_cmd(Parsed_Ddcui_Cmd * parsed_cmd) { printf("(%s) Parsed_Cmd at %p\n", __func__, (void *) parsed_cmd); if (parsed_cmd) { printf(" stats: 0x%08x\n", parsed_cmd->stats_types); printf(" traced_groups 0x%08x\n", parsed_cmd->traced_groups); if (parsed_cmd->traced_functions) { char * joined = g_strjoinv(", ", parsed_cmd->traced_functions); printf(" traced_functions: %s\n", joined); free(joined); } else printf(" traced_functions: none\n" ); if (parsed_cmd->traced_files) { char * joined = g_strjoinv(", ", parsed_cmd->traced_files); printf(" traced_files: %s\n", joined); free(joined); } else printf(" traced_files: none\n" ); // char buf[20]; // snprintf(buf,20, "%d,%d,%d", parsed_cmd->max_tries[0], parsed_cmd->max_tries[1], parsed_cmd->max_tries[2] ); // printf(" max_retries: %s\n", buf); printf(" report_freed_exceptions: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_REPORT_FREED_EXCP) ); // printf(" nousb %s\n", sbool(parsed_cmd->flags & CMD_FLAG_NOUSB) ); printf(" display ddc errors: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_DDCDATA) ); printf(" timestamp prefix: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_TIMESTAMP_TRACE) ); printf(" thread_id prefix: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_THREAD_ID_TRACE) ); printf(" show styles: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_SHOW_STYLES) ); printf(" show active style: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_SHOW_ACTIVE_STYLE) ); printf(" require control key: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_UI_REQUIRE_CONTROL_KEY) ); printf(" initial view: %s\n", get_view_table_symbol(parsed_cmd->view) ); printf(" default feature set: %s\n", get_feature_set_table_symbol(parsed_cmd->feature_set)); printf(" custom feature set: %s\n", ddca_feature_list_string(parsed_cmd->custom_feature_list, "",",")); printf(" NC values source: %s\n", get_nc_values_source_table_symbol(parsed_cmd->nc_values_source)); // printf(" Force Latest NC Value Names:%s\n", sbool(parsed_cmd->flags & CMD_FLAG_LATEST_NC_VALUE_NAMES) ); printf(" include all capabilities features: %s\n", trival_repr(parsed_cmd->include_all_capabilities_features)); printf(" include_only capabilities features: %s\n", trival_repr(parsed_cmd->include_only_capabilities_features)); printf(" initial model: %s\n", parsed_cmd->model); printf(" initial bus number: %d\n", parsed_cmd->busno); printf(" hidpi: %s\n", sbool(parsed_cmd->flags & CMD_FLAG_HIDPI)); } } /** Frees a #Parsed_Cmd instance * * @param parsed_cmd instance to free */ void free_parsed_ddcui_cmd(Parsed_Ddcui_Cmd * parsed_cmd) { bool debug = false; if (debug) printf("(%s) Starting. parsed_cmd=%p\n", __func__, (void*) parsed_cmd); if (parsed_cmd) { assert ( memcmp(parsed_cmd->marker,PARSED_CMD_MARKER,4) == 0); parsed_cmd->marker[3] = 'x'; g_strfreev(parsed_cmd->traced_files); // used instead of ntsa_free() g_strfreev(parsed_cmd->traced_functions); free(parsed_cmd); } if (debug) { printf("(%s) Done\n", __func__); fflush(stdout); } } ddcui-0.3.0/src/cmdline/ddcui_parsed_cmd.h000066400000000000000000000067451427175135000204470ustar00rootroot00000000000000/** @file ddcui_parsed_cmd.h - parsed ddcui command line */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUI_PARSED_CMD_H_ #define DDCUI_PARSED_CMD_H_ #include // Used to distinguish between an explicit option set vs no option set, // in which case the default value will be used typedef enum { TRIVAL_UNSET, TRIVAL_FALSE, TRIVAL_TRUE } Optional_True_False; // what's the term used for kernel configuration? const char * trival_repr(Optional_True_False value); // View Menu typedef enum { VIEW_UNSET = 0, // unset or invalid VIEW_SUMMARY, VIEW_CAPABILITIES, VIEW_FEATURES } Parsed_View; // Options Menu typedef enum { FS_UNSET = 0, FS_MCCS, FS_CAPABILITIES, FS_MANUFACTURER, FS_COLOR, FS_SCAN, FS_CUSTOM } Parsed_Feature_Set; typedef enum { NC_VALUES_SOURCE_UNSET = 0, NC_VALUES_SOURCE_MCCS, NC_VALUES_SOURCE_CAPABILITIES, NC_VALUES_SOURCE_BOTH } Parsed_NC_Values_Source; // General typedef enum { CMD_FLAG_NONE = 0x000000, CMD_FLAG_DDCDATA = 0x000001, CMD_FLAG_TIMESTAMP_TRACE = 0x000002, // prepend trace and debug msgs with elapsed time CMD_FLAG_REPORT_FREED_EXCP = 0x000004, CMD_FLAG_THREAD_ID_TRACE = 0x000008, // CMD_FLAG_NOUSB = 0x000020, CMD_FLAG_SHOW_STYLES = 0x000040, CMD_FLAG_UI_REQUIRE_CONTROL_KEY = 0x000080, CMD_FLAG_SHOW_UNSUPPORTED = 0x000100, CMD_FLAG_SHOW_ACTIVE_STYLE = 0x000200, // CMD_FLAG_LATEST_NC_VALUE_NAMES = 0x000400, CMD_FLAG_F1 = 0x01000000, CMD_FLAG_F2 = 0x02000000, CMD_FLAG_F3 = 0x04000000, CMD_FLAG_F4 = 0x08000000, CMD_FLAG_F5 = 0x10000000, CMD_FLAG_F6 = 0x20000000, CMD_FLAG_HIDPI = 0x40000000, } Parsed_Cmd_Flags; #define PARSED_CMD_MARKER "PCMD" typedef struct { char marker[4]; // PARSED_CMD_MARKER DDCA_Stats_Type stats_types; DDCA_Trace_Group traced_groups; char ** traced_files; char ** traced_functions; // int max_tries[3]; Parsed_Cmd_Flags flags; Parsed_View view; Parsed_Feature_Set feature_set; Parsed_NC_Values_Source nc_values_source; Optional_True_False include_all_capabilities_features; Optional_True_False include_only_capabilities_features; Optional_True_False enable_sleep_suppression; char * model; int busno; DDCA_Feature_List custom_feature_list; } Parsed_Ddcui_Cmd; // VNT Table Lookup const char * get_feature_set_table_symbol(Parsed_Feature_Set feature_set_id); const char * get_view_table_symbol(Parsed_View view_id); Parsed_View find_view_table_value(const char * value); const char * get_nc_values_source_table_symbol(Parsed_NC_Values_Source src_id); Parsed_NC_Values_Source find_nc_values_source_table_value(const char * value); Parsed_Feature_Set find_feature_set_table_value( char * value); // Lifecycle and debug Parsed_Ddcui_Cmd * new_parsed_ddcui_cmd(); void free_parsed_ddcui_cmd(Parsed_Ddcui_Cmd * parsed_cmd); void dbgrpt_parsed_ddcui_cmd(Parsed_Ddcui_Cmd * parsed_cmd); // debugging function #endif /* DDCUI_PARSED_CMD_H_ */ ddcui-0.3.0/src/core_widgets/000077500000000000000000000000001427175135000160545ustar00rootroot00000000000000ddcui-0.3.0/src/core_widgets/hex_number_validator.cpp000066400000000000000000000022531427175135000227630ustar00rootroot00000000000000/** hex_number_validator.cpp */ // Copyright (C) 2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "hex_number_validator.h" #include "../base/core.h" HexNumberValidator::HexNumberValidator(QObject * parent) : QValidator(parent) // , _fieldNumber(fieldNumber) { _cls = metaObject()->className(); } static inline bool isHexDigit(QChar ch) { bool result = ( (ch >= 'a' && ch <='f') || (ch >= 'A' && ch <= 'F' ) || (ch >= '0' && ch <= '9') ); return result; } HexNumberValidator::State HexNumberValidator::validate(QString &input, int &pos) const { bool debug = false; QValidator::State result = QValidator::Acceptable; for (int ndx = 0; ndx < input.length(); ndx++) { const QChar& ch = input.at(ndx); if (!isHexDigit(ch)) { result = QValidator::Invalid; break; } } if (result == QValidator::Acceptable) { int sz = input.size(); if (sz == 0) result = QValidator::Intermediate; else if (sz > 2) result = QValidator::Invalid; } TRACECF(debug, "String: %s, returning %d", QS2S(input), result); return result; } ddcui-0.3.0/src/core_widgets/hex_number_validator.h000066400000000000000000000007551427175135000224350ustar00rootroot00000000000000/** hex_number_validator.h */ // Copyright (C) 2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef HEX_NUMBER_VALIDATOR_H_ #define HEX_NUMBER_VALIDATOR_H_ #include class HexNumberValidator : public QValidator { Q_OBJECT public: HexNumberValidator(QObject * parent = nullptr); QValidator::State validate(QString &input, int &pos) const; private: const char * _cls; }; #endif /* HEX_NUMBER_VALIDATOR_H_ */ ddcui-0.3.0/src/core_widgets/hline_widget.cpp000066400000000000000000000010441427175135000212210ustar00rootroot00000000000000// hline_widget.cpp // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "hline_widget.h" HLineWidget::HLineWidget(QWidget * parent ) : QFrame(parent) { _cls = metaObject()->className(); setFrameStyle(QFrame::HLine); QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); setSizePolicy(sizePolicy); setMaximumHeight(1); setLineWidth(1); // setFrameWidth(1); } HLineWidget::~HLineWidget() { // TODO Auto-generated destructor stub } ddcui-0.3.0/src/core_widgets/hline_widget.h000066400000000000000000000007211427175135000206670ustar00rootroot00000000000000// hline_widget.h - creates a horizonal line // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef HLINE_WIDGET_H_ #define HLINE_WIDGET_H_ #include #include "../base/core.h" class HLineWidget : public QFrame { Q_OBJECT public: explicit HLineWidget(QWidget * parent = nullptr); virtual ~HLineWidget(); private: const char * _cls; }; #endif /* HLINE_WIDGET_H_ */ ddcui-0.3.0/src/core_widgets/number_entry_widget.cpp000066400000000000000000000151631427175135000226420ustar00rootroot00000000000000// number_entry_widget.cpp // Copyright (C) 2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include "base/core.h" #include "base/ddcui_parms.h" #include "base/widget_debug.h" #include "hex_number_validator.h" #include "number_entry_widget.h" void NumberEntryWidget::layoutWidget( uint8_t bytect, QFont font, int style, // not currently used QSize size) { setMaxLength( 2*bytect); setFont(font); // setFrameStyle(style); ??? setFixedSize(size); setAlignment(Qt::AlignRight); if (debugLayout) setStyleSheet("background-color:orange;"); } // initializes _widgetState to StateOldValid NumberEntryWidget::NumberEntryWidget( uint8_t bytect, QFont font, int style, // not currently used QSize size, QWidget *parent) : QLineEdit(nullptr) , _bytect(bytect) , _curval(0) , _widgetState(NumberEntryWidget::StateOldValid) { _cls = metaObject()->className(); // TODO: use an enum instead of bytect // ***TEMP*** assert(bytect == 1 || bytect == 2); // could allow 4, just more cases in switch stmts etc. // *** Constrain what character strings are accepted /* All three methods work. All provide that at most 2 hexadecimal characters * are entered, so the value shown is always valid. true for 1, 2, what about 3? * All three have the same deviciency. */ #ifdef METHOD1 // Method 1, a regular expression validator // Unlike the custom validator, does not even allow invalid chars to be entered // same problem as methods 1 and 2, only backspace works QString rxs = QString("^[A-Fa-f0-9]{%1}$").arg(2*bytect,1,10,QLatin1Char('0')) ; QRegExp rx = QRegExp(rxs); setValidator( new QRegExpValidator(rx)); #endif // #ifdef METHOND2 // Method 2: use Input Mask // also allows only valid hex characters to be entered. // but hard to change data, have to click on right then basckspace to be able to enter text QString hexByteInputMask("HH"); setInputMask(hexByteInputMask); // #endif #ifdef METHOD3 // similar problem, delete key never works, must position cursor to right of a digit, then // can use backspace // now it's blocking all input??? // Method 3: Custom validator QValidator* v = new HexNumberValidator(); setValidator(new HexNumberValidator()); #endif layoutWidget(bytect,font,style,size); connect(this, &NumberEntryWidget::textEdited, this, &NumberEntryWidget::onTextEdited); } uint16_t NumberEntryWidget::getExistingValue() { bool debug = false; TRACECF(debug, "widget = %s, returning: x%04x", QS2S(this->objectName()), _curval); return _curval; } uint16_t NumberEntryWidget::getNewValue() { bool debug = false; TRACECF(debug, "widget = %s, returning: x%04x", QS2S(this->objectName()), _valueEntered); return _valueEntered; } // sets the current value // changes state to StateOldValue void NumberEntryWidget::setValue(uint16_t newval) { bool debug = false; TRACECF(debug, "widget = %s, newval = x%04x", QS2S(this->objectName()), newval); // Set text value in widget int textLength = 2 * _bytect; QString sval = QString("%1").arg(newval,textLength,16,QLatin1Char('0')); setText(sval); _curval = newval; _widgetState = NumberEntryWidget::StateOldValid; } NumberEntryWidget::States NumberEntryWidget::getState() { return _widgetState; } // if widgestate = OldState, do nothing // o.w. sets the displayed value to curval // set state to OldState void NumberEntryWidget::reset() { bool debug = false; TRACECF(debug, "Starting. widget = %s, _curState = %d", QS2S(this->objectName()),_widgetState); if (_widgetState != NumberEntryWidget::StateOldValid ) { int textLength = 2*_bytect; _valueEntered = 0; setText( QString("%1").arg(_curval,textLength,16,QLatin1Char('0')) ); _widgetState = NumberEntryWidget::StateOldValid; } TRACECF(debug, "Done. _curState = %d", _widgetState); } #ifdef OLD void NumberEntryWidget::onTextEdited(const QString &text) { TRACECF(true, "Starting. text=%s", text.toLatin1().data()); bool ok = false; if (text.length() > 0) { int newval = text.toInt(&ok, 16); if (ok) { // should already have been checked _curval = newval; TRACECF(true, "About to emit, _curval = newval = 0x%02x", newval); emit NumberEntryWidget::valueChanged8( newval & 0xff); } else { TRACEC("Not a number: %s", QS2S(text)); } } TRACEC("emitting NumberEntryWidet::isValidValue, _fieldNumber = %d, ok=%s", _fieldNumber, sbool(ok) ); emit NumberEntryWidget::isValidValue(_fieldNumber, ok); } #endif // sets newval to the int value of the tex text // if value shown has length 0, sets state to Invalid // if value shown (valueEntered) == oldval, sets state to OldValid // o.w. sets state to NewValid void NumberEntryWidget::onTextEdited(const QString &text) { bool debug = false; TRACECF(debug, "Starting. text=%s", text.toLatin1().data()); NumberEntryWidget::States newState = NumberEntryWidget::StateInvalid; bool ok = false; _valueEntered = 0; if (text.length() > 0) { _valueEntered = text.toInt(&ok, 16); if (ok) { // should already have been checked if (_curval == _valueEntered) newState = NumberEntryWidget::StateOldValid; else newState = NumberEntryWidget::StateNewValid; } else { TRACEC("Not a number: %s", QS2S(text)); } } if (newState != _widgetState && newState != NumberEntryWidget::StateInvalid) { TRACECF(debug, "About to emit stateChanged, newstate = %d", newState); emit NumberEntryWidget::stateChanged(this, newState); } _widgetState = newState; // if (newState == NumberEntryWidget::StateNewValid ) // _curval = newval; TRACECF(debug, "Done. setting _widgetState to %d", _widgetState); } // For exploring behavior void NumberEntryWidget::focusInEvent(QFocusEvent * event) { // TRACE("Executing, _curState = %d", _widgetState); } void NumberEntryWidget::focusOutEvent(QFocusEvent * event) { // TRACE("Executing, _curState = %d", _widgetState); } void NumberEntryWidget::mousePressEvent(QMouseEvent * event) { // TRACE("Executing, _curState = %d", _widgetState); } void NumberEntryWidget::mouseReleaseEvent(QMouseEvent * event) { // TRACE("Executing, _curState = %d", _widgetState); } ddcui-0.3.0/src/core_widgets/number_entry_widget.h000066400000000000000000000034011427175135000222770ustar00rootroot00000000000000// number_entry_widget.h // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef NUMBER_ENTRY_WIDGET_H_ #define NUMBER_ENTRY_WIDGET_H_ #include #include #include class NumberEntryWidget : public QLineEdit { Q_OBJECT // Q_ENUMS(States) public: enum States {StateOldValid, StateInvalid, StateNewValid}; NumberEntryWidget( uint8_t bytect, QFont font, int style, QSize size, QWidget *parent = nullptr); void setValue(uint16_t byteval); NumberEntryWidget::States getState(); uint16_t getExistingValue(); uint16_t getNewValue(); void reset(); protected: void focusInEvent(QFocusEvent * event) override; void focusOutEvent(QFocusEvent * event) override; void mousePressEvent(QMouseEvent * event) override; void mouseReleaseEvent(QMouseEvent * event) override; private slots: void onTextEdited(const QString &text); signals: // void valueChanged8(uint8_t value); // void valueChanged16(uint16_t value); // void valueChanged32(uint32_t value); // void isValidValue(uint8_t fieldNumber, bool tf); // void setCurrentField(int fieldNumber); void stateChanged(NumberEntryWidget * widget, NumberEntryWidget::States newState); private: void layoutWidget( uint8_t bytect, QFont font, int style, // not currently used QSize size); const char * _cls; uint8_t _bytect; uint16_t _curval; uint16_t _valueEntered = 0; // valid value displayed but not yet accepted NumberEntryWidget::States _widgetState; }; #endif /* NUMBER_ENTRY_WIDGET_H_ */ ddcui-0.3.0/src/core_widgets/spin_slider.cpp000066400000000000000000000150171427175135000210770ustar00rootroot00000000000000/** @file slider_spinner.cpp * Combines a slider with a spinbox */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "base/core.h" #include "base/global_state.h" #include "base/widget_debug.h" #include "core_widgets/spin_slider.h" void SpinSlider::createWidgets() { // _slider = new EnhancedSlider(Qt::Horizontal); _slider = new QSlider(Qt::Horizontal); _slider->setFocusPolicy(Qt::StrongFocus); _slider->setTickPosition(QSlider::TicksBelow); // alt TicksBothSides _slider->setSingleStep(1); // _slider->setFixedSize(200,18); // was 18 , 14 stuffs slider to bottom _slider->setMinimumSize(200,10); _slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); // Trying to force a bit of space above and below slider // _slider->setContentsMargins(3,0,1,0); // no effect // increases height of rows in at least style adwaita // _slider->setStyleSheet("padding-top:2px;padding-bottom:2px"); if (debugLayout) _slider->setStyleSheet("background-color:pink;"); _spinBox = new QSpinBox(); // _spinBox = new EnhancedSpinBox(); _spinBox->setSingleStep(1); // _spinBox->setFixedSize(100,18); // extra large for 2 byte values, possible horizontal up/down buttons _spinBox->setMinimumSize(100,18); // becomes 52,32 - how? _spinBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); _spinBox->setFont(FeatureValueNumberEntryFont); _spinBox->setAlignment(Qt::AlignRight); if (debugLayout) _spinBox->setStyleSheet("background-color:green;"); } QLayout* SpinSlider::layoutWidget() { QLayout* layout = new QHBoxLayout(); layout->setSpacing(5); // layout->addWidget(sliderContainer); layout->addWidget(_slider); // crops off tick marks at bottom of slider: // how to shrink the slider size? // layout->setAlignment(_curSlider, Qt::AlignVCenter); layout->addWidget(_spinBox); layout->setContentsMargins(1,0,1,0); // was 0,0,0,0 setLayout(layout); return layout; } SpinSlider::SpinSlider(QWidget * parent) : QWidget(parent) , _cls(metaObject()->className()) { bool debug = false; createWidgets(); layoutWidget(); if (debug) REPORT_BASIC_WIDGET_DIMENSIONS(_spinBox); connect(_slider, SIGNAL(sliderReleased()), this, SLOT( onSliderReleased())); connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT( onSpinBoxValueChanged(int))); // Tie the slider and spinbox together connect(_slider, SIGNAL(valueChanged(int)), _spinBox, SLOT( setValue(int))); connect(_spinBox, SIGNAL(valueChanged(int)), _slider, SLOT( setValue(int))); _spinBoxTimer = new QTimer(); _spinBoxTimer->setSingleShot(true); _spinBoxTimer->setInterval(1000); connect(_spinBoxTimer, SIGNAL(timeout()), this, SLOT(onSpinBoxTimedOut())); } SpinSlider::~SpinSlider() { delete _spinBoxTimer; } void SpinSlider::setFeatureCode(uint8_t featureCode) { _featureCode = featureCode; _isFeatureCodeSet = true; } void SpinSlider::setRange(int minval, int maxval) { _slider->setTickInterval((maxval-minval)/10); _slider->setRange(minval, maxval); _spinBox->setRange(minval, maxval); } // Called by the containing class to update the widget void SpinSlider::setShSl(uint16_t newval) { bool debug = false; // TRACEMCF(debug, "newval = 0x%04x", newval); // ValueBaseWidget::setCurrentShSl(newval); // _guiChange = false; uint8_t sh = newval >> 8; uint8_t sl = newval & 0xff; int curval = sh << 8 | sl; TRACEMCF(debug, "Starting. feature=0x%02x, newval=%d, curval=%d", _featureCode , curval); TRACEMF(debug, "Calling _spinBoxTime->stop(), _spinBox->setValue()"); // in case the timer is running, don't trigger _spinBoxTimer->stop(); _spinBox->setValue(curval); // _slider->setValue(curval); // _guiChange = true; TRACECF(debug, "Done"); } // Used by the containing class to query the widget's value after having been // notified that that widget value has changed. uint16_t SpinSlider::getShSl() { int curval = _spinBox->value(); uint8_t sh = (curval >> 8) & 0xff; uint8_t sl = curval & 0xff; uint16_t result = (sh << 8) | sl; return result; } void SpinSlider::onSliderReleased() { bool debug = false; debug = debug || debugValueWidgetSignals; // TRACECF(debug, "feature=0x%02x", _featureCode); int newval = _spinBox->value(); uint8_t new_sh = (newval >> 8) & 0xff; uint8_t new_sl = newval & 0xff; // if (debugValueWidgetSignals) // printf("(%s::%s) sh=0x%02x, sl=0x%02x \n", _cls, __func__, new_sh, new_sl); fflush(stdout); // if (_guiChange) { TRACECF(debug, "emitting featureValueChanged(), _feature_code=0x%02x, new_sh=0x%02x, new_sl=0x%02x", _featureCode, new_sh, new_sl); emit featureValueChanged(_featureCode, new_sh, new_sl); // } } void SpinSlider::onSpinBoxValueChanged(int value) { bool debug = false; debug = debug || debugValueWidgetSignals; // TRACECF(debug, "feature=0x%02x, value=%d, _guiChange=%d=%s", // _featureCode, value, _guiChange, SBOOL(_guiChange)); TRACECF(debug, "feature=0x%02x, value=%d", _featureCode, value); int newval = _spinBox->value(); // Do not immediately signal valueChanged() - this generates too many API calls. // instead only emit valueChanged() after multiple changes occur or the final change is made // uint8_t new_sh = (newval >> 8) & 0xff; // uint8_t new_sl = newval & 0xff; // if (debugValueWidgetSignals) // printf("(%s::%s) sh=0x%02x, sl=0x%02x \n", _cls, __func__, new_sh, new_sl); fflush(stdout); _latestSpinBoxValue = newval & 0xffff; // if (_guiChange || true) { // *** TEMP *** TRACECF(debug, "Starting spinbox timer"); _spinBoxTimer->start(); // } // else { // TRACECF(debug,"Not starting spinbox timer"); // } } void SpinSlider::onSpinBoxTimedOut() { bool debug = false; debug = debug || debugValueWidgetSignals; uint8_t new_sh = (_latestSpinBoxValue >> 8) & 0xff; uint8_t new_sl = _latestSpinBoxValue & 0xff; TRACECF(debug, "feature 0x%02x, _latestSpinBoxValue=%d, new_sh=0x%02x, new_sl=0x%02x, " "emitting featureValueChanged()", _featureCode, _latestSpinBoxValue, new_sh, new_sl); emit featureValueChanged(_featureCode, new_sh, new_sl); } ddcui-0.3.0/src/core_widgets/spin_slider.h000066400000000000000000000026771427175135000205540ustar00rootroot00000000000000/** @file spin_slider.h * Combines a slider with a spinbox */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef SPIN_SLIDER_H_ #define SPIN_SLIDER_H_ #include #include #include #include #include "nongui/feature_value.h" class SpinSlider : public QWidget { Q_OBJECT // *** Constructors and Methods public: // allocation and initialization SpinSlider(QWidget * parent = nullptr); ~SpinSlider(); void setRange(int minval, int maxval); void setFeatureCode(uint8_t featureCode); // For containing class void setShSl(uint16_t newval) ; uint16_t getShSl(); signals: void featureValueChanged(uint8_t feature_code, uint8_t sh, uint8_t sl); private slots: // for signaling valueChanged(): void onSliderReleased(); void onSpinBoxValueChanged(int value); void onSpinBoxTimedOut(); private: void createWidgets(); QLayout* layoutWidget(); // *** Variables *** private: const char * _cls; QSlider * _slider; QSpinBox * _spinBox; QTimer * _spinBoxTimer; uint8_t _featureCode; bool _isFeatureCodeSet = true; // for assert() uint16_t _latestSpinBoxValue; // enum _valueChangeInitiator { ChangedByModel, ChangedByGUI }; }; #endif /* SPIN_SLIDER_H_ */ ddcui-0.3.0/src/feature_scrollarea/000077500000000000000000000000001427175135000172405ustar00rootroot00000000000000ddcui-0.3.0/src/feature_scrollarea/feature_widget.cpp000066400000000000000000000231041427175135000227420ustar00rootroot00000000000000/*** @file feature_widget.cpp Custom widget for displaying/editing a VCP feature */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_scrollarea/feature_widget.h" #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" #include "nongui/feature_base_model.h" #include "feature_value_widgets/value_nc_widget.h" #include "feature_value_widgets/value_stacked_widget.h" #include "feature_value_widgets/value_std_widget.h" static bool showBasicDims = false || debugFeatureDimensions; static bool showFullDims = false; static bool showResizeEvents = false; // static QFont monoValueFont; // used for all but the value field static QLabel * createFeatureWidgetField( const char * objectName, const int fixedWidth, const char * dummyValue) { QLabel * field = new QLabel(); field->setObjectName(QString::fromUtf8(objectName)); field->setFixedWidth(fixedWidth); // field->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); field->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding); // field->setFont(monoValueFont); field->setFont(FeatureValueTextFont); field->setText(QString::fromUtf8(dummyValue)); field->setFrameStyle( QFrame::Sunken | QFrame::Panel ); // alt: QFrame::Plain | QFrame::Box; field->setContentsMargins(1,1,1,1); // This is what kills the panel, when set to 0 field->setLineWidth(1); return field; } void FeatureWidget::setupFeatureWidget() { bool debug = false; TRACECF(debug, "Starting"); // setFrameStyle(QFrame::Box); // something to make it visible for development _featureCodeField = createFeatureWidgetField("featureCode", 30, "x00"); _featureNameField = createFeatureWidgetField("featureName", 200, "dummy feature name"); // _featureNameField->setFont(nonMonoValueFont); _featureNameField->setFont(FeatureValueTextFont); _featureRwField = createFeatureWidgetField("featureRW", 25, "XX"); // RW/RO/WO _featureTypeField = createFeatureWidgetField("featureType", 25, "YY"); // MCCS type TRACECF(debug, "creating ValueStackedWidget, feature code dummy"); _valueWidget = new ValueStackedWidget(); _valueWidget->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); _layout = new QHBoxLayout(); _layout->addWidget(_featureCodeField); _layout->addWidget(_featureNameField); _layout->addWidget(_featureRwField); _layout->addWidget(_featureTypeField); _layout->addWidget(_valueWidget, /*stretch*/ 10, Qt::AlignVCenter); // eliminating addStretch() eliminates gap between Type and Value fields, but allows // feature name field to expand // _layout->addStretch(2); // _layout->insertStretch(-1, 2); _layout->setSpacing(0); // spacing between widgets inside the (horizontal) layout _layout->setContentsMargins(0,0,0,0); // eliminating vlayout restores horizontal spacing between all fields. why? #ifdef UNNEEDED QVBoxLayout * vlayout = new QVBoxLayout(); vlayout->addLayout(_layout); vlayout->setSpacing(0); vlayout->setContentsMargins(0,0,0,0); setLayout(vlayout); #endif setLayout(_layout); setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); setMaximumHeight(FeatureRowHeight); // with this alone. rows ware narrow, even // setMinimumHeight(FeatureRowHeight); // with this alone, rows too large, uneven static bool dimensionReportShown = false; if (debugLayout || showFullDims) { this->setStyleSheet("background-color:orange;"); if (!dimensionReportShown) { TRACEMC("FeatureWidget dimensions:"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(_featureCodeField); REPORT_BASIC_WIDGET_DIMENSIONS(_valueWidget); basicDimsShown = true; } TRACECF(debug, "Done"); } void FeatureWidget::setupConnections() { QObject::connect(_valueWidget, &ValueStackedWidget::stackedFeatureValueChanged, this, &FeatureWidget::onInternalValueChanged); } int FeatureWidget::nextId = 0; FeatureWidget::FeatureWidget(QWidget *parent) : QWidget(parent) , _cls(strdup(metaObject()->className())) , _id(++nextId) { setupFeatureWidget(); setupConnections(); } FeatureWidget::FeatureWidget(FeatureValue& fv, QWidget *parent) : QWidget(parent) , _cls(strdup(metaObject()->className())) , _id(++nextId) { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d, FeatureValue::id=%d, featureCode = 0x%02x", _id, fv._id, fv.featureCode()); setupFeatureWidget(); setupConnections(); setFeatureValue(fv); } FeatureWidget::~FeatureWidget() { free((void*) _cls); } // Used only to set feature value immediately after constructor called void FeatureWidget::setFeatureValue(FeatureValue &fv) { bool debug = false; TRACECF(debug, "feature code = 0x%02x, ddcrc=%s", fv.featureCode(), ddca_rc_name(fv.ddcrc())); _feature_code = fv.featureCode(); _feature_flags = fv.flags(); setObjectName(QString::asprintf("FeatureWidget-0x%02x", _feature_code)); _featureCodeField->setText(QString::asprintf("x%02x", _feature_code) ); _featureNameField->setText(QString::fromUtf8( fv.finfo()->feature_name)); QString s_rw; if (_feature_flags & DDCA_RW) s_rw = QString("RW"); else if (_feature_flags & DDCA_RO) s_rw = QString("RO"); else { assert(_feature_flags & DDCA_WO); s_rw = QString("WO"); } _featureRwField->setText(s_rw); if (_feature_flags & DDCA_CONT) _featureTypeField->setText(QString("C")); else if (_feature_flags & DDCA_NC) _featureTypeField->setText(QString("NC")); else { assert(_feature_flags & DDCA_TABLE); _featureTypeField->setText(QString("T")); } DDCA_Status ddcrc =fv.ddcrc(); TRACECF(debug, "feature=0x%02x, getvcp status=%s", _feature_code , ddca_rc_name(ddcrc) ); // TRACEF(debug, "Before calling valueWidget->setFeatureValue()"); _valueWidget->setFeatureValue(fv); TRACECF(debug, "After calling valueWidget->setFeatureValue()"); _layout->addWidget(_valueWidget); } #ifdef UNUSED void FeatureWidget::setInstanceControlKeyRequired(bool onoff) { _valueWidget->setInstanceControlKeyRequired(onoff); } #endif void FeatureWidget::setCurrentValue(uint16_t newval) { _valueWidget->setCurrentValue(newval); } #ifdef UNNEEDED QSize FeatureWidget::sizeHint() const { int w = 700; int h = 10; // printf("(%s::%s) Returning (%d,%d)\n", _cls, __func__, w, h); fflush(stdout); return QSize(w,h); // ??? } #endif #ifdef NO void FeatureWidget::paintEvent(QPaintEvent *event) { printf("%s::%s)\n", _cls, __func__); fflush(stdout); QFrame::paintEvent(event); _featureCodeField->update(); // causes separate X window - NO NOT THIS } #endif void FeatureWidget::dbgrpt() const { std::string on1 = objectName().toStdString(); const char * objname = on1.c_str(); // printf("%-20s code: 0x%02x, flags: 0x%04x, mh: 0x%02x, ml: 0x%02x, sh: 0x%02x, sl 0x%02x\n", // objname, _feature_code, _feature_flags, _mh, _ml, _sh, _sl); TRACEC("%-20s feature code: 0x%02x, flags: 0x%04x", objname, _feature_code, _feature_flags); } void FeatureWidget::onInternalValueChanged(uint8_t featureCode, uint8_t sh, uint8_t sl) { bool debug = false; debug = debug || debugSignals; // TRACEMCF(debug, "feature_code = 0x%02x, sh=0x%02x, sl=0x%02x", featureCode, sh, sl); assert(featureCode == _feature_code); bool writeOnlyFeature = _feature_flags & DDCA_WO; TRACEMCF(debug, "-> Calling emit valueChanged, feature_code=0x%02x, writeOnlyFeature=%s, sh=0x%02x, sl=0x%02x", featureCode, SBOOL(writeOnlyFeature), sh, sl); emit valueChanged(featureCode, writeOnlyFeature, sh, sl); } #ifdef UNUSED // SimpleFeatureValueObserver void FeatureWidget::simpleFeatureValueChanged(SimpleFeatureValue fv) { printf("(%s::%s) feature_code = 0x%02x, sh=0x%02x, sl=0x%02x\n", _cls, __func__, fv.featureCode, fv.hiByte, fv.loByte); fflush(stdout); } #endif #ifdef PASS_NC_PARMS2 bool FeatureWidget::hasSlTable() { bool result = _valueWidget->hasSlTable(); // TRACE("Returning: %s", SBOOL(result)); return result; } #endif #ifdef PASS_NC_PARMS void FeatureWidget::setNcValuesSource(NcValuesSource newsrc, bool useLatestNcValueNames) { bool debug = false; TRACEMF(debug, "newsrc = %d-%s", newsrc, ncValuesSourceName(newsrc)); _valueWidget->setNcValuesSource(newsrc, useLatestNcValueNames); TRACEMF(debug, "Done"); } #endif void FeatureWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool resizeEventsShown = false; if (showResizeEvents && !resizeEventsShown) { show = true; // resizeEventsShown = true; } #ifdef ALT int oldWidth = oldSz.width(); int oldHeight = oldSz.height(); int newWidth = newSz.width(); int newHeight = newSz.width(); if (oldHeight != newHeight || oldWidth != newWidth) { show = true; } #endif if (show) { TRACEC("old size = %d, %d, new size = %d, %d", oldSz.width(), oldSz.height(), newSz.width(), newSz.height()); } // evt->ignore(); evt->accept(); } ddcui-0.3.0/src/feature_scrollarea/feature_widget.h000066400000000000000000000045521427175135000224150ustar00rootroot00000000000000/** @ feature_widget.h Custom widget for displaying/editing a VCP feature */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURE_WIDGET_H #define FEATURE_WIDGET_H #include "base/core.h" #include "nongui/feature_value.h" #include "feature_value_widgets/value_stacked_widget.h" class QLabel; class QHBoxLayout; class FeatureBaseModel; class QResizeEvent; class FeatureWidget : public QWidget // , public SimpleFeatureValueObserver { Q_OBJECT public: explicit FeatureWidget(QWidget *parent = nullptr); FeatureWidget(FeatureValue& fv, QWidget *parent=nullptr); ~FeatureWidget(); // QSize sizeHint() const override; void setFeatureValue(FeatureValue &fv); void setCurrentValue(uint16_t newval); #ifdef PASS_NC_PARMS2 bool hasSlTable(); #endif #ifdef PASS_NC_PARMS void setNcValuesSource(NcValuesSource newsrc, bool useLatestNcValueNames); #endif void dbgrpt() const; // void simpleFeatureValueChanged(SimpleFeatureValue fv) override; // SimpleFeatureValueObserver public slots: void onInternalValueChanged(uint8_t featureCode, uint8_t sh, uint8_t sl); #ifdef UNUSED void setInstanceControlKeyRequired(bool onoff); #endif signals: void valueChanged(uint8_t featureCode, bool writeOnlyFeature, uint8_t sh, uint8_t sl); protected: void resizeEvent(QResizeEvent * event) override; // *** Member variables *** public: uint8_t _feature_code; QString* _feature_name; protected: static int nextId; private: void setupFeatureWidget(); // called by constructor void setupConnections(); // called by constructor const char * _cls; // className int _id; // uint8_t _feature_code; // QString* _feature_name; DDCA_Version_Feature_Flags _feature_flags; // uint16_t QHBoxLayout* _layout; QLabel* _featureCodeField; QLabel* _featureNameField; QLabel* _featureRwField; QLabel* _featureTypeField; ValueStackedWidget* _valueWidget; #ifdef ALT QStackedWidget * _featureValueStackedWidget; QWidget* _featureValueStandardWidget; QWidget* _featureValueContWidget; QWidget* _featureValueNcWidget; #endif }; #endif // FEATURE_WIDGET_H ddcui-0.3.0/src/feature_scrollarea/feature_widget_header.cpp000066400000000000000000000077111427175135000242600ustar00rootroot00000000000000/** feature_widget_header.cpp * * Row at top of central widget showing column titles */ // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" #include "feature_widget_header.h" static bool showDimensionReport = false; static bool showResizeEvents = false; static QLabel* stdLabelSetup(QLabel * l) { // l->setFrameStyle(QFrame::NoFrame | QFrame::Plain); l->setFrameStyle(QFrame::Box | QFrame::Plain); l->setLineWidth(0); // eliminates bar between Code|Name Type|Value - why? // l->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed); // l->setHorizontalPolicy(QSizePolicy::Fixed); // l->setVerticalPolicy(QSizePolicy::Fixed); l->setFont(FeatureValueHeaderFont); l->setContentsMargins(0,0,0,0); l->setIndent(0); return l; } void FeatureWidgetHeader::layoutWidget() { QLabel * _codeLabel = stdLabelSetup( new QLabel("Code") ); QLabel * _nameLabel = stdLabelSetup( new QLabel("Name") ); QLabel * _rwLabel = stdLabelSetup( new QLabel("RW") ); QLabel * _typeLabel = stdLabelSetup( new QLabel("Type") ); QLabel * _valueLabel = stdLabelSetup( new QLabel("Value") ); // width _codeLabel->setMinimumWidth(30); _nameLabel->setFixedWidth(200); // was 200-2 _rwLabel->setFixedWidth(25-1); _typeLabel->setFixedWidth(25+1+4); _valueLabel->setMinimumWidth(200-4+2); _nameLabel->setContentsMargins(2,0,0,0); // so there's space before "Name" _valueLabel->setContentsMargins(4,0,0,0); // so there's space before "Value" _valueLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); QHBoxLayout * layout = new QHBoxLayout(); layout->addWidget(_codeLabel); layout->addWidget(_nameLabel); layout->addWidget(_rwLabel); layout->addWidget(_typeLabel); layout->addWidget(_valueLabel); layout->setSpacing(0); // From QLayout doc; // margins around the layout // By default, QLayout uses the values provided by the style. // On most platforms, the margin is 11 pixels in all directions. layout->setContentsMargins(0,0,0,0); setLayout(layout); setFrameStyle(QFrame::NoFrame | QFrame::Plain); // setContentsMargins(1,1,1,1); // 0,0,0,0 doesn't move "Code" left setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); setFixedHeight( FeatureHeaderHeight ); setLineWidth(1); if (debugLayout || showDimensionReport) { setStyleSheet("background-color:beige;"); static bool dimensionsReported = false; if (showDimensionReport && !dimensionsReported) { printf("\nFeatureWidgetHeader dimensions:\n"); REPORT_BASIC_WIDGET_DIMENSIONS(this); reportLabelDimensions(_codeLabel, _cls, __func__, "_codeLabel dimensions"); reportLabelDimensions(_nameLabel, _cls, __func__, "_nameLabel dimensions"); reportLabelDimensions(_rwLabel, _cls, __func__, "_rwLabel dimensions"); reportLabelDimensions(_typeLabel, _cls, __func__, "_typeLabel dimensions"); reportLabelDimensions(_valueLabel, _cls, __func__, "_valueLabel dimensions"); reportFrameDimensions(this, _cls, __func__, "FeatureWidgetHeader dimensions"); // dimensionsReported = true; } } } FeatureWidgetHeader::FeatureWidgetHeader(QWidget * parent) : QFrame(parent) { _cls = metaObject()->className(); layoutWidget(); } FeatureWidgetHeader::~FeatureWidgetHeader() { // TODO Auto-generated destructor stub } void FeatureWidgetHeader::resizeEvent(QResizeEvent * evt) { if (showResizeEvents) { QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); TRACEC("old size = %d, %d new size = %d, %d", oldSz.width(), oldSz.height(), newSz.width(), newSz.height()); } evt->ignore(); } ddcui-0.3.0/src/feature_scrollarea/feature_widget_header.h000066400000000000000000000012221427175135000237140ustar00rootroot00000000000000// feature_widget_header.h // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURE_WIDGET_HEADER_H_ #define FEATURE_WIDGET_HEADER_H_ #include #include #include "../base/core.h" class FeatureWidgetHeader : public QFrame { Q_OBJECT public: explicit FeatureWidgetHeader(QWidget * parent = nullptr); virtual ~FeatureWidgetHeader(); protected: void resizeEvent(QResizeEvent * event) override; private: void layoutWidget(); private: // member variables const char * _cls; }; #endif /* FEATURE_WIDGET_HEADER_H_ */ ddcui-0.3.0/src/feature_scrollarea/features_scrollarea.cpp000066400000000000000000000033431427175135000237740ustar00rootroot00000000000000// features_scrollarea.cpp // Copyright (C) 2019-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "base/core.h" #include "base/widget_debug.h" #include "feature_scrollarea/features_scrollarea_contents.h" #include "feature_scrollarea/features_scrollarea.h" static bool showWidgetDimensions = false; static bool traceResizeEvents = false; void FeaturesScrollArea::layoutWidget() { if (debugLayout) { setStyleSheet("background-color:maroon;"); static bool widgetDimensionsReported = false; if (showWidgetDimensions && !widgetDimensionsReported) { reportWidgetDimensions(this, _cls, __func__, "FeatureScrollAreaContents dimensions"); widgetDimensionsReported = true; } } } FeaturesScrollArea::FeaturesScrollArea(QWidget *parent) : QScrollArea(parent) { _cls = metaObject()->className(); // TRACE("Executing"); layoutWidget(); } FeaturesScrollArea::~FeaturesScrollArea() { } void FeaturesScrollArea::resizeEvent(QResizeEvent * evt) { QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); QWidget * contents = widget(); QSize contentsSize = contents->size(); // TODO: get calculate the actual scrollbar width QSize newSize = QSize(contentsSize.width()-24, contentsSize.height()); contents->resize(newSize); evt->ignore(); if (traceResizeEvents) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); TRACEC("Current contents size %d,%d", contentsSize.width(), contentsSize.height()); TRACEC("Resizing contents to %d,%d", newSize.width(), newSize.height()); } } ddcui-0.3.0/src/feature_scrollarea/features_scrollarea.h000066400000000000000000000013041427175135000234340ustar00rootroot00000000000000// features_scrollarea.h // Copyright (C) 2019-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURES_SCROLLAREA_H_ #define FEATURES_SCROLLAREA_H_ #include #include class FeaturesScrollArea : public QScrollArea { Q_OBJECT public: FeaturesScrollArea(QWidget *parent = Q_NULLPTR); virtual ~FeaturesScrollArea(); // void addPageChangeObserver(PageChangeObserver * observer); // void notifyPageChangeObservers(int pageno); protected: void resizeEvent(QResizeEvent * event) override; private: void layoutWidget(); const char * _cls; }; #endif /* FEATURES_SCROLLAREA_H_ */ ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_contents.cpp000066400000000000000000000111231427175135000257040ustar00rootroot00000000000000// features_scroll_area_contents.cpp - Contains rows of FeatureWidgets // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_scrollarea/features_scrollarea_contents.h" #include #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_stacked_widget.h" #include "feature_scrollarea/feature_widget.h" static bool debugWidget = false; static bool showWidgetDimensions = false; static bool traceResizeEvents = false; FeaturesScrollAreaContents::FeaturesScrollAreaContents(QWidget * parent) : QWidget(parent) { bool debug = false; _cls = metaObject()->className(); // _pageChangeObservers = new QVector; // setLayout(new QVBoxLayout()); // check that signal being fired // connect(this, SIGNAL(showCentralWidgetByWidget(QWidget *)), // qApp, SLOT(aboutQt())); // layout()->setContentsMargins(0,0,0,0); // no layout defined // doesn't expand the contents area //setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); TRACECF(debug, "Executing"); if (debugLayout) { setStyleSheet("background-color:aqua;"); static bool widgetDimensionsReported = false; if (showWidgetDimensions && !widgetDimensionsReported) { reportWidgetDimensions(this, _cls, __func__, "FeatureScrollAreaContents dimensions"); } } } FeaturesScrollAreaContents::~FeaturesScrollAreaContents() { bool debug = false; TRACECF(debug, "Executing"); // TODO IMPLEMENT!!! } void FeaturesScrollAreaContents::setModel(FeatureBaseModel * baseModel) { _baseModel = baseModel; } void FeaturesScrollAreaContents::setContainingScrollArea(QScrollArea * scrollArea) { _containingScrollArea = scrollArea; // no, just adds horizontal scrollbar on bottom // scrollArea->setWidgetResizable(true); } #ifdef UNUSED void FeaturesScrollAreaContents::setInstanceControlKeyRequired(bool onoff) { } #endif #ifdef UNUSED void FeaturesScrollAreaContents::featureAdded(FeatureValue fv) { if (debugMain) { printf("(%s::%s)\n", _cls, __func__); fflush(stdout); // fv.report(); } FeatureWidget * newTableEntry = new FeatureWidget(); newTableEntry->setFeatureValue(fv); if (debugMain) newTableEntry->dbgrpt(); layout()->addWidget(newTableEntry); _widgets[fv._feature_code] = newTableEntry; } #endif #ifdef OLD // Unused! void FeaturesScrollAreaContents::featureUpdated(char feature_code) { if (debugMain) printf("(%s::%s)\n", _cls, __func__); fflush(stdout); // get the current value for the feature FeatureValue * fv = _baseModel->modelVcpValueFind(feature_code); // find the entry in _widgets _widgets[feature_code]; // set value in the widget } #endif void FeaturesScrollAreaContents::startInitialLoad(void) { bool debugFunc = debugWidget; debugFunc = false; TRACECF(debugFunc, "Executing"); assert(_containingScrollArea != nullptr); // _containingScrollArea->hide(); } void FeaturesScrollAreaContents::endInitialLoad() { bool debugFunc = debugWidget; debugFunc = false; TRACECF(debugFunc, "Executing"); assert(_containingScrollArea); emit showCentralWidgetByWidget(_containingScrollArea); } #ifdef PAGE_CHANGE_OBSERVER void FeaturesScrollAreaContents::addPageChangeObserver(PageChangeObserver * observer) { _pageChangeObservers->append(observer); } void FeaturesScrollAreaContents::notifyPageChangeObservers(int pageno) { int ct = _pageChangeObservers->count(); TRACECF(debugSignals, "Starting ct=%d", ct); for (int ndx = 0; ndx < ct; ndx++) { TRACECF(debugSignals, "Notifying observer"); PageChangeObserver* observer = _pageChangeObservers->at(ndx); observer->pageChangedByWidget(_containingScrollArea); } } #endif void FeaturesScrollAreaContents::resize(int w, int h) { TRACEC("width = %d, height = %s", w, h); QWidget::resize(w, h); } void FeaturesScrollAreaContents::resize(QSize sz) { TRACEC("width = %d, height = %s", sz.width(), sz.height()); QWidget::resize(sz); } void FeaturesScrollAreaContents::resizeEvent(QResizeEvent * evt) { if (traceResizeEvents) { QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); TRACEC("old size = %d, %d new size = %d, %d", oldSz.width(), oldSz.height(), newSz.width(), newSz.height()); } evt->ignore(); } int FeaturesScrollAreaContents::maxRowHeight() { return 0; } ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_contents.h000066400000000000000000000033661427175135000253630ustar00rootroot00000000000000// features_scrollarea_contents.h - Contains rows of FeatureWidgets // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURES_SCROLLAREA_CONTENTS_H_ #define FEATURES_SCROLLAREA_CONTENTS_H_ #include #include #include "nongui/feature_value.h" #include "nongui/feature_base_model.h" #include "feature_scrollarea/feature_widget.h" // #include "page_change_observer.h" class QScrollArea; class QVBoxLayout; class FeaturesScrollAreaContents : public QWidget { Q_OBJECT public: FeaturesScrollAreaContents(QWidget *parent = Q_NULLPTR); virtual ~FeaturesScrollAreaContents(); void setModel(FeatureBaseModel * baseModel); void setContainingScrollArea(QScrollArea * scrollArea); // void addPageChangeObserver(PageChangeObserver * observer); // void notifyPageChangeObservers(int pageno); void resize(int w, int h); void resize(QSize sz); int maxRowHeight(); #ifdef UNUSED void setInstanceControlKeyRequired(bool onoff); #endif protected: void resizeEvent(QResizeEvent * event) override; signals: void showCentralWidgetByWidget(QWidget * widget); // void showCentralWidgetByPageno(int pageno); public slots: #ifdef MAYBE_UNUSED void featureAdded(FeatureValue fv); #endif #ifdef OLD void featureUpdated(char feature_code); #endif void startInitialLoad(void); void endInitialLoad(); private: // member variables const char * _cls; // className FeatureBaseModel * _baseModel = NULL; QScrollArea * _containingScrollArea = NULL; #ifdef PAGE_CHANGE_OBSERVER QVector * _pageChangeObservers; #endif }; #endif /* FEATURES_SCROLLAREA_CONTENTS_H_ */ ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_ui.cpp000066400000000000000000000027721427175135000244760ustar00rootroot00000000000000/** @file features_scrollarea_ui.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include "base/monitor.h" #include "features_scrollarea_view.h" #include "features_scrollarea_ui.h" #include "nongui/msgbox_queue.h" // Sets curMonitor->featuresScrollAreaView // on endInitialLoad, creates new scrollarea, scrollareacontents, does not set them in Monitor void initFeaturesScrollAreaView( Monitor * curMonitor, FeatureBaseModel* baseModel, QStackedWidget * stackedWidget, MsgBoxQueue * msgboxQueue ) { // printf("(%s) stackedWidget=%p\n", __func__, stackedWidget); fflush(stdout); // printf("(%s) Starting. msgboxQueue=%p\n", __func__, msgboxQueue); fflush(stdout); FeaturesScrollAreaView * featuresView = new FeaturesScrollAreaView( curMonitor, baseModel, stackedWidget, msgboxQueue); curMonitor->_featuresScrollAreaView = featuresView; QObject::connect(baseModel, &FeatureBaseModel::signalEndInitialLoad, featuresView, &FeaturesScrollAreaView::onEndInitialLoad); // QObject::connect(featuresView, &FeaturesScrollAreaView::signalVcpRequest, // curMonitor, &Monitor::putVcpRequest); } ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_ui.h000066400000000000000000000010501427175135000241270ustar00rootroot00000000000000/* features_scrollarea_ui.h */ // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURES_SCROLLAREA_UI_H_ #define FEATURES_SCROLLAREA_UI_H_ // class FeaturesScrollAreaUI { // }; class Monitor; class FeatureBaseModel; class QStackedWidget; class MsgBoxQueue; void initFeaturesScrollAreaView( Monitor* curMonitor, FeatureBaseModel* baseModel, QStackedWidget* stackedWidget, MsgBoxQueue * msgboxQueue); #endif /* FEATURES_SCROLLAREA_UI_H_ */ ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_view.cpp000066400000000000000000000424131427175135000250270ustar00rootroot00000000000000/* features_scrollarea_view.cpp */ // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_scrollarea/features_scrollarea_view.h" #include #include #include #include #include #include #include #include #include #include "../base/nc_values_state.h" #include "base/core.h" #include "base/global_state.h" #include "base/monitor.h" #include "base/widget_debug.h" #include "nongui/msgbox_queue.h" #include "feature_scrollarea/feature_widget.h" #include "feature_scrollarea/feature_widget_header.h" #include "feature_scrollarea/features_scrollarea_contents.h" #include "feature_scrollarea/features_scrollarea.h" static bool showDimensionReport = false; int FeaturesScrollAreaView::nextId = 0; FeaturesScrollAreaView::FeaturesScrollAreaView( Monitor * monitor, FeatureBaseModel * model, QStackedWidget * centralStackedWidget, MsgBoxQueue * msgboxQueue, QObject * parent) : QObject(parent) , _cls(metaObject()->className()) , _id(++nextId) , _monitor(monitor) , _baseModel(model) , _centralStackedWidget(centralStackedWidget) , _msgboxQueue(msgboxQueue) // , _curNcValuesSource(OtherOptionsState::DefaultNcValuesSource) // , _curNcValuesSource(NcValuesSourceUnset) , _controlKeyRequired(false) { bool debug = false; // _id = ++nextId; TRACEMCF(debug, "Executing. this->_id=%d, _msgboxQueue=%p", _id, _msgboxQueue); } #ifdef UNUSED void FeaturesScrollAreaView::setInstanceControlKeyRequired(bool onoff) { bool debugFunc = true; QRegularExpression re("^FeatureWidget-"); // QList * children = _scrollAreaContents->children(); // n. find same FeatureValue children using _centralWidget->findChildren(..) QList children2 = _scrollAreaContents->findChildren(re); TRACEMCF(debugFunc, "Found %d children of scrollAreaContents using regular expression", children2.count()); for (int ndx = 0; ndx < children2.count(); ndx++) { // printf(" ndx=%d\n", ndx); FeatureWidget * child = children2.at(ndx); child->setInstanceControlKeyRequired(onoff); } } #endif void FeaturesScrollAreaView::freeContents(void) { bool debug = false; QWidget * scrollWrapWidget = NULL; for (int ndx = 0; ndx < _centralStackedWidget->count(); ndx++) { QWidget* curobj = _centralStackedWidget->widget(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); TRACEMCF(debug, " widget[%d]: %s, type:%s", ndx, name.toLatin1().data(), clsName); if (name.compare("scrollwrap") == 0 ) { TRACEMCF(debug, "scrollwrap found, index=%d", ndx); scrollWrapWidget = curobj; break; } } if (scrollWrapWidget) { TRACEMCF(debug, "Removing locally found scrollWrapWidget %p", scrollWrapWidget); _centralStackedWidget->removeWidget(scrollWrapWidget); } } // triggered by signal FeatureBaseModel::signalEndInitialLoad void FeaturesScrollAreaView::onEndInitialLoad(void) { bool debugFunc = false; TRACEMCF(debugFunc, "Starting, this->_id=%d, Monitor=%s", _id, _monitor->_displayInfo->model_name); freeContents(); // scrollWrap contains a FeatureWidgetHeader and a scrollable // collection of FeatureWidget rows QFrame * scrollWrap = new QFrame(); scrollWrap->setObjectName("scrollwrap"); QVBoxLayout * wrapLayout = new QVBoxLayout; wrapLayout->setSpacing(0); wrapLayout->addWidget(new FeatureWidgetHeader()); FeaturesScrollArea * scrollArea = new FeaturesScrollArea(); scrollArea->setWidgetResizable(true); FeaturesScrollAreaContents * scrollAreaContents = new FeaturesScrollAreaContents(); scrollAreaContents->setObjectName("scrollAreaContents local to onEndInitialLoad"); // no effect, only applies if no layout is set // scrollAreaContents->setSizePolicy(pageSizePolicy()); // screws things up, value block forced right and truncated // scrollAreaContents->setMinimumSize(QSize(900,0)); QVBoxLayout * vLayout = new QVBoxLayout(); vLayout->setObjectName("vLayout in onEndInitLoad"); vLayout->setContentsMargins(0,0,0,0); // vLayout->setMargin(0); vLayout->setSpacing(0); // <=== CONTROLS SPACING BETWEEN ROWS // doesn't solve the non-expanding widgets QSizePolicy adjSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); scrollAreaContents->setSizePolicy(adjSizePolicy); if (debugLayout) { scrollAreaContents->setStyleSheet("background-color:chartreuse;"); _centralStackedWidget->setStyleSheet("background-color:chocolate:"); // so this is where the gap is scrollArea->setStyleSheet("background-color:purple"); } // vLayout->addWidget(new FeatureWidgetHeader()); int maxHeight1 = 0; int maxHintHeight1 = 0; TRACEMCF(debugFunc, "Create FeatureWidgets for each reported VCP code and" " add them to the layout for ScrollAreaContents..."); int ct = 0; for (int feature_code = 0; feature_code < 256; feature_code++) { FeatureValue * fv = _baseModel->modelVcpValueFilteredFind(feature_code); if (fv) { // FeatureWidget * w = new FeatureWidget(); FeatureWidget * w = new FeatureWidget(*fv); if (debugLayout) { // gets applied to the widgets inside w, not to w itself w->setStyleSheet("background-color:brown;"); } // w->setFeatureValue(*fv); int ht = w->height(); QSize hintSize = w->sizeHint(); int hintHeight = hintSize.height(); // QString name = w->objectName(); // const char * clsName = w->metaObject()->className(); // printf(" Child: %s, type:%s, height=%d, hintHeight=%d\n", // QS2S(name), clsName, ht, hintHeight); if (ht > maxHeight1) maxHeight1 = ht; if (hintHeight > maxHintHeight1) maxHintHeight1 = hintHeight; QObject::connect(w , &FeatureWidget::valueChanged, this, &FeaturesScrollAreaView::onUIValueChanged); vLayout->addWidget(w); _widgets[feature_code] = w; ct++; } } TRACEMCF(debugFunc, "Created %d FeatureWidgets", ct); TRACEMCF(debugFunc, "Max height, maxHintHeight after widget creation: %d, %d", maxHeight1, maxHintHeight1); ; scrollAreaContents->setLayout(vLayout); scrollArea->setWidget(scrollAreaContents); wrapLayout->addWidget(scrollArea); scrollWrap->setLayout(wrapLayout); QObject::connect(_baseModel, &FeatureBaseModel::signalFeatureUpdated3, this, &FeaturesScrollAreaView::onModelValueChanged); _centralStackedWidget->addWidget(scrollWrap); // was scrollArea // _centralStackedWidget->hide(); // no effect _centralStackedWidget->setCurrentWidget(scrollWrap); // was scrollArea // what re childern of scrollAreaContents, scrollAreaConents.layout() // reportWidgetChildren(scrollAreaContents, "children of ScrollAreaContents"); // reportWidgetChildren(scrollWrap, "children of ScrollWrap"); #ifdef NO QRegularExpression re("^FeatureWidget-"); // QList children = scrollAreaContents.children(); // n. find same FeatureValue children using _centralWidget->findChildren(..) QList children2 = scrollAreaContents->findChildren(re); TRACEMCF(debugFunc, "Found %d children of scrollAreaContents using regular expression", children2.count()); int maxHeight2 = 0; int maxHintHeight2 = 0; for (int ndx = 0; ndx < children2.count(); ndx++) { // printf(" ndx=%d\n", ndx); FeatureWidget * child = children2.at(ndx); QString name = child->objectName(); // TRACEC("name = %s", QS2S(name)); int ht = child->height(); QSize hintSize = child->sizeHint(); int hintHeight = hintSize.height(); // const char * clsName = child->metaObject()->className(); // TRACEMCF(debug, " FeatureValue: %s, type:%s, height=%d, hintHeight=%d", // QS2S(name), clsName, ht, hintHeight); if (ht > maxHeight2) maxHeight2 = ht; if (hintHeight > maxHintHeight2) maxHintHeight2 = hintHeight; } TRACEMCF(debugFunc, "Maximum values of height, hintheight after all widgets added to layout: %d, %d", maxHeight2, maxHintHeight2); ; #endif #ifdef NO TRACEMCF(debugFunc, "Setting height of each FeatureWidget..."); for (int ndx = 0; ndx < children2.count(); ndx++) { FeatureWidget * child = children2.at(scrollwrapNdx); QSize sz = child->size(); // TRACEC("Before resize, ndx=%d", ndx); QSize hintSz = child->sizeHint(); child->setMaximumHeight(40 /* maxHintHeight2 */); //child->resize(sz.width(), 50); // !!! WRONG - INFINITE RECURSION // child->setMinimumHeight(40); // causes segfault } // printf("(onEndInitialLoad) WOLF 5\n"); fflush(stdout); #endif if (debugLayout) { static bool dimensionReportShown = false; if ( (showDimensionReport && !dimensionReportShown) ) { TRACEC("---------------------> scrollAreaContents in QScrollArea"); reportWidgetDimensions(scrollAreaContents, _cls, __func__, "scrollAreaContents in QScrollArea"); TRACEC("---------------------> QScrollArea in _centralStackedWidget"); reportWidgetDimensions(scrollArea, _cls, __func__, "QScrollArea in _centralStackedWidget"); TRACEC("---------------------> centralStackedWidget" ); reportWidgetDimensions(_centralStackedWidget, _cls, __func__, "centralStackedWidget"); dimensionReportShown = true; } } // GlobalState& globalState = GlobalState::instance(); // _curNcValuesSource = globalState._otherOptionsState->_ncValuesSource; _scrollAreaContents = scrollAreaContents; _centralStackedWidget->show(); TRACEMCF(debugFunc, "Done. feature count: %d", ct); } QSize FeaturesScrollAreaView::maxRowSize() { QSize result(0,0); return result; } void FeaturesScrollAreaView::onUIValueChanged( uint8_t featureCode, bool writeOnly, uint8_t sh, uint8_t sl) { bool debug = false; debug = debug || debugSignals; TRACEMCF(debug, "Starting. featureCode = 0x%02x, writeOnly=%s, sh=0x%02x, sl=0x%02x", featureCode, SBOOL(writeOnly), sh, sl); // *** Critical code point. This is what prevents infinite loop after getvcp returns a new value, // *** which then changes the UI valuem, which then would trigger a setvcp/getvcp call to // *** set and verify the new value, etc. FeatureValue * curFv = _baseModel->modelVcpValueFind(featureCode); if (curFv && curFv->val().sh == sh && curFv->val().sl == sl) { TRACEMCF(debug, "featureCode = 0x%02x, New value matches model value, sh=0x%02x, sl=0x%02x, Suppressing.", featureCode, sh, sl); } else { // TRACEMCF(debug, "Emitting signalVcpRequest() for VcpSetRequest, featureCode=0x%02x", featureCode); TRACEMCF(debug, "Calling _monitor->putVcpRequest() for VcpSetRequest, featureCode=0x%02x", featureCode); VcpRequest * rqst = new VcpSetRequest(featureCode, sh, sl, writeOnly); // emit signalVcpRequest(rqst); // used to call into monitor _monitor->putVcpRequest(rqst); // If feature value change affects other features, reread possibly affected features TRACEMCF(debug, "Rereading possibly affected features"); switch(featureCode) { case 0x05: // restore factory defaults brightness/contrast { uint8_t features[2] = {0x10, 0x12}; _monitor->_baseModel->reloadSpecificFeatures(2, features); // emit signalVcpRequest( new VcpGetRequest(0x10) ); // emit signalVcpRequest( new VcpGetRequest(0x12) ); // what if contrast is unsupported feature? break; } case 0x04: // restore factory defaults case 0x06: // restore geometry defaults - treat as restore factory defaults case 0x08: // restore color defaults - treat as restore factory defaults // alternatively, handle x14 in feature_base_model, is that the right place or this? // reload all, all color, or just the features documented in spec 2.2 as affected? case 0x14: // select color preset - treat as restore factory defaults // alt: wait to see if value changed case 0xdc: // display mode _monitor->_baseModel->reloadFeatures(); break; default: break; } } TRACEMCF(debug, "Done"); } void FeaturesScrollAreaView::onModelValueChanged( const char* caller, uint8_t featureCode, uint8_t sh, uint8_t sl) { bool debugFunc = false; // || (featureCode == 0x14); debugFunc = debugFunc || debugSignals; TRACEMCF(debugFunc, "caller = %s, feature_code = 0x%02x, sh=0x%02x, sl=0x%02x", caller, featureCode, sh, sl); // find the FeatureWidget for the feature code FeatureWidget * curWidget = _widgets[featureCode]; // set value in the widget uint16_t newval = sh << 8 | sl; curWidget->setCurrentValue(newval); } #ifdef PASS_NC_PARMS void FeaturesScrollAreaView::onNcValuesSourceChanged(NcValuesSource newsrc, bool newUseLatestNames) { bool debugFunc = false; debugFunc = debugFunc || debugSignals; TRACEMF(debugFunc, "newsrc=%d=%s, newUseLatestNames=%s", newsrc, (char *) ncValuesSourceName(newsrc), SBOOL(newUseLatestNames)); // TRACEMCF(debugFunc, // "newsrc=%d=%s, _curNcValuesSource=%d=%s, newUseLatestNames=%s,_curUseLatestNcValueNames=%s", // newsrc, (char*) ncValuesSourceName(newsrc), // _curNcValuesSource, (char*) ncValuesSourceName(_curNcValuesSource), // SBOOL(newUseLatestNames), SBOOL(_curUseLatestNcValueNames)); // if (newsrc != _curNcValuesSource || newUseLatestNames != _curUseLatestNcValueNames) { // reportWidgetChildren(_scrollAreaContents, (const char *) "Children of FeatuersScrollAreaView"); QObjectList childs = _scrollAreaContents->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); // QString name = curobj->objectName(); // const char * clsName = curobj->metaObject()->className(); // printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); fflush(stdout); // Both .inherits() and dyamic_cast work // if (curobj->inherits("FeatureWidget")) // printf("(%s::%s) inherits()\n", _cls, __func__); fflush(stdout); FeatureWidget * curWidget = dynamic_cast(curobj); if (curWidget) { // TRACEMCF(debugFunc, "dynamic_cast succeeded"); if (curWidget->hasSlTable()) { TRACEMCF(debugFunc, "feature_code=0x%02x, has SL table", curWidget->_feature_code); curWidget->setNcValuesSource(newsrc, newUseLatestNames); } } // } // _curNcValuesSource = newsrc; // _curUseLatestNcValueNames = newUseLatestNames; } TRACEMCF(debugFunc, "Done"); } #endif #ifdef OLD void FeaturesScrollAreaView::onModelDdcDetailedError(DdcDetailedError* perec) { bool debugFunc = false; debugFunc = debugFunc || debugSignals; TRACEMCF(debugFunc, "perec=%p, perec->%s", perec, perec->srepr() ); QString qstitle = QString("ddcutil Error"); QString qsexpl = perec->expl(); QMessageBox::Icon icon = QMessageBox::Warning; MsgBoxQueueEntry * qe = new MsgBoxQueueEntry( qstitle, qsexpl, icon); TRACEMCF(debugFunc, "Calling _msgboxQueue.put() for qe: %s", QS2S(qe->repr())); _msgboxQueue->put(qe); } void FeaturesScrollAreaView::onModelDdcFeatureError(DdcFeatureError* perec) { bool debugFunc = false; debugFunc = debugFunc || debugSignals; TRACEMCF(debugFunc, "perec=%p, perec->%s", perec, QS2S(perec->repr()) ); DDCA_Display_Info * dinfo = _monitor->_displayInfo; QString qstitle = QString("ddcutil API Error"); QString qsexpl = perec->expl(); QMessageBox::Icon icon = QMessageBox::Warning; if ( QString::compare(perec->_ddcFunction, QString("ddca_get_capabilities_string")) == 0) { // TRACE("ddca_get_capabilities_string() branch"); qsexpl = QString::asprintf( "Error reading capabilities string for display %d - %s", dinfo->dispno+1, dinfo->model_name ); qstitle = "DDC Error"; } MsgBoxQueueEntry * qe = new MsgBoxQueueEntry( qstitle, qsexpl, icon); TRACEMCF(debugFunc, "Calling _msgboxQueue.put() for qe: %s", QS2S(qe->repr())); _msgboxQueue->put(qe); TRACEMCF(debugFunc, "Done"); } #endif ddcui-0.3.0/src/feature_scrollarea/features_scrollarea_view.h000066400000000000000000000046061427175135000244760ustar00rootroot00000000000000/* features_scrollarea_view.h * * Manages the scroll area that provides a view onto the current feature settings * of a monitor. * * There is one instance of this class for each detected monitor. */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURES_SCROLLAREA_VIEW_H #define FEATURES_SCROLLAREA_VIEW_H #include #include "nongui/feature_base_model.h" #include "feature_scrollarea/feature_widget.h" class QStackedWidget; class Monitor; class FeaturesScrollAreaContents; class MsgBoxQueue; class FeaturesScrollAreaView : public QObject { Q_OBJECT public: FeaturesScrollAreaView( Monitor * monitor, // needed? complicates dependency order? FeatureBaseModel * model, QStackedWidget * centralStackedWidget, MsgBoxQueue * msgboxQueue, QObject * parent = nullptr); void freeContents(void); // unimplemented QSize maxRowSize(); // signals: // void signalVcpRequest(VcpRequest * rqst); // used to call into monitor public slots: // void startInitialLoad(void); void onEndInitialLoad(void); void onUIValueChanged(uint8_t feature_code, bool writeOnly, uint8_t sh, uint8_t sl); void onModelValueChanged(const char * caller, uint8_t featureCode, uint8_t sh, uint8_t sl); #ifdef PASS_NC_PARMS void onNcValuesSourceChanged(NcValuesSource newsrc, bool useLatestNcValueNames); #endif #ifdef OLD void onModelDdcDetailedError(DdcDetailedError* perec); void onModelDdcFeatureError(DdcFeatureError* perec); #endif #ifdef UNUSED void setInstanceControlKeyRequired(bool onoff); #endif // *** Member variables *** protected: static int nextId; private: // member variables const char * _cls; const int _id; Monitor * _monitor; FeatureBaseModel * _baseModel; QStackedWidget * _centralStackedWidget; MsgBoxQueue * _msgboxQueue; #ifdef PASS_NC_PARMS NcValuesSource _curNcValuesSource; // how to properly initialize? bool _curUseLatestNcValueNames; #endif bool _controlKeyRequired; FeaturesScrollAreaContents * _scrollAreaContents = NULL; // quick and dirty for now, eventually replace by hash FeatureWidget * _widgets[256] = {0}; }; #endif // FEATURES_SCROLLAREA_VIEW_H ddcui-0.3.0/src/feature_scrollarea/unused/000077500000000000000000000000001427175135000205435ustar00rootroot00000000000000ddcui-0.3.0/src/feature_scrollarea/unused/page_change_observer.cpp000066400000000000000000000006671427175135000254100ustar00rootroot00000000000000#include "unused/page_change_observer.h" #include #include #include // PageChangeObserver::PageChangeObserver() {} // PageChangeObserver::~PageChangeObserver() {} // void PageChangeObserver::PageChanged(int pageno) { // printf("(PageChangeObserver::%s) feature_code: %d\n", __func__, pageno ); fflush(stdout); // // std::cout << " objectName: " << objectName.toStdString() << std::endl; // } ddcui-0.3.0/src/feature_scrollarea/unused/page_change_observer.h000066400000000000000000000005341427175135000250460ustar00rootroot00000000000000#ifndef PAGE_CHANGE_OBSERVER_H #define PAGE_CHANGE_OBSERVER_H #include class QWidget; class PageChangeObserver { public: // PageChangeObserver(); // virtual ~PageChangeObserver(); virtual void pageChanged(int pageno) = 0; virtual void pageChangedByWidget(QWidget * widget) = 0; }; #endif // PAGE_CHANGE_OBSERVER_H ddcui-0.3.0/src/feature_value_widgets/000077500000000000000000000000001427175135000177535ustar00rootroot00000000000000ddcui-0.3.0/src/feature_value_widgets/.gitignore000066400000000000000000000000051427175135000217360ustar00rootroot00000000000000old/ ddcui-0.3.0/src/feature_value_widgets/old/000077500000000000000000000000001427175135000205315ustar00rootroot00000000000000ddcui-0.3.0/src/feature_value_widgets/old/value_cont_widget.cpp000066400000000000000000000331611427175135000247430ustar00rootroot00000000000000/* value_cont_widget.cpp */ // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_cont_widget.h" #include #include // #include #include #include #include #include #include #include #include #include "base/ddcui_parms.h" #include "base/core.h" #include "base/widget_debug.h" #include "c_util/string_util.h" #include "core_widgets/enhanced_slider.h" int ValueContWidget::idGenerator = 1; static bool showDimensionReports = false; static bool showBasicDims = false || debugFeatureDimensions; static bool showResizeEvents = false; void ValueContWidget::subLayout() { QSizePolicy fixedSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); fixedSizePolicy.setHorizontalStretch(0); // needed? fixedSizePolicy.setVerticalStretch(0); // sizePolicy1.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); fixedSizePolicy.setHeightForWidth(false); #ifdef UNUSED QFont monoValueFont; monoValueFont.setPointSize(9); monoValueFont.setFamily(QString::fromUtf8("Monospace")); QFont monoValueFont8; monoValueFont.setPointSize(8); monoValueFont.setFamily(QString::fromUtf8("Monospace")); QFont nonMonoValueFont; nonMonoValueFont.setPointSize(8); #endif // QFont nonMonoFont9; // nonMonoFont9.setPointSize(8); // QFont FeatureTextFont= QFont(FEATURE_VALUE_TEXT_FONT_FAMILY, FEATURE_VALUE_TEXT_FONT_SIZE); // _curSlider = new QSlider(Qt::Horizontal); _curSlider = new EnhancedSlider(Qt::Horizontal); _curSlider->setFocusPolicy(Qt::StrongFocus); _curSlider->setTickPosition(QSlider::TicksBelow); // alt TicksBothSides _curSlider->setSingleStep(1); // _curSlider->setFixedSize(200,18); // was 18 , 14 stuffs slider to bottom _curSlider->setMinimumSize(200,10); _curSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); // Trying to force a bit of space above and below slider // _curSlider->setContentsMargins(3,0,1,0); // no effect // increases height of rows in at least style adwaita // _curSlider->setStyleSheet("padding-top:2px;padding-bottom:2px"); if (debugLayout) _curSlider->setStyleSheet("background-color:pink;"); _curSpinBox = new QSpinBox(); _curSpinBox->setSingleStep(1); // _curSpinBox->setFixedSize(100,18); // extra large for 2 byte values, possible horizontal up/down buttons _curSpinBox->setMinimumSize(100,18); // becomes 52,32 - how? _curSpinBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); _curSpinBox->setFont(FeatureValueNumberEntryFont); _curSpinBox->setAlignment(Qt::AlignRight); if (debugLayout) _curSpinBox->setStyleSheet("background-color:green;"); #ifdef DOESNT_SOLVE_PROBLEM QWidget * sliderContainer = new QWidget(); QLayout * sliderContainerLayout = new QVBoxLayout(); // this?? sliderContainerLayout->setContentsMargins(0,2,0,2); sliderContainerLayout->addWidget(_curSlider); // AlignTop, AlignBottom, AlignVCenter have no effect bool ok = sliderContainerLayout->setAlignment(_curSlider, Qt::AlignBottom); // Qt::AlignVCenter); assert(ok); sliderContainer->setLayout(sliderContainerLayout); #endif _maxTitle = new QLabel("Max:"); _maxTitle->setFixedSize(30,18); // _maxTitle->setFont(nonMonoValueFont); _maxTitle->setFont(FeatureValueTextFont); _maxTitle->setContentsMargins(5,0,0,0); if (debugLayout) _maxTitle->setStyleSheet("background-color:cyan;"); _maxValue = new QLabel(); // _maxValue->setFont(monoValueFont8); _maxValue->setFont(FeatureValueTextFont); // _maxValue->setFrameStyle(QFrame::Sunken | QFrame::Panel); _maxValue->setFrameStyle(QFrame::Plain | QFrame::NoFrame); _maxValue->setFixedSize(35,20); _maxValue->setAlignment(Qt::AlignRight | Qt::AlignVCenter); if (debugLayout) _maxValue->setStyleSheet("background-color:blue;"); } void ValueContWidget::layoutWidget() { subLayout(); // unused // QLabel* spacer = new QLabel(); // spacer->setFixedSize(10,18); QHBoxLayout * layout = new QHBoxLayout(); layout->addSpacing(5); #ifdef DOESNT_SOLVE_PROBLEM layout->addWidget(sliderContainer); #else layout->addWidget(_curSlider); // crops off tick marks at bottom of slider: // how to shrint the slider size? // layout->setAlignment(_curSlider, Qt::AlignVCenter); #endif layout->addWidget(_curSpinBox); layout->addWidget(_maxTitle); layout->addWidget(_maxValue); layout->addSpacing(5+10); // layout->addWidget(spacer); layout->addStretch(10); // take up all the space at the end - stretch factor = 10 layout->setContentsMargins(1,0,1,0); // was 0,0,0,0 setLayout(layout); if (debugLayout && _id == 1) { this->setStyleSheet("background-color:yellow;"); static bool dimensionReportShown = false; if (showDimensionReports && !dimensionReportShown) { TRACEC("curSlider dimensions"); reportWidgetDimensions(_curSlider, _cls, __func__); TRACEC("_curSpinBox dimensions"); reportWidgetDimensions(_curSpinBox, _cls, __func__); TRACEC("_maxTitle dimensions"); reportWidgetDimensions(_maxTitle, _cls, __func__); TRACEC("_maxValue dimensions"); reportWidgetDimensions(_maxValue, _cls, __func__); TRACEC("ValueContWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown && _id == 1) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(this->_curSlider); REPORT_BASIC_WIDGET_DIMENSIONS(this->_curSpinBox); REPORT_BASIC_WIDGET_DIMENSIONS(this->_maxTitle); REPORT_BASIC_WIDGET_DIMENSIONS(this->_maxValue); QObjectList childs = this->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); } fflush(stdout); printf("Children of _curSpinBox:\n"); childs = _curSpinBox->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); } fflush(stdout); basicDimsShown = true; } } ValueContWidget::ValueContWidget(QWidget *parent) : ValueBaseWidget(parent) , _newval(0) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "Starting." ); _id = ValueContWidget::idGenerator++; // TRACEMC("===========================> Instance: %d", _id); layoutWidget(); TRACEMCF(debug, "TRACECMF. After ValueBaseWidget constructor"); // duplicate // connect( _curSlider, SIGNAL(valueChanged(int)), // this, SLOT( onSliderValueChanged(int))); #ifdef UNUSED connect( _curSlider, SIGNAL(valueChanged(int)), this, SLOT( onSliderValueChanged(int))); #endif connect( _curSlider, SIGNAL(sliderReleased()), this, SLOT( onSliderReleased())); connect( _curSpinBox, SIGNAL(valueChanged(int)), this, SLOT( onSpinBoxValueChanged(int))); connect( _curSlider, SIGNAL(valueChanged(int)), _curSpinBox, SLOT( setValue(int))); connect(_curSpinBox, SIGNAL(valueChanged(int)), _curSlider, SLOT( setValue(int))); #ifdef UNUSED connect( _curSpinBox, SIGNAL(editingFinished()), this, SLOT( onSpinBoxEditingFinished())); #endif _spinBoxTimer = new QTimer(); _spinBoxTimer->setSingleShot(true); _spinBoxTimer->setInterval(1000); connect(_spinBoxTimer, SIGNAL(timeout()), this, SLOT(onSpinBoxTimedOut())); } void ValueContWidget::setFeatureValue(const FeatureValue &fv) { bool debug = debugValueWidgetSignals; // debug = true; TRACEMCF(debug, "Starting. feature code: 0x%02x, before ValueBaseWidget::setFeatureValue()", fv.featureCode()); ValueBaseWidget::setFeatureValue(fv); int maxval = _mh << 8 | _ml; int curval = _sh << 8 | _sl; TRACEMCF(debug, "feature=0x%02x, curval=%d, maxval=%d", _featureCode, curval, maxval); // maxval = 99999; // for testing big numbers // curval = 99999; _guiChange = false; _curSlider->setTickInterval(maxval/10); // _curSlider->setRange(0, maxVal); _curSlider->setMaximum(maxval); _curSlider->setValue(curval); _curSpinBox->setMaximum(maxval); _curSpinBox->setValue(curval); //_curSpinBox->setRange(0,maxval); QString s = QString::number(maxval); _maxValue->setText(s); _guiChange = true; TRACEMCF(debug, "Done"); } void ValueContWidget::setCurrentShSl(uint16_t newval) { bool debug = false; TRACEMCF(debug, "newval = 0x%04x", newval); ValueBaseWidget::setCurrentShSl(newval); _guiChange = false; int curval = _sh << 8 | _sl; TRACEMCF(debugValueWidgetSignals, "feature=0x%02x, curval=%d", _featureCode , curval); // in case the timer is running, don't trigger _spinBoxTimer->stop(); _curSpinBox->setValue(curval); _curSlider->setValue(curval); _guiChange = true; TRACECF(debug, "Done"); } // model is changing value uint16_t ValueContWidget::getCurrentShSl() { int curval = _curSpinBox->value(); _sh = (curval >> 8) & 0xff; _sl = curval & 0xff; uint16_t result = (_sh << 8) | _sl; return result; } #ifdef UNUSED void ValueContWidget::onSliderValueChanged(int value) { TRACECF(debugValueWidgetSignals, "NO ACTION feature=0x%02x, value=%d", _featureCode, value); } #endif void ValueContWidget::onSliderReleased() { bool debug = debugValueWidgetSignals; // debug = true; TRACECF(debug, "feature=0x%02x", _featureCode); int newval = _curSpinBox->value(); uint8_t new_sh = (newval >> 8) & 0xff; uint8_t new_sl = newval & 0xff; // if (debugValueWidgetSignals) // printf("(%s::%s) sh=0x%02x, sl=0x%02x \n", _cls, __func__, new_sh, new_sl); fflush(stdout); _newval = newval; if (_guiChange) emit featureValueChanged(_featureCode, new_sh, new_sl); } void ValueContWidget::onSpinBoxValueChanged(int value) { bool debug = debugValueWidgetSignals; // debug = true; TRACECF(debug, "feature=0x%02x, value=%d, _guiChange=%d", _featureCode, value, _guiChange); int newval = _curSpinBox->value(); // uint8_t new_sh = (newval >> 8) & 0xff; // uint8_t new_sl = newval & 0xff; // if (debugValueWidgetSignals) // printf("(%s::%s) sh=0x%02x, sl=0x%02x \n", _cls, __func__, new_sh, new_sl); fflush(stdout); // emit featureValueChanged(_feature_code, new_sh, new_sl); _newval = newval; // QTimer::singleShot(1000, this, SLOT(onSpinBoxTimedOut())); if (_guiChange) { TRACECF(debug, "Starting spinbox timer"); _spinBoxTimer->start(); } else { TRACECF(debug,"Not starting spinbox timer"); } } void ValueContWidget::onSpinBoxTimedOut() { bool debug = debugValueWidgetSignals; // debug = true; TRACECF(debug, "feature 0x%02x, _newval=%d, emitting featureValueChanged()", _featureCode, _newval); uint8_t new_sh = (_newval >> 8) & 0xff; uint8_t new_sl = _newval & 0xff; emit featureValueChanged(_featureCode, new_sh, new_sl); } #ifdef OLD void ValueContWidget::setControlKeyRequired(bool onoff) { // TRACE("onoff=%s", sbool(onoff) ); ValueBaseWidget::setControlKeyRequired(onoff); _curSlider->oldSetControlKeyRequired(onoff); } #endif #ifdef UNNEEDED void ValueContWidget::when_ckrChanged(bool onoff) { // should probably use a function, but quick and dirty _curSlider->oldSetControlKeyRequired(onoff); } #endif #ifdef UNUSED void ValueContWidget::onSpinBoxEditingFinished() { if (debugValueWidgetSignals) printf("(%s::%s) \n", _cls, __func__); fflush(stdout); } #endif #ifdef USELESS // works for mouse // called when mouse leaves the widget's screen space. // n. not when focus is lost void ValueContWidget::leaveEvent(QEvent * event) { if (debugValueWidgetSignals) printf("(%s::%s) \n", _cls, __func__); fflush(stdout); ValueBaseWidget::leaveEvent(event); uint16_t oldval = _sh << 8 | _sl; if (oldval != _newval) { if (debugValueWidgetSignals) printf("(%s::%s) Discarding changed value\n", _cls, __func__); fflush(stdout); _curSpinBox->setValue(oldval); _newval = oldval; } } #endif void ValueContWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool sizeShown = false; if (showResizeEvents && !sizeShown && _id == 1) { show = true; sizeShown = true; } #ifdef ALT int oldWidth = oldSz.width(); int oldHeight = oldSz.height(); int newWidth = newSz.width(); int newHeight = newSz.width(); if (oldHeight != newHeight || oldWidth != newWidth) { show = true; } #endif if (show) { TRACEC("_id=%d, old size = %d, %d, new size = %d, %d ", oldSz.width(), oldSz.height(), newSz.width(), newSz.height(), _id); } evt->ignore(); } ddcui-0.3.0/src/feature_value_widgets/old/value_cont_widget.h000066400000000000000000000031511427175135000244040ustar00rootroot00000000000000/* value_cont_widget.h - Widget for displaying/editing a Continuous VCP feature value */ // Copyright (C) 2018-2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_CONT_WIDGET_H #define VALUE_CONT_WIDGET_H #include "config.h" #include "nongui/feature_value.h" #include "feature_value_widgets/value_base_widget.h" class QSlider; class QSpinBox; class QLabel; class QPushButton; class EnhancedSlider; class ValueContWidget : public ValueBaseWidget { Q_OBJECT public: ValueContWidget(QWidget *parent = nullptr); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; uint16_t getCurrentShSl() override; // void setControlKeyRequired(bool onoff) override; protected: void resizeEvent(QResizeEvent * event) override; void subLayout(); private: void layoutWidget(); #ifdef UNUSED public slots: void when_ckrChanged(bool onoff); #endif private slots: void onSliderReleased(); // void onSliderValueChanged(int value); // unused // void onSpinBoxEditingFinished(); // unused void onSpinBoxTimedOut(); void onSpinBoxValueChanged(int value); private: // member variables static int idGenerator; int _id; const char * _cls; EnhancedSlider * _curSlider; QSpinBox* _curSpinBox; QLabel* _maxTitle; QLabel* _maxValue; uint16_t _newval; QTimer* _spinBoxTimer; bool _guiChange = false; }; #endif // VALUE_CONT_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_2button_widget.cpp000066400000000000000000000107741427175135000246240ustar00rootroot00000000000000/** @file value_2button_widget.cpp * Widget containing 2 named buttons */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_2button_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" static bool showDimensionReport = false; void Value2ButtonWidget::layoutWidget() { _featureValueWidgetHeight = 20; // set it here for now uint8_t buttonHeight = _featureValueWidgetHeight; // seems to work QFont nonMonoFont; nonMonoFont.setPointSize(9); _button1 = new QPushButton(); _button1->setMaximumSize(60,buttonHeight); _button2 = new QPushButton(); _button2->setMaximumSize(60,buttonHeight); QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _button1->setSizePolicy(*sizePolicy); _button1->setFont(FeatureValueButtonFont); // _cb->setFrameStyle(QFrame::Sunken | QFrame::Panel); // not a method // _button1->setStyleSheet("background-color:white;"); _button2->setSizePolicy(*sizePolicy); _button2->setFont(FeatureValueButtonFont); // _button2->setStyleSheet("background-color:white;color:black;"); _savedBackgroundColor = _button1->backgroundRole(); QHBoxLayout * layout = new QHBoxLayout(); layout->addSpacing(5); layout->addWidget(_button1); layout->addWidget(_button2); layout->addStretch(1); layout->setContentsMargins(0,0,0,0); setLayout(layout); delete sizePolicy; if (debugLayout) { this->setStyleSheet("background-color:cyan;"); static bool dimensionReportShown = false; if (showDimensionReport && !dimensionReportShown) { printf("(%s::%s) ------------------------------------------>\n", _cls, __func__); fflush(stdout); reportWidgetDimensions(_button1, _cls, __func__, "_button1"); reportWidgetDimensions(this, _cls, __func__, "Value2ButtonWidget"); dimensionReportShown = true; } } } Value2ButtonWidget::Value2ButtonWidget( QWidget *parent) : ValueBaseWidget(parent) , _val1(0) // set in setButtonDetail() , _val2(0) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "Starting. _id=%d, _featureCode=0x%02x", _id, _featureCode ); layoutWidget(); QObject::connect(_button1, SIGNAL(released()), this, SLOT( on_button1_pressed()) ); QObject::connect(_button2, SIGNAL(released()), this, SLOT( on_button2_pressed()) ); TRACEMCF(debug, "Done"); } Value2ButtonWidget::~Value2ButtonWidget() { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d", _id); free((void*) _cls); } void Value2ButtonWidget::setButtonDetail( QString name1, uint8_t val1, QString name2, uint8_t val2) { _val1 = val1; _val2 = val2; _button1->setText(name1); _button2->setText(name2); } void Value2ButtonWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "Starting. onoff=%s", SBOOL(onoff)); ValueBaseWidget::setEnabled(onoff); #ifdef OUT ValueBaseWidget::setEnabled(onoff); if (onoff) { _button1->setBackgroundRole(_savedBackgroundColor); _button2->setBackgroundRole(_savedBackgroundColor); } else { _button1->setBackgroundRole(QPalette::Dark); _button2->setBackgroundRole(QPalette::Dark); } #endif TRACEMCF(debug, "Done."); } void Value2ButtonWidget::on_button1_pressed() { bool debug = false; // if (_base_ctrl_key_is_pressed || !classControlKeyRequired) { TRACEMCF(debug || debugValueWidgetSignals, "Button pressed. Emitting featureValueChanged()"); emit featureValueChanged(_featureCode, 0, _val1); // } // else // TRACEMCF(debug|| debugValueWidgetSignals, "Button pressed. NOT emitting featureValueChanged()"); } void Value2ButtonWidget::on_button2_pressed() { bool debug = false; // if (_base_ctrl_key_is_pressed || !classControlKeyRequired) { TRACEMCF(debug || debugValueWidgetSignals, "Button pressed. Emitting featureValueChanged()"); emit featureValueChanged(_featureCode, 0, _val2); // } // else // TRACEMCF(debug|| debugValueWidgetSignals, "Button pressed. NOT emitting featureValueChanged()"); } ddcui-0.3.0/src/feature_value_widgets/value_2button_widget.h000066400000000000000000000020461427175135000242620ustar00rootroot00000000000000/** @file value_2button_widget.h * Widget containing 2 named buttons */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_2BUTTON_WIDGET_H #define VALUE_2BUTTON_WIDGET_H #include #include "value_base_widget.h" class QPushButton; class QPalette; class Value2ButtonWidget : public ValueBaseWidget { Q_OBJECT public: Value2ButtonWidget( QWidget *parent = nullptr); ~Value2ButtonWidget(); void setButtonDetail( QString name1, uint8_t val1, QString name2, uint8_t val2); public slots: void setEnabled(bool onoff) override; private slots: void on_button1_pressed(); void on_button2_pressed(); private: // methods void layoutWidget(); private: // member variables const char * _cls; QPushButton * _button1; QPushButton * _button2; uint8_t _val1; uint8_t _val2; }; #endif // VALUE_2BUTTON_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_base_widget.cpp000066400000000000000000000104341427175135000241320ustar00rootroot00000000000000/** @file value_base_widget.cpp * Superclass of all feature value widgets */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_base_widget.h" #include #include #include #include #include "base/core.h" #include "base/global_state.h" #include "base/widget_debug.h" #include "ddcutil_c_api.h" void ValueBaseWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "Starting. _id=%d, _featureCode=0x%02x, onoff=%s, " "before calling QFrame::setEnabled(%s)", _id, _featureCode, SBOOL(onoff), SBOOL(onoff)); QFrame::setEnabled(onoff); TRACEMCF(debug, "Done."); } // utility method that provides consistent formatting for comboboxes QComboBox * ValueBaseWidget::createFormattedComboBox() { bool debug = false; TRACECF(debug, "Starting. _id=%d", _id); QComboBox * cb = new QComboBox(); TRACECF(debug, "Allocated"); QSizePolicy cbSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); cbSizePolicy.setControlType(QSizePolicy::ComboBox); cb->setSizePolicy(cbSizePolicy); cb->setFont(FeatureValueComboBoxFont); // cb->setMaximumHeight(15); // clips cb->setMaximumWidth(320); cb->setMinimumWidth(80); // _cb->setFrameStyle(QFrame::Sunken | QFrame::Panel); // not a method // cb->setStyleSheet("background-color:white;color:black;padding-left:2px;"); cb->setContentsMargins(0,0,0,0); TRACECF(debug, "Done, _id=%d", _id); return cb; } int ValueBaseWidget::nextId = 0; ValueBaseWidget::ValueBaseWidget(QWidget *parent) : QFrame(parent) // ValueAbstractWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); // private to this class _id = ++nextId; TRACECF(debug, "Executing. this._id = %d, _featureCode=%0x%02x", _id, _featureCode); //QMargins margins = contentsMargins(); //printf("(ValueBaseWidget::ValueBaseWidget) margins: left=%d, top=%d, right=%d, bottom=%d)\n", // margins.m_left, margins.m_top, margins.m_right, margins.m_bottom); // try setting frame style at this level, setFrameStyle(QFrame::Sunken | QFrame::Panel); TRACECF(debug, "Done"); } ValueBaseWidget::~ValueBaseWidget() { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d", _id); ddca_free_feature_metadata(_finfo); TRACEMCF(debug, "Done."); free((void*)_cls); } void ValueBaseWidget::setFeatureValue(const FeatureValue &fv) { bool debug = false; TRACEMCF(debug, "ValueBaseWidget. this._id=%d, featureCode=0x%02x, capVcp=%p, ddcrc=%d", _id, fv.featureCode(), fv.capVcp(), fv.ddcrc()); _featureCode = fv.featureCode(); _dref = fv.dref(); _finfo = fv.finfo(); _capVcp = fv.capVcp(); _vspec = fv.vspec(); _mh = fv.val().mh; _ml = fv.val().ml; _sh = fv.val().sh; _sl = fv.val().sl; _ddcrc = fv.ddcrc(); } #ifdef UNNEEDED // hack to give ValueNcWidget access to parsed capabilities void ValueBaseWidget::setBaseModel(FeatureBaseModel * model) { printf("(%s::%s) feature_code=0x%02x, model=%p\n", _cls, __func__, _featureCode, model); fflush(stdout); _baseModel = model; } #endif void ValueBaseWidget::setCurrentShSl(uint16_t newval) { _sh = newval >> 8; _sl = newval & 0xff; } uint16_t ValueBaseWidget::getCurrentShSl() { uint16_t result = (_sh << 8) | _sl; return result; } #ifdef NO QSize ValueBaseWidget::sizeHint() const { int w = 300; int h = 20; printf("============> (ValueBaseWidget::sizeHint) returning (%d,%d)\n", w,h ); fflush(stdout); return QSize(w,h); } #endif #ifdef NO void ValueBaseWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool resizeEventsShown = false; if (showValueWidgetResizeEvents && !resizeEventsShown) { show = true; resizeEventsShown = true; } if (show) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); } evt->ignore(); } #endif ddcui-0.3.0/src/feature_value_widgets/value_base_widget.h000066400000000000000000000044671427175135000236100ustar00rootroot00000000000000/** @file value_base_widget.h * Superclass for all Value_..._Widgets */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_BASE_WIDGET_H #define VALUE_BASE_WIDGET_H #include #include #include #include #include "base/global_state.h" #include "nongui/feature_value.h" extern bool showValueWidgetResizeEvents; class ValueStackedWidget; class ValueBaseWidget : public QFrame // was ValueAbstractWidget { Q_OBJECT // *** Constructors and Methods public: explicit ValueBaseWidget(QWidget *parent = nullptr); virtual ~ValueBaseWidget(); virtual void setFeatureValue(const FeatureValue &fv); virtual void setCurrentShSl(uint16_t newval); virtual uint16_t getCurrentShSl(); // QSize sizeHint() const override; // needed? public slots: virtual void setEnabled(bool onoff); signals: void featureValueChanged(uint8_t feature_code, uint8_t sh, uint8_t sl); protected: QComboBox * createFormattedComboBox(); bool isChangable(); // void resizeEvent( QResizeEvent * ev) override; // for debugging layout // *** Variables *** public: int _id; protected: static int nextId; // initialized since Coverity complains that uninitialized in constructor, // will be set by setFeatureValue() before first use uint8_t _featureCode = 0; DDCA_Display_Ref _dref = NULL; DDCA_Feature_Metadata * _finfo = NULL; DDCA_Cap_Vcp * _capVcp = NULL; DDCA_MCCS_Version_Spec _vspec = DDCA_VSPEC_UNQUERIED; // yes, it's in DDCA_Feature_Metadata, but this makes use clearer uint8_t _mh = 0; uint8_t _ml = 0; uint8_t _sh = 0; uint8_t _sl = 0; DDCA_Status _ddcrc = 0; GlobalState& _globalState = GlobalState::instance(); int _featureValueWidgetHeight = 20; QPalette::ColorRole _savedBackgroundColor = QPalette::Base; private: const char * _cls; }; #endif // VALUE_BASE_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_bytes_widget.cpp000066400000000000000000000226201427175135000243460ustar00rootroot00000000000000// value_bytes_widget.cpp // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "value_bytes_widget.h" #include #include #include #include #include #include #include #include "base/ddcui_parms.h" #include "base/core.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_base_widget.h" int ValueBytesWidget::idGenerator = 1; static bool showDimensionReports = false; static bool titleDimensionReportShown = false; static bool dimensionReportShown = false; QLabel * ValueBytesWidget::newTitle(QString title, int titleHeight) { QLabel* lab = new QLabel(title); // TRACECF(true, "titleHeight=%d",titleHeight); // QFont nonMonoValueFont; // nonMonoValueFont.setPointSize(8); QSize titleSize = QSize(20,titleHeight); // QFont titleFont = nonMonoValueFont; // QFont titleFont = FeatureValueTextFont; int titleFrameStyle = QFrame::Plain | QFrame::NoFrame; lab->setFixedSize(titleSize); // lab->setFont(nonMonoValueFont); lab->setFont(FeatureValueTextFont); lab->setFrameStyle(titleFrameStyle); if (debugLayout) { QString titleDebugStyle("background-color:cyan;"); lab->setStyleSheet(titleDebugStyle); if (showDimensionReports && !titleDimensionReportShown) { } } return lab; } void ValueBytesWidget::createWidgets() { int buttonHeight = widgetHeight; int titleHeight = widgetHeight - 2; // if (_id == 1) { // TRACEC("_id=%d, _widgetHeight=%d, widgetHeight=%d", _id, _featureValueWidgetHeight, widgetHeight); // } QSizePolicy fixedSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); fixedSizePolicy.setHorizontalStretch(0); // needed? fixedSizePolicy.setVerticalStretch(0); // sizePolicy1.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); fixedSizePolicy.setHeightForWidth(false); // QFont monoValueFont; // monoValueFont.setPointSize(9); // monoValueFont.setFamily(QString::fromUtf8("Monospace")); _mhTitle = newTitle("mh:", titleHeight); _mlTitle = newTitle("ml:", titleHeight); _shTitle = newTitle("sh:", titleHeight); _slTitle = newTitle("sl:", titleHeight); QFont valueFont = FeatureValueNumberEntryFont; //QFont valueFont(monoValueFont); // int valueFrameStyle = QFrame::Plain | QFrame::NoFrame; QSize valueSize(30,widgetHeight); _mhValue = newTitle("x00", titleHeight); _mlValue = newTitle("x00", titleHeight); _shValue = createFormattedComboBox(); _slValue = createFormattedComboBox(); _shValue->setMinimumWidth(60); _slValue->setMinimumWidth(60); // _shValue->setFrameStyle(QFrame::Sunken | QFrame::Panel); // not a method for (int ndx = 0; ndx <= 255; ndx++) { // TRACEMF(debugFunc, "value code: 0x%02x, value_name: %s", // cur->value_code, cur->value_name); QString s = QString::asprintf("x%02x (%d)", ndx, ndx); // TRACEMF(debugNcValues, "text being added: %s", QS2S(s)); _shValue->addItem(s, QVariant(ndx)); _slValue->addItem(s, QVariant(ndx)); } QSizePolicy sizePolicy = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _applyButton = new QPushButton("Apply"); _cancelButton = new QPushButton("Cancel"); _applyButton->setMaximumSize(55,buttonHeight); _applyButton->setSizePolicy(sizePolicy); _applyButton->setFont(FeatureValueButtonFont); _cancelButton->setMaximumSize(55,buttonHeight); _cancelButton->setSizePolicy(sizePolicy); _cancelButton->setFont(FeatureValueButtonFont); _applyButton->setEnabled(false); _cancelButton->setEnabled(false); } void ValueBytesWidget::layoutWidget() { int afterValueSpace = 15; int preValueSpace = 10; QHBoxLayout * layout = new QHBoxLayout(); layout->addSpacing(10); layout->addWidget(_mhTitle); layout->addSpacing(preValueSpace); layout->addWidget(_mhValue); layout->addSpacing(afterValueSpace); layout->addWidget(_mlTitle); layout->addSpacing(preValueSpace); layout->addWidget(_mlValue); layout->addSpacing(afterValueSpace); layout->addWidget(_shTitle); layout->addSpacing(afterValueSpace); layout->addWidget(_shValue); layout->addSpacing(afterValueSpace); layout->addWidget(_slTitle); layout->addSpacing(preValueSpace); layout->addWidget(_slValue); layout->addSpacing(afterValueSpace); layout->addWidget(_applyButton); layout->addWidget(_cancelButton); layout->addStretch(10); // apply all added size to end layout->setSpacing(0); layout->setContentsMargins(0,0,0,0); setLayout(layout); if (debugLayout && _id == 1) { this->setStyleSheet("background-color:yellow;"); if (showDimensionReports && !dimensionReportShown && _id == 1) { TRACEC("_mhTitle dimensions"); reportWidgetDimensions(_mhTitle, _cls, __func__); //TRACEC("_mhWidget dimensions"); //reportWidgetDimensions(_mhWidget, _cls, __func__); TRACEC("_mhvalue dimensions"); reportWidgetDimensions(_mhValue, _cls, __func__); TRACEC("_mlTitle dimensions"); reportWidgetDimensions(_mlTitle, _cls, __func__); // TRACEC("_mlWidget dimensions"); // reportWidgetDimensions(_mlWidget, _cls, __func__); TRACEC("_mlvalue dimensions"); reportWidgetDimensions(_mlValue, _cls, __func__); TRACEC("_applyButton dimensions"); reportWidgetDimensions(_applyButton, _cls, __func__); TRACEC("ValueBytesWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } } ValueBytesWidget::ValueBytesWidget(QWidget *parent) : ValueBaseWidget(parent) { _cls = strdup(metaObject()->className()); bool debug = false; TRACEMCF(debug, "Starting." ); _id = ValueBytesWidget::idGenerator++; createWidgets(); layoutWidget(); QObject::connect(_shValue, SIGNAL(activated(int)), this, SLOT(when_combobox_activated(int)) ); QObject::connect(_slValue, SIGNAL(activated(int)), this, SLOT(when_combobox_activated(int)) ); connect(_applyButton, &QPushButton::clicked, this, &ValueBytesWidget::onApplyButtonClicked); connect(_cancelButton, &QPushButton::clicked, this, &ValueBytesWidget::onCancelButtonClicked); TRACEMCF(debug, "Done"); } ValueBytesWidget::~ValueBytesWidget() { free((void*) _cls); } void ValueBytesWidget::when_combobox_activated(int ndx) { uint8_t new_sh = ndx >> 8; uint8_t new_sl = ndx & 0xff; if (new_sh != _sh || new_sl != _sl) { _shNew = new_sh; _slNew = new_sl; _applyButton->setEnabled(true); _cancelButton->setEnabled(true); } } void ValueBytesWidget::setFeatureValue(const FeatureValue &fv) { bool debug = debugValueWidgetSignals; // debug = false; TRACEMCF(debug, "Starting. feature code: 0x%02x, mh: 0x%02x, ml: 0x%02x, sh: 0x%02x sl: 0x%02x", fv.featureCode(), fv.val().mh, fv.val().ml, fv.val().sh, fv.val().sl); ValueBaseWidget::setFeatureValue(fv); TRACEMCF(debug, "After valueBaseWidget::setFeatureValue() called, feature code: 0x%02x, mh: 0x%02x, ml: 0x%02x, sh: 0x%02x sl: 0x%02x", _featureCode, _mh, _ml, _sh, _sl); _guiChange = false; _mhValue->setText(QString::asprintf("x%02x", _mh)); _mlValue->setText(QString::asprintf("x%02x", _ml)); _shValue->setCurrentIndex(_sh); _slValue->setCurrentIndex(_sl); // cf: // QString s = QString::number(maxval); // _maxValue->setText(s); _applyButton->setEnabled(false); _cancelButton->setEnabled(false); _guiChange = true; TRACEMCF(debug, "Done"); } void ValueBytesWidget::setCurrentShSl(uint16_t newval) { ValueBaseWidget::setCurrentShSl(newval); _guiChange = false; // will update what's shown _shValue->setCurrentIndex(newval >> 8); _slValue->setCurrentIndex(newval & 0xff); // int baseval = _sh << 8 | _sl; // assert(baseval == newval); TRACECF(debugValueWidgetSignals, "feature=0x%02x, newval=0%04x", _featureCode , newval); _applyButton->setEnabled(false); _cancelButton->setEnabled(false); _guiChange = true; } // MOC not finding base class implementation #ifdef SHOULD_USE_BASE uint16_t ValueBytesWidget::getCurrentShSl() { return ValueBaseWidget::getCurrentShSl(); // uint16_t result = (_sh << 8) | _sl; // return result; } // #endif void ValueBytesWidget::onApplyButtonClicked(bool checked) { bool debug = debugValueWidgetSignals; // debug = true; // TRACEF(debug, "Executing. checked=%s", sbool(checked)); if (_shNew != _sh || _slNew != _sl) { TRACECF(debug, "Emitting featureValueChanged(). feature code: 0x%02x, new sh: 0x%02x, new sl: 0x%02x", _featureCode, _shNew, _slNew); _sh = _shNew; _sl = _slNew; emit featureValueChanged(_featureCode, _shNew, _slNew); } // what to do while we're waiting for the update to apply or fail? _applyButton->setEnabled(false); _cancelButton->setEnabled(false); } void ValueBytesWidget::onCancelButtonClicked(bool checked) { _shNew = _sh; _slNew = _sl; _applyButton->setEnabled(false); _cancelButton->setEnabled(false); } ddcui-0.3.0/src/feature_value_widgets/value_bytes_widget.h000066400000000000000000000034551427175135000240200ustar00rootroot00000000000000/* value_bytes_widget.h * * For undefined features. */ // Copyright (C) 2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_BYTES_WIDGET_H_ #define VALUE_BYTES_WIDGET_H_ #include "config.h" #include #include "core_widgets/number_entry_widget.h" #include "nongui/feature_value.h" #include "feature_value_widgets/value_base_widget.h" class QLabel; class QPushButton; class QComboBox; class ValueBytesWidget : public ValueBaseWidget { Q_OBJECT public: ValueBytesWidget(QWidget *parent = nullptr); ~ValueBytesWidget(); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; uint16_t getCurrentShSl() override; private: QLabel * newTitle(QString title, int titleHeight); void createWidgets(); void layoutWidget(); void checkAcceptCancelEnabled(); private slots: void when_combobox_activated(int index); void onApplyButtonClicked(bool checked); void onCancelButtonClicked(bool checked); private: // member variables static int idGenerator; int _id; const char * _cls; QLabel* _mhTitle; QLabel* _mhValue; QLabel* _mlTitle; QLabel* _mlValue; QLabel* _shTitle; QComboBox * _shValue; QLabel* _slTitle; QComboBox * _slValue; QPushButton * _applyButton; QPushButton * _cancelButton; bool _guiChange = false; const int widgetHeight = 20; // QFont nonMonoFont9; uint8_t _shNew; uint8_t _slNew; }; #endif /* VALUE_BYTES_WIDGET_H_ */ ddcui-0.3.0/src/feature_value_widgets/value_cnc_widget_x14.cpp000066400000000000000000000105601427175135000244570ustar00rootroot00000000000000/* value_cnc_widget_x14.cpp * * Special handling for complex non-continuous feature x14 - Color Preset */ // Copyright (C) 2019-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_cnc_widget_x14.h" #include #include #include #include #include #include #include #include #include "base/core.h" #include "base/ddca_utils.h" #include "base/widget_debug.h" #include "nongui/feature_base_model.h" #include "feature_value_widgets/value_nc_widget.h" ValueCncWidgetX14::ValueCncWidgetX14(QWidget *parent): ValueNcWidget(parent) { _cls = strdup(metaObject()->className()); // TRACE("Starting." ); #ifdef REF QFont nonMonoFont8; nonMonoFont8.setPointSize(8); QFont nonMonoFont9; nonMonoFont9.setPointSize(9); _cb = new QComboBox(); QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); sizePolicy->setControlType(QSizePolicy::ComboBox); _cb->setSizePolicy(*sizePolicy); _cb->setFont(nonMonoFont8); _cb->setMaximumHeight(20); // whatever the size, large or small, causes big gap between RW and feature value _cb->setMaximumWidth(320); // _cb->setFrameStyle(QFrame::Sunken | QFrame::Panel); // not a method _cb->setStyleSheet("background-color:white;color:black;"); #ifdef APPLY_CANCEL if (useApplyCancel) { sizePolicy->setControlType(QSizePolicy::PushButton); _applyButton = new QPushButton("Apply"); _cancelButton = new QPushButton("Cancel"); _applyButton->setMaximumSize(55,20); _applyButton->setSizePolicy(*sizePolicy); _applyButton->setFont(nonMonoFont9); _cancelButton->setMaximumSize(55,20); _cancelButton->setSizePolicy(*sizePolicy); _cancelButton->setFont(nonMonoFont9); } #endif QHBoxLayout * layout = new QHBoxLayout(); layout->addSpacing(5); layout->addWidget(_cb); layout->addStretch(1); #ifdef APPLY_CANCEL if (useApplyCancel) { layout->addWidget(_applyButton); layout->addWidget(_cancelButton); } else { layout->addSpacing(10); } #else layout->addSpacing(10); #endif layout->setContentsMargins(0,0,0,0); setLayout(layout); if (debugLayout) { if (!dimensionReportShown) { TRACE("combobox dimensions"); reportWidgetDimensions(_cb, _cls, __func__); TRACE("ValueNcWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } this->setStyleSheet("background-color:cyan;"); } QObject::connect(_cb, SIGNAL(activated(int)), this, SLOT(combobox_activated(int)) ); #endif _mhlabel = new QLabel("Tolerance:"); _mhdesc = new QLabel(); delete _layout; _layout = new QHBoxLayout(); _layout->addSpacing(5); _layout->addWidget(_cb); _layout->addStretch(1); #ifdef UNUSED _layout->addWidget(_mhlabel); #endif _layout->addWidget(_mhdesc); _layout->addStretch(2); #ifdef APPLY_CANCEL if (useApplyCancel) { _layout->addWidget(_applyButton); _layout->addWidget(_cancelButton); } else { _layout->addSpacing(10); } #else _layout->addSpacing(10); #endif _layout->setContentsMargins(0,0,0,0); setLayout(_layout); } ValueCncWidgetX14::~ValueCncWidgetX14() { free((void*) _cls); delete _mhlabel; delete _mhdesc; } void ValueCncWidgetX14::setFeatureValue(const FeatureValue &fv) { ValueNcWidget::setFeatureValue(fv); const char * mh_msg = ""; // how to pull in x14_color_preset_tolerances from vcp_feature_codes.c instead, // or the formatted MH value? char buf0[100]; // TODO, either define ddcui versions of vcp_version_le(), etc, or put into api DDCA_MCCS_Version_Spec vspec = fv.vspec(); if ( (vspec.major == 2 && vspec.minor >= 2) || vspec.major == 3) { if (_mh == 0x00) mh_msg = "No tolerance specified. (mh=0x00)"; else if (_mh >= 0x0b) { snprintf(buf0, 100, "Invalid tolerance. (mh=0x%02x)", _mh); mh_msg = buf0; } else { snprintf(buf0, 100, "Tolerance: %d%% (MH=0x%02x)", _mh, _mh); mh_msg = buf0; } } _mhdesc->setText(mh_msg); } ddcui-0.3.0/src/feature_value_widgets/value_cnc_widget_x14.h000066400000000000000000000030371427175135000241250ustar00rootroot00000000000000/* value_cnc_widget_x14.h * * Special handling for complex non-continuous feature x14 - Color Preset */ // Copyright (C) 2019-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_CNC_WIDGET_X14_H_ #define VALUE_CNC_WIDGET_X14_H_ #include #include #include #include #include "../base/nc_values_state.h" #include "config.h" #include "base/ddca_utils.h" #include "feature_value_widgets/value_base_widget.h" #include "feature_value_widgets/value_nc_widget.h" class ValueCncWidgetX14 : public ValueNcWidget { Q_OBJECT public: ValueCncWidgetX14(QWidget *parent = nullptr); ~ValueCncWidgetX14(); void setFeatureValue(const FeatureValue &fv) override; // void setCurrentValue(uint16_t newval) override; // uint16_t getCurrentValue() override; // int findItem(uint8_t sl_value); // Local_Feature_Value_Table * getComboBoxEntries(NcValuesSource mode); // void loadComboBox(NcValuesSource mode); // void reloadComboBox(NcValuesSource newSource); private: QLabel * _mhdesc; QLabel * _mhlabel; const char * _cls; #ifdef NO QComboBox * _cb; #ifdef APPLY_CANCEL QPushButton * _applyButton; QPushButton * _cancelButton; #endif NcValuesSource _curNcValuesSource = OtherOptionsState::DefaultNcValuesSource; bool _guiChange = false; private slots: void combobox_activated(int index); #endif }; #endif /* VALUE_CNC_WIDGET_X14_H_ */ ddcui-0.3.0/src/feature_value_widgets/value_nc_widget.cpp000066400000000000000000000347741427175135000236350ustar00rootroot00000000000000/** @file value_nc_widget.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_nc_widget.h" #include #include #include #include #include #include #include #include #include #include "c_util/data_structures.h" #include "base/ddcui_parms.h" #include "base/core.h" #include "base/ddca_utils.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_base_widget.h" static bool debugWidget = false; static bool showDimensionReports = false; static bool showBasicDims = false || debugFeatureDimensions; static bool showResizeEvents = false; void ValueNcWidget::createWidgets() { bool debug = false; TRACECF(debug, "Starting. _id=%d", _id); _cb = createFormattedComboBox(); // in ValueBaseWidget _savedBackgroundColor = _cb->backgroundRole(); _extraInfo = new QLabel("_extraInfo"); _extraInfo->setMinimumSize(20,10); // changing has no effect _extraInfo->setFrameStyle( QFrame::Plain | QFrame::NoFrame); // ValueStdWidget has the frame, not Label _extraInfo->setFont(FeatureValueTextFont); _extraInfo->setIndent(5); QSizePolicy extraInfoSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); extraInfoSizePolicy.setHorizontalStretch(1); _extraInfo->setSizePolicy( extraInfoSizePolicy); TRACECF(debug, "Done. _id=%d", _id); } void ValueNcWidget::layoutWidget() { // TRACE("Starting"); _layout->addSpacing(5); _layout->addWidget(_cb); // _layout->addStretch(1); _layout->addWidget(_extraInfo); // _layout->addSpacing(10); _layout->setContentsMargins(0,0,0,0); // _layout->addStretch(10); // apply all added size to end setLayout(_layout); if (debugLayout) { static bool dimensionReportShown = false; this->setStyleSheet("background-color:cyan;"); _extraInfo->setStyleSheet("background-color:green;"); if (showDimensionReports &&!dimensionReportShown) { TRACEC("combobox dimensions"); reportWidgetDimensions(_cb, _cls, __func__); TRACEC("ValueNcWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(this->_cb); basicDimsShown = true; } // TRACE("Done"); } ValueNcWidget::ValueNcWidget(QWidget *parent): ValueBaseWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "Starting. id=%d, _featureCode=0x%02x", _id, _featureCode ); _layout = new QHBoxLayout(); createWidgets(); layoutWidget(); QObject::connect(_cb, SIGNAL(activated(int)), this, SLOT(combobox_activated(int)) ); TRACEMCF(debug, "Done"); } ValueNcWidget::~ValueNcWidget() { bool debugFunc = false; // debugFunc = debugFunc || (_featureCode == 0x14); TRACECF(debugFunc, "Executing. _id=%d, _featureCode=0x%02x", _id, _featureCode); free((void*) _cls); } void ValueNcWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "onoff=%s", SBOOL(onoff)); ValueBaseWidget::setEnabled(onoff); #ifdef OUT if (onoff) { _cb->setBackgroundRole(_savedBackgroundColor); } else { _cb->setBackgroundRole(QPalette::Dark); } #endif TRACEMCF(debug, "Done."); } /* It is possible that the monitor returns a value that is not in the capabilities/MCCS list. That value is added to the combobox with the description "Unrecognized Value". We want to still show that value in the combobox even if another value is subsequently selected. The solution is complicated by the fact that rescan causes the feature widgets to be recreated. So this widget uses both itself and the associated FeatureValue instance to maintain the list of observed values. The "master" list of observed values is maintained in the associated FeatureValue. Method setFeatureValue() saves a local copy in _observedNcValues. This local copy is combined with the capabilities/MCCS list to generate the list of values shown in the combo box. Method setCurrentShSl() does not have access to the master list in the FeatureValue. It adds the value passed to the local _observedNcValues. Therefore _observedNcValues remains in sync with the master list. */ void ValueNcWidget::setFeatureValue(const FeatureValue &fv) { bool debug = false; // || (fv.featureCode() == 0x14); // debug = debug || (fv.featureCode() == 0xca); debug = debug || debugWidget; // TRACEMCF(debug, "[TRACEMCF. ValueNcWidget]. Starting." ); // TRACEMF(debug, "[TRACEMF. ValueNcWidget]. Starting." ); // reports ValueNcPlosWidget, i.e. subclass name // TRACECF(debug, "[TRACECF. ValueNcWidget]. Starting." ); // reports ValueNcWidget TRACEMCF(debug, "Starting. this._id=%d, fv._id=%d, featureCode=0x%02x, capVcp=%p, ddcrc=%d", _id, fv._id, fv.featureCode(), fv.capVcp(), fv.ddcrc()); TRACEMCF(debug, " feature 0x%02x, new sl=x%02x, Before ValueBaseWidget::setFeatureValue()", fv.featureCode(), fv.val().sl); ValueBaseWidget::setFeatureValue(fv); _guiChange = false; // TRACEMCF(debug, "_sl = 0x%02x", _sl); TRACEMF(debug, "Local _observedNcValues: %s", bs256_to_string(_observedValues, ""," ")); TRACEMF(debug, "Persistent _observedValues from FeatureValue: %s", bs256_to_string(fv._observedNcValues, ""," ")); // HACK2 // assert( bs256_contains(fv._observedNcValues, _sl) ); // *** HACK *** _observedValues = bs256_or(_observedValues, fv._observedNcValues); TRACEMF(debug, "Using union of this._observedValues and fv._observedNcValues: %s", bs256_to_string(fv._observedNcValues, ""," ")); // HACK2 _observedValues = bs256_insert(_observedValues, _sl); TRACEMF(debug, "_observedValues after adding 0x%02x: %s", _sl, bs256_to_string(_observedValues, ""," ")); _ncValuesSource = _globalState._ncValuesState->_ncValuesSource; // _useLatestNcValues = _globalState._otherOptionsState->_useLatestNcValues; _useLatestNcValues = false; loadComboBox2(); _extraInfo->setText(""); _guiChange=true; TRACEMCF(debug, "Done"); } // copied from feature_metadata.c char * ValueNcWidget::sl_value_table_lookup( DDCA_Feature_Value_Entry * value_entries, uint8_t value_id) { bool debug = false; TRACEMF(debug, "Starting. value_entries=%p, value_id=0x%02x", value_entries, value_id); char * result = NULL; if (value_entries) { DDCA_Feature_Value_Entry * cur_value = value_entries; while (cur_value->value_name != NULL) { TRACEMF(debug, "value_code=0x%02x, value_name = %s", cur_value->value_code, cur_value->value_name); if (cur_value->value_code == value_id) { result = cur_value->value_name; // DBGMSG("Found"); break; } cur_value++; } } TRACEMF(debug, "Returning %p -> %s", result, result); return result; } void ValueNcWidget::loadComboBox2() { bool debugFunc = false; // (_featureCode == 0x14); // debug = debug || (_featureCode == 0xca); debugFunc = debugFunc || debugNcValues; NcValuesSource mode = _ncValuesSource; TRACEMF(debugFunc, "feature 0x%02x, mode=%d=%s, _useLatestNcValueNames=%s", _featureCode, mode, ncValuesSourceName(mode), SBOOL(_useLatestNcValues) ); // In case we're called to reload the combobox values, delete existing values for (int ndx = _cb->count()-1; ndx >= 0; ndx--) { _cb->removeItem(ndx); } TRACEMF(debugFunc, "_observedValues at method start: %s", bs256_to_string(_observedValues, ""," ")); _validValues = bs256_or(EMPTY_BIT_SET_256, _observedValues); TRACEMF(debugFunc, "_validValues at method start: %s", bs256_to_string(_validValues, ""," ")); if (mode == NcValuesFromCapabilities || mode == NcValuesFromBoth) { if (_capVcp) _validValues = bs256_or(_validValues, bs256_from_cfr(_capVcp)); } // DDCA_Feature_Value_Entry * slValues = // (_useLatestNcValues) ? _finfo->latest_sl_values : _finfo->sl_values; DDCA_Feature_Value_Entry * slValues = _finfo->sl_values; if (mode == NcValuesFromMccs || mode == NcValuesFromBoth) { _validValues = bs256_or(_validValues, bs256_from_sl_values(slValues)); } TRACEMF(debugFunc, "final _validValues: %s", bs256_to_string(_validValues, ""," ")); // DDCA_Feature_Value_Entry * valueNames = _finfo->sl_values; // if (_useLatestNcValueNames) // valueNames = _finfo->latest_sl_values; Bit_Set_256_Iterator iter = bs256_iter_new(_validValues); while(true){ int iValueCode = bs256_iter_next(iter); if (iValueCode < 0) break; uint8_t valueCode = iValueCode & 0xff; char * valueName = sl_value_table_lookup(slValues, valueCode); QString s = (valueName) ? QString::asprintf("x%02x - %s", valueCode, valueName) : QString::asprintf("x%02x - Unrecognized value", valueCode); // TRACEMF(debugFunc, "inserting 0x%02x into combobox: %s", valueCode, QS2S(s)); _cb->addItem(s, QVariant(valueCode)); } bs256_iter_free(iter); int cur_ndx = findItem(_sl); // assert (cur_ndx >= 0); // must be in _observedValues if (cur_ndx >= 0) { _cb->setCurrentIndex(cur_ndx); } else { // pathological case TRACEM("findItem() failed. _sl=%d", _sl); TRACEM(" _validValues: %s", bs256_to_string(_validValues, ""," ")); TRACEM(" _observedValues: %s", bs256_to_string(_observedValues, ""," ")); QString qstitle = QString("Internal Error"); QString qsexpl = QString::asprintf( "Value x%02x not found in combo box, _validValues: %s, _observedValues: %s", _sl, bs256_to_string(_validValues, "", " "), bs256_to_string(_observedValues, "", " ") ); QMessageBox::Icon icon = QMessageBox::Critical; MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(qstitle, qsexpl, icon); GlobalState::instance()._msgBoxQueue->put(qe); _cb->setCurrentIndex(0); } TRACEMF(debugFunc, "Done. VCP feature 0x%02x, _sl=0x%02x, current index: %d", _featureCode, _sl, _cb->currentIndex()); } void ValueNcWidget::reloadComboBox(NcValuesSource newSource, bool newUseLatestNames) { bool debugFunc = false; // (_featureCode == 0x14); debugFunc = debugFunc || debugNcValues; TRACEMF(debugFunc, "feature=0x%02x, newSource=%d=%s, _ncValuesSource=%d=%s,", _featureCode, newSource, ncValuesSourceName(newSource), _ncValuesSource, ncValuesSourceName(_ncValuesSource) ); TRACEMF(debugFunc, " newUseLatestNames=%s, _useLatestNcValueNames=%s", SBOOL(newUseLatestNames), SBOOL(_useLatestNcValues) ); // if (newSource != _ncValuesSource || newUseLatestNames != _useLatestNcValues) { if (newSource != _ncValuesSource) { _ncValuesSource = newSource; // _useLatestNcValues = newUseLatestNames; _guiChange = false; loadComboBox2(); _guiChange = true; } TRACEMF(debugFunc, "Done"); } void ValueNcWidget::setCurrentShSl(uint16_t newval) { bool debugFunc = false; // (_featureCode == 0x14); debugFunc = debugFunc || debugWidget; TRACEMF(debugFunc, "Starting. ValueNcWidget.this._id=%d, feature 0x%02x, newval=x%04x", _id, _featureCode, newval); _guiChange = false; ValueBaseWidget::setCurrentShSl(newval); // TRACEMCF(debugFunc, "_sl = 0x%02x", _sl); TRACEMCF(debugFunc, "Using local _observedNcValues: %s", bs256_to_string(_observedValues, ""," ")); if (!bs256_contains(_observedValues, _sl)) { TRACECF(debugFunc, "Value 0x%02x not found in existing _observedValues: %s", _sl, bs256_to_string(_observedValues, ""," ")); _observedValues = bs256_insert(_observedValues, _sl); TRACECF(debugFunc, "After value 0x%02x added. _observedValues: %s", _sl, bs256_to_string(_observedValues, ""," ")); loadComboBox2(); // reloads combo box, then sets current value } else { TRACECF(debugFunc, "Value 0x%02x found in existing _observedValues: %s", _sl, bs256_to_string(_observedValues, ""," ")); // - set current value in combo box int cur_ndx = findItem(_sl); if (cur_ndx >= 0) { _cb->setCurrentIndex(cur_ndx); } else { TRACEC("Unable to find value 0x%02x", _sl); } } _guiChange = true; TRACEMF(debugFunc, "Done"); } // returns -1 if not found int ValueNcWidget::findItem(uint8_t sl_value) { int result = _cb->findData(QVariant(sl_value)); return result; } uint16_t ValueNcWidget::getCurrentShSl() { // get sl from combobox int ndx = _cb->currentIndex(); QVariant qv = _cb->itemData(ndx); uint i = qv.toUInt(); _sh = 0; _sl = i & 0xff; uint16_t result = (_sh << 8) | _sl; return result; } void ValueNcWidget::combobox_activated(int index) { bool debug = false; debug = debug || debugWidget; TRACEMCF(debug, "feature 0x%02x, index=%d", _featureCode, index); int ndx = _cb->currentIndex(); assert(ndx == index); QVariant qv = _cb->itemData(ndx); uint i = qv.toUInt(); uint8_t new_sh = 0; uint8_t new_sl = i & 0xff; if (new_sh != _sh || new_sl != _sl) { TRACEMCF(debug, "Value changed. New sl: %u, _guiChange=%d", new_sl, _guiChange); if (_guiChange) { TRACEMCF(debug, "Emitting featureValueChanged, featureCode = 0x%02x, sh=0, new_sl=0x%02x", _featureCode, new_sl); emit featureValueChanged(_featureCode, 0, new_sl); } _sh = 0; _sl = new_sl; } else { TRACEMCF(debug, "Value not changed."); } } void ValueNcWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool resizeEventsShown = false; if (showResizeEvents && !resizeEventsShown) { show = true; resizeEventsShown = true; } if (show) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); } evt->ignore(); } ddcui-0.3.0/src/feature_value_widgets/value_nc_widget.h000066400000000000000000000035341427175135000232700ustar00rootroot00000000000000/** @file value_nc_widget.h * Widget to display/edit a simple Non-Continuous VCP feature value */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_NC_WIDGET_H #define VALUE_NC_WIDGET_H #include #include #include #include #include #include "config.h" #include "c_util/data_structures.h" #include "feature_value_widgets/value_base_widget.h" class ValueNcWidget : public ValueBaseWidget { Q_OBJECT // *** Methods *** public: ValueNcWidget(QWidget *parent = nullptr); ~ValueNcWidget(); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; uint16_t getCurrentShSl() override; public slots: void reloadComboBox(NcValuesSource newSource, bool useLatestNames); void setEnabled(bool onoff) override; protected: // void layoutWidgetAux(); void resizeEvent(QResizeEvent * evt) override; protected slots: void combobox_activated(int index); private: void createWidgets(); void layoutWidget(); int findItem(uint8_t sl_value); char * sl_value_table_lookup(DDCA_Feature_Value_Entry * value_entries, uint8_t value_id); void loadComboBox2(); // *** Member Variables *** protected: QComboBox * _cb; QHBoxLayout * _layout; QLabel * _extraInfo; private: NcValuesSource _ncValuesSource = NcValuesState::DefaultNcValuesSource; bool _useLatestNcValues = NcValuesState::DefaultUseMaximalMccsNcValues; Bit_Set_256 _observedValues = EMPTY_BIT_SET_256; Bit_Set_256 _validValues = EMPTY_BIT_SET_256; bool _guiChange = false; const char * _cls; }; #endif // VALUE_NC_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_ncplus_widget.cpp000066400000000000000000000144511427175135000245270ustar00rootroot00000000000000/* value_ncplus_widget.cpp * * For NC features with additional information in a byte other than SL */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_ncplus_widget.h" #include #include #include #include #include #include #include #include #include #include "base/core.h" #include "base/ddca_utils.h" #include "base/widget_debug.h" #include "nongui/feature_base_model.h" #include "feature_value_widgets/value_cnc_widget_x14.h" #include "feature_value_widgets/value_nc_widget.h" // static bool dimensionReportShown = false; // unused static bool showResizeEvents = false; #ifdef UNUSED void ValueNcplusWidget::layoutWidget() { bool debug = false; TRACEF(debug, "Starting. feature = 0x%02x", _featureCode); QFont font; font.setPointSize(8); QWidget::setFont(font); delete _layout; _layout = new QHBoxLayout(); layoutWidgetAux(); #ifdef OLD // additional fields _auxTitle = new QLabel("_auxTitle"); _auxDetail = new QLabel("_auxDetail"); // _layout = new QHBoxLayout(); _auxTitle->setAlignment(Qt::AlignLeft); // _auxTitle->setFrameStyle(QFrame::Sunken | QFrame::Panel); // now set in ValueBaseWidget _auxTitle->setMinimumSize(20,10); _auxTitle->setFrameStyle( QFrame::Plain | QFrame::NoFrame); // ValueStdWidget has the frame, not Label _auxTitle->setFont(font); _auxTitle->setIndent(5); QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); sizePolicy->setHorizontalStretch(1); _auxTitle->setSizePolicy(*sizePolicy); // delete sizePolicy; _auxDetail->setMinimumSize(20,10); _auxDetail->setFrameStyle( QFrame::Plain | QFrame::NoFrame); // ValueStdWidget has the frame, not Label _auxDetail->setFont(font); _auxDetail->setIndent(5); // QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); // sizePolicy->setHorizontalStretch(1); // _auxDetail->setSizePolicy(*sizePolicy); delete sizePolicy; // _layout->addSpacing(5); _layout->addWidget(_auxTitle); // _layout->addWidget(_auxDetail); _layout->addStretch(1); #ifdef APPLY_CANCEL if (useApplyCancel) { _layout->addWidget(_applyButton); _layout->addWidget(_cancelButton); } else { _layout->addSpacing(10); } #else // _layout->addSpacing(10); #endif _layout->setContentsMargins(0,0,0,0); setLayout(_layout); if (debugLayout) { if (!dimensionReportShown) { TRACE("combobox dimensions"); reportWidgetDimensions(_cb, _cls, __func__); TRACE("ValueNcWidget dimensions"); reportWidgetDimensions(this, _cls, __func__, "valueNcplusWidget"); dimensionReportShown = true; _auxTitle->setStyleSheet("background-color:orange;"); _auxDetail->setStyleSheet("background-color:green;"); this->setStyleSheet("background-color:cyan;"); } } #endif TRACEF(debug, "Done"); } #endif ValueNcplusWidget::ValueNcplusWidget(QWidget *parent): ValueNcWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); // layoutWidget(); TRACEMCF(debug, "Executing. _id=%d, _feature_code=0x%02x", _id, _featureCode ); } ValueNcplusWidget::~ValueNcplusWidget() { free((void*) _cls); } void ValueNcplusWidget::setAuxFieldsX14() // Color preset { // how to pull in x14_color_preset_tolerances from vcp_feature_codes.c instead, // or the formatted MH value? if ( (_vspec.major == 2 && _vspec.minor >= 2) || _vspec.major == 3) { char buf0[100]; // TODO: Convert to QString if (_mh == 0x00) { strcpy(buf0, "Tolerance: No tolerance specified. (mh=0x00)"); } else if (_mh >= 0x0b) { snprintf(buf0, 100, "Tolerance: Invalid tolerance. (mh=0x%02x)", _mh); } else { snprintf(buf0, 100, "Tolerance: %d%% (MH=0x%02x)", _mh, _mh); } // QString& mhtext(mh_msg); // _mhdesc->setText(mh_msg); _extraInfo->setText(QString(buf0)); } } void ValueNcplusWidget::setAuxFieldsXca() { // OSD if ( (_vspec.major == 2 && _vspec.minor >= 2) ) { // _auxTitle->setText("Power Mode:"); const char * s = NULL; switch(_sh) { case 0x00: s = "Host control of power function unsupported, display may not report power events (sh=x00)"; break; case 0x01: s ="Power button disabled, events enabled (sh=x01)"; break; case 0x02: s = "Power button enabled, events enabled (sh=x02)"; break; case 0x03: s = "Power button disabled, events disabled (sh=x03)"; break; default: char buf[40]; g_snprintf(buf, 40, "Invalid value (sh=x%02x)", _sh); } _extraInfo->setText(QString(s)); } } void ValueNcplusWidget::setAuxFields() { if (_featureCode == 0x14) { setAuxFieldsX14(); } else if (_featureCode == 0xca) { setAuxFieldsXca(); } } void ValueNcplusWidget::setFeatureValue(const FeatureValue &fv) { DDCA_MCCS_Version_Spec vspec = fv.vspec(); bool debug = false; TRACEMCF(debug, "Executing. feature = 0x%02x, vspec = %d.%d", fv.featureCode(), vspec.major, vspec.minor); TRACEMCF(debug, " featureCode=0x%02x, capVcp=%p, ddcrc=%d, Before ValueNcWidget::setFeatureValue()", fv.featureCode(), fv.capVcp(), fv.ddcrc()); ValueNcWidget::setFeatureValue(fv); setAuxFields(); // TRACE("Done"); } void ValueNcplusWidget::setCurrentShSl(uint16_t newval) { ValueNcWidget::setCurrentShSl(newval); setAuxFields(); } void ValueNcplusWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool resizeEventsShown = false; if (showResizeEvents && !resizeEventsShown) { show = true; resizeEventsShown = true; } if (show) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); } evt->ignore(); } ddcui-0.3.0/src/feature_value_widgets/value_ncplus_widget.h000066400000000000000000000023541427175135000241730ustar00rootroot00000000000000/* value_ncplus_widget.cpp * * For NC features with additional information in a byte other than SL */ // Copyright (C) 2021-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_NCPLUS_WIDGET_H_ #define VALUE_NCPLUS_WIDGET_H_ #include #include #include #include #include #include "../base/nc_values_state.h" #include "config.h" #include "base/ddca_utils.h" #include "feature_value_widgets/value_base_widget.h" #include "feature_value_widgets/value_nc_widget.h" class ValueNcplusWidget : public ValueNcWidget { Q_OBJECT public: ValueNcplusWidget(QWidget *parent = nullptr); ~ValueNcplusWidget(); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; // uint16_t getCurrentValue() override; protected: void resizeEvent(QResizeEvent * evt) override; private: // QLabel * _auxTitle; // QLabel * _auxDetail; // void layoutWidget(); void setAuxFieldsX14(); void setAuxFieldsXca(); void setAuxFields(); private: const char * _cls; }; #endif /* VALUE_NCPLUS_WIDGET_H_ */ ddcui-0.3.0/src/feature_value_widgets/value_new_cont_widget.cpp000066400000000000000000000041271427175135000250360ustar00rootroot00000000000000/** \file value_new_cont_widget.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "base/ddcui_parms.h" #include #include #include "base/ddcui_parms.h" #include "base/core.h" #include "base/widget_debug.h" #include "c_util/string_util.h" #include "feature_value_widgets/value_new_cont_widget.h" void ValueNewContWidget::layoutWidget(QHBoxLayout * layout) { bool debug = false; TRACECF(debug, " Starting." ); // createWidgets(); // done in ValueSimpleContWidget constructor // additionalWidgets(); // done in our constructor layout->addSpacing(5); layout->addWidget(_spinSlider); layout->addWidget(_maxTitle); layout->addWidget(_maxValue); layout->addSpacing(5+10); layout->addStretch(10); // take up all the space at the end - stretch factor = 10 layout->setContentsMargins(1,0,1,0); // was 0,0,0,0 setLayout(layout); TRACECF(debug, "Done." ); } ValueNewContWidget::ValueNewContWidget(QWidget *parent) : ValueSimpleContWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "TRACECMF. Executing. After ValueSimpleContWidget constructor, _id=%d, _featureCode=0x%02x", _id, _featureCode); } ValueNewContWidget::~ValueNewContWidget() { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d", _id); free((void*) _cls); } void ValueNewContWidget::setFeatureValue(const FeatureValue &fv) { bool debug = false; debug = debug ||debugValueWidgetSignals; int maxval = fv.val().mh << 8 | fv.val().ml; int curval = fv.val().sh << 8 | fv.val().sl; // maxval = 99999; // for testing big numbers // curval = 99999; // for testing big numbers TRACEMCF(debug, "Starting. _id=%d, feature=0x%02x, curval=%d, maxval=%d", _id, fv.featureCode(), curval, maxval); _spinSlider->setRange(0,maxval); ValueSimpleContWidget::setFeatureValue(fv); _maxValue->setText(QString::number(maxval)); TRACEMCF(debug, "Done"); } ddcui-0.3.0/src/feature_value_widgets/value_new_cont_widget.h000066400000000000000000000014131427175135000244760ustar00rootroot00000000000000/** *file value_new_cont_widget.h * Widget for displaying/editing a Continuous VCP feature value */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_NEW_CONT_WIDGET_H #define VALUE_NEW_CONT_WIDGET_H #include "config.h" #include #include "nongui/feature_value.h" #include "feature_value_widgets/value_simple_cont_widget.h" class ValueNewContWidget : public ValueSimpleContWidget { Q_OBJECT public: ValueNewContWidget(QWidget *parent = nullptr); ~ValueNewContWidget(); void setFeatureValue(const FeatureValue &fv) override; private: void layoutWidget(QHBoxLayout * layout) override; const char * _cls; }; #endif // VALUE_NEW_CONT_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_reset_widget.cpp000066400000000000000000000107641427175135000243500ustar00rootroot00000000000000/** @file value_reset_widget.cpp * Widget containing a Reset button */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_reset_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" static bool showDimensionReport = false; static bool showBasicDims = false || debugFeatureDimensions; static bool showResizeEvents = false; void ValueResetWidget::layoutWidget() { QFont nonMonoFont; nonMonoFont.setPointSize(8); _resetButton = new QPushButton("Restore"); _resetButton->setMaximumSize(60,20); QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _resetButton->setSizePolicy(*sizePolicy); _resetButton->setFont(FeatureValueButtonFont); // _resetButton->setStyleSheet("background-color:white;color:black;"); _savedBackgroundColor = _resetButton->backgroundRole(); QHBoxLayout * layout = new QHBoxLayout(); layout->addSpacing(5); layout->addWidget(_resetButton); layout->addStretch(1); layout->setContentsMargins(0,0,0,0); setLayout(layout); delete(sizePolicy); if (debugLayout) { this->setStyleSheet("background-color:cyan;"); static bool dimensionReportShown = false; if (showDimensionReport && !dimensionReportShown) { // printf("-------------------------------------------->\n"); fflush(stdout); reportWidgetDimensions(_resetButton, _cls, __func__, "ValueResetWidget::_resetButton"); reportWidgetDimensions(this, _cls, __func__, "ValueResetWidget"); dimensionReportShown = true; } } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(this->_resetButton); QObjectList childs = this->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); } fflush(stdout); basicDimsShown = true; } } ValueResetWidget::ValueResetWidget(QWidget *parent): ValueBaseWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "Starting. _id=%d, _featureCode=0x%02x", _id, _featureCode ); layoutWidget(); // QObject::connect(_resetButton, &QAbstractButton::released), // this, &ValueResetWidget::on_resetButton_pressed ); QObject::connect(_resetButton, SIGNAL(released()), this, SLOT( on_resetButton_pressed()) ); TRACEMCF(debug, "Done."); } ValueResetWidget::~ValueResetWidget() { free((void*) _cls); } void ValueResetWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "Starting. onoff=%s", SBOOL(onoff)); ValueBaseWidget::setEnabled(onoff); #ifdef OUT if (onoff) { _resetButton->setBackgroundRole(_savedBackgroundColor); } else { _resetButton->setBackgroundRole(QPalette::Dark); } #endif TRACEMCF(debug, "Done."); } void ValueResetWidget::on_resetButton_pressed() { bool debug = false; TRACEMCF(debug, "Starting. _id=%d, _featureCode=0x%02x, isEnabled=%s", _id, _featureCode, SBOOL(ValueBaseWidget::isEnabled())); TRACEMCF(debug || debugValueWidgetSignals, "Button pressed. Emitting featureValueChanged()"); emit featureValueChanged(_featureCode, 0, 1); } void ValueResetWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool resizeShown = false; if (showResizeEvents && !resizeShown) { show = true; resizeShown = true; } #ifdef ALT int oldWidth = oldSz.width(); int oldHeight = oldSz.height(); int newWidth = newSz.width(); int newHeight = newSz.width(); if (oldHeight != newHeight || oldWidth != newWidth) { show = true; } #endif if (show) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); } evt->ignore(); } ddcui-0.3.0/src/feature_value_widgets/value_reset_widget.h000066400000000000000000000015471427175135000240140ustar00rootroot00000000000000/** @file value_reset_widget.h * Widget containing a Reset button */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_RESET_WIDGET_H #define VALUE_RESET_WIDGET_H #include #include "value_base_widget.h" class QPushButton; class QPalette; class ValueResetWidget : public ValueBaseWidget { Q_OBJECT // Constructors and Methods public: ValueResetWidget(QWidget *parent = nullptr); ~ValueResetWidget(); public slots: void setEnabled(bool onoff) override; protected: void resizeEvent(QResizeEvent * evt) override; // for debugging private slots: void on_resetButton_pressed(); private: void layoutWidget(); // Variables private: const char * _cls; QPushButton * _resetButton; }; #endif // VALUE_RESET_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_simple_cont_widget.cpp000066400000000000000000000212141427175135000255320ustar00rootroot00000000000000/** @file value_simple_cont_widget.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include "base/ddcui_parms.h" #include "base/core.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_simple_cont_widget.h" static bool showDimensionReports = false; static bool showBasicDims = false || debugFeatureDimensions; static bool showResizeEvents = false; void ValueSimpleContWidget::additionalWidgets() { bool debug = false; TRACEMCF(debug, "Starting." ); // max value fields _maxTitle = new QLabel("Max:"); _maxTitle->setFixedSize(40,18); _maxTitle->setFont(FeatureValueTextFont); _maxTitle->setContentsMargins(5,0,0,0); if (debugLayout) _maxTitle->setStyleSheet("background-color:cyan;"); _maxValue = new QLabel(); _maxValue->setFont(FeatureValueTextFont); // _maxValue->setFrameStyle(QFrame::Sunken | QFrame::Panel); _maxValue->setFrameStyle(QFrame::Plain | QFrame::NoFrame); _maxValue->setFixedSize(35,20); _maxValue->setAlignment(Qt::AlignRight | Qt::AlignVCenter); if (debugLayout) _maxValue->setStyleSheet("background-color:orange;"); TRACEMCF(debug, "Done." ); } void ValueSimpleContWidget::createWidgets() { bool debug = false; TRACEMCF(debug, "Starting."); _spinSlider = new SpinSlider(); TRACEMCF(debug, "Done."); } void ValueSimpleContWidget::layoutWidget(QHBoxLayout * layout) { bool debug = false; TRACEMCF(debug, "Starting." ); layout->addSpacing(5); layout->addWidget(_spinSlider); layout->addWidget(_maxTitle); layout->addWidget(_maxValue); layout->addStretch(10); // take up all the space at the end - stretch factor = 10 layout->setContentsMargins(1,0,1,0); // was 0,0,0,0 setLayout(layout); debugSimpleContLayout(); TRACEMCF(debug, "Done." ); } ValueSimpleContWidget::ValueSimpleContWidget(QWidget *parent) : ValueBaseWidget(parent) , _cls( strdup(metaObject()->className()) ) // , _newval(0) { bool debug = false; TRACEMCF(debug, "Starting. After ValueBaseWidget() constructor." ); _newval = 0; createWidgets(); additionalWidgets(); QHBoxLayout * layout = new QHBoxLayout(); layoutWidget(layout); connect( _spinSlider, SIGNAL(featureValueChanged(uint8_t, uint8_t, uint8_t)), this, SLOT(onFeatureValueChanged(uint8_t, uint8_t, uint8_t))); TRACEMCF(debug, "Done." ); } ValueSimpleContWidget::~ValueSimpleContWidget() { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d", _id); free((void*) _cls); } void ValueSimpleContWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "_id=%d, _featureCode=0x%02x, onoff=%s", _id, _featureCode, SBOOL(onoff)); ValueBaseWidget::setEnabled(onoff); #ifdef OUT if (onoff) { _cb->setBackgroundRole(_savedBackgroundColor); } else { _cb->setBackgroundRole(QPalette::Dark); } #endif TRACEMCF(debug, "Done."); } void ValueSimpleContWidget::setRange(int minval, int maxval) { bool debug = false; TRACEMCF(debug, "minval=%d, maxval=%d", minval, maxval); assert (_minval < 0 && _maxval < 0); assert (minval >= 0 && maxval >= 0); _minval = minval; _maxval = maxval; _maxTitle->setText(QString("Range:")); _maxValue->setText( QString::asprintf("%d-%d", minval, maxval) ); TRACEMCF(debug, "Done"); } void ValueSimpleContWidget::setFeatureValue(const FeatureValue &fv) { bool debug = false; debug = debug || debugValueWidgetSignals; // _guiChange = false; TRACEMCF(debug, "Starting. feature code: 0x%02x, before ValueBaseWidget::setFeatureValue()", fv.featureCode()); ValueBaseWidget::setFeatureValue(fv); if (_maxval < 0) { // setRange has not been called _maxval = _mh << 8 | _ml; _minval = 0; } int curval = _sh << 8 | _sl; _featureCode = fv.featureCode(); // needed when signaling value changed TRACEMCF(debug, "feature=0x%02x, curval=%d, maxval=%d", _featureCode, curval, _maxval); // maxval = 99999; // for testing big numbers // curval = 99999; // _guiChange = false; TRACEMCF(debug, "Calling _spinSlider->setFeatureCode(), setRange(), setShSl()"); _spinSlider->setFeatureCode(fv.featureCode()); _spinSlider->setRange(_minval, _maxval); _spinSlider->setShSl(curval); TRACEMCF(debug, "Done."); } void ValueSimpleContWidget::setCurrentShSl(uint16_t newval) { bool debug = false; debug = debug || debugValueWidgetSignals; TRACEMCF(debug, "Starting. newval = 0x%04x", newval); ValueBaseWidget::setCurrentShSl(newval); int curval = _sh << 8 | _sl; _spinSlider->setShSl(curval); TRACEMCF(debug, "Done. feature=0x%02x, curval=%d", _featureCode , curval); } // model is querying value uint16_t ValueSimpleContWidget::getCurrentShSl() { int curval = _spinSlider->getShSl(); _sh = (curval >> 8) & 0xff; _sl = curval & 0xff; uint16_t result = (_sh << 8) | _sl; return result; } void ValueSimpleContWidget::onFeatureValueChanged(uint8_t featureCode, uint8_t sh, uint8_t sl) { bool debug = false; TRACEMCF(debug, "featureCode=0x%02x, sh=0x%02x, sl=0x%02x,_featureCode=0x%02x", featureCode, sh, sl, _featureCode); TRACEMCF(debug, "Emitting featureValueChanged(0x%02x, 0x%02x, 0x%02x)", _featureCode, sh, sl); emit featureValueChanged(_featureCode, sh, sl); } #ifdef UNUSED void ValueSimpleContWidget::onSpinBoxEditingFinished() { if (debugValueWidgetSignals) printf("(%s::%s) \n", _cls, __func__); fflush(stdout); } #endif #ifdef USELESS // works for mouse // called when mouse leaves the widget's screen space. // n. not when focus is lost void ValueSimpleContWidget::leaveEvent(QEvent * event) { if (debugValueWidgetSignals) printf("(%s::%s) \n", _cls, __func__); fflush(stdout); ValueBaseWidget::leaveEvent(event); uint16_t oldval = _sh << 8 | _sl; if (oldval != _newval) { if (debugValueWidgetSignals) printf("(%s::%s) Discarding changed value\n", _cls, __func__); fflush(stdout); _curSpinBox->setValue(oldval); _newval = oldval; } } #endif // // Debug Methods // void ValueSimpleContWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool sizeShown = false; if (showResizeEvents && !sizeShown && _id == 1) { show = true; sizeShown = true; } #ifdef ALT int oldWidth = oldSz.width(); int oldHeight = oldSz.height(); int newWidth = newSz.width(); int newHeight = newSz.width(); if (oldHeight != newHeight || oldWidth != newWidth) { show = true; } #endif if (show) { TRACEC("_id=%d, old size = %d, %d, new size = %d, %d ", oldSz.width(), oldSz.height(), newSz.width(), newSz.height(), _id); } evt->ignore(); } void ValueSimpleContWidget::debugSimpleContLayout() { if (debugLayout && _id == 1) { this->setStyleSheet("background-color:yellow;"); static bool dimensionReportShown = false; if (showDimensionReports && !dimensionReportShown) { TRACEC("_spinSlider dimensions"); reportWidgetDimensions(_spinSlider, _cls, __func__); #ifdef FOR_SUBCLASS TRACEC("_maxTitle dimensions"); reportWidgetDimensions(_maxTitle, _cls, __func__); TRACEC("_maxValue dimensions"); reportWidgetDimensions(_maxValue, _cls, __func__); #endif TRACEC("ValueSimpleContWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } // if (_id == 1) { // TRACEC("widget background color %s", QS2S(this->palette().color(QWidget::backgroundRole()).name())); // TRACEC("slider background color %s", QS2S(_curSlider->palette().color(QWidget::backgroundRole()).name())); // } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown && _id == 1) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(this->_spinSlider); REPORT_BASIC_WIDGET_DIMENSIONS(this->_maxTitle); REPORT_BASIC_WIDGET_DIMENSIONS(this->_maxValue); QObjectList childs = this->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); } fflush(stdout); basicDimsShown = true; } } ddcui-0.3.0/src/feature_value_widgets/value_simple_cont_widget.h000066400000000000000000000031261427175135000252010ustar00rootroot00000000000000/** @file value_simple_cont_widget.h * * Display/edit a Continuous VCP feature value with specified minimum and maximum values */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_SIMPLE_CONT_WIDGET_H #define VALUE_SIMPLE_CONT_WIDGET_H #include "config.h" #include "base/ddcui_parms.h" #include "nongui/feature_value.h" #include "core_widgets/spin_slider.h" #include "feature_value_widgets/value_base_widget.h" class SpinSlider; class ValueSimpleContWidget : public ValueBaseWidget { Q_OBJECT public: ValueSimpleContWidget(QWidget *parent = nullptr); ~ValueSimpleContWidget(); void setRange(int minval, int maxval); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; uint16_t getCurrentShSl() override; protected: // methods void resizeEvent(QResizeEvent * event) override; virtual void layoutWidget(QHBoxLayout * layout); void createWidgets(); void additionalWidgets(); private slots: void onFeatureValueChanged(uint8_t featureCode, uint8_t sh, uint8_t sl); void setEnabled(bool onoff) override; private: // methods void debugSimpleContLayout(); protected: // member variables int _minval = -1; int _maxval = -1; SpinSlider * _spinSlider; uint16_t _newval; QLabel* _maxTitle; QLabel* _maxValue; private: // member variables const char * _cls; }; #endif // VALUE_SIMPLE_CONT_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_special_widget_x62.cpp000066400000000000000000000124611427175135000253410ustar00rootroot00000000000000/** @file value_special_widget_x62.cpp * Adjust audio volume */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include "base/ddcui_parms.h" #include "value_simple_cont_widget.h" #include "value_special_widget_x62.h" static bool debugWidget = true; void ValueSpecialWidgetX62::createInitialWidgets() { bool debug = false; TRACECF(debug, "Starting. ValueSpecialWidgetX62::createInitialWidgets()"); _cb = createFormattedComboBox(); if (debugLayout) _cb->setStyleSheet("background-color:cyan;"); TRACECF(debug, "Done. ValueSpecialWidgetX62::createInitialWidgets()"); } void ValueSpecialWidgetX62::layoutWidget(QHBoxLayout * layout) { bool debug = false; TRACECF(debug, "Starting. ValueSpecialWidgetX62::layoutWidget" ); layout->addSpacing(5); _cb->setVisible(true); layout->addWidget(_cb); layout->addWidget(_spinSlider); layout->addSpacing(5+10); layout->addStretch(10); // take up all the space at the end - stretch factor = 10 layout->setContentsMargins(0,0,0,0); setLayout(layout); TRACECF(debug, "Done. ValueSpecialWidgetX62::layoutWidget" ); } ValueSpecialWidgetX62::ValueSpecialWidgetX62(QWidget *parent) : ValueSimpleContWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); TRACEMCF(debug, "Starting. _cls=%s, _id=%d, _featureCode=0x%02x", _cls, _id, _featureCode ); setRange(0x01, 0xfe); createInitialWidgets(); delete layout(); // delete layout created by superclass constructor QHBoxLayout * layout = new QHBoxLayout(); layoutWidget(layout); loadComboBox(); QObject::connect(_cb, SIGNAL(activated(int)), this, SLOT(combobox_activated(int)) ); TRACEMCF(debug, "Done."); } ValueSpecialWidgetX62::~ValueSpecialWidgetX62() { bool debug = false; TRACEMCF(debug, "Executing. this._id = %d", _id); free((void*) _cls); } void ValueSpecialWidgetX62::setFeatureValue(const FeatureValue &fv) { bool debug = false; TRACEMCF(debug, "ValueSpecialWidgetX62. featureCode=0x%02x, capVcp=%p, sh=0x%02x, sl=0x%02x, ddcrc=%d", fv.featureCode(), fv.capVcp(), fv.ddcrc()); ValueSimpleContWidget::setFeatureValue(fv); TRACEMCF(debug, "Done"); } void ValueSpecialWidgetX62::loadComboBox() { _cb->addItem(QString("0: Mute"), QVariant( 0) ); _cb->addItem(QString("1-254: Level"), QVariant( 1) ); _cb->addItem(QString("255 - Default Level"), QVariant(255) ); _cb->setCurrentIndex(2); } void ValueSpecialWidgetX62::setCurrentShSl(uint16_t newval) { bool debugFunc = false; debugFunc = debugFunc || debugWidget; TRACEMF(debugFunc, "Starting. feature 0x%02x, newval=x%04x", _featureCode, newval); ValueBaseWidget::setCurrentShSl(newval); newval = newval & 0xff; if (newval == 0) { TRACECF(debugFunc, "newval = 0, oldCbIndex != 0"); _cb->setCurrentIndex(0); _spinSlider->setEnabled(false); } else if (newval == 255) { TRACECF(debugFunc,"newval = 255, oldCbIndex != 2"); _cb->setCurrentIndex(2); _spinSlider->setEnabled(false); } else { // newval = 1..254 TRACECF(debugFunc, "newval = %d, oldCbIndex != 1", newval); _cb->setCurrentIndex(1); _spinSlider->setShSl(newval); _spinSlider->setEnabled(true); } } uint16_t ValueSpecialWidgetX62::getCurrentShSl() { // get sl from combobox if (_cb->currentIndex() == 0) _sl = 0; else if (_cb->currentIndex() == 2) _sl = 255; else _sl = _spinSlider->getShSl(); _sh = 0; uint16_t result = (_sh << 8) | _sl; return result; } void ValueSpecialWidgetX62::combobox_activated(int index) { bool debug = false; debug = debug || debugWidget; TRACEMCF(debug, "feature 0x%02x, index=%d", _featureCode, index); assert(_cb->currentIndex() == index); assert(_sh == 0); uint8_t new_sh = 0; uint8_t new_sl = _spinSlider->getShSl(); if (index == 0) new_sl = 0; else if (index == 2) new_sl = 255; if (new_sh != _sh || new_sl != _sl) { TRACEMCF(debug, "Value changed. New sl: %u", new_sl); TRACEMCF(debug, "Emitting featureValueChanged, featureCode = 0x%02x, sh=0, new_sl=0x%02x", _featureCode, new_sl); emit featureValueChanged(_featureCode, 0, new_sl); // _sh = 0; // unnecessary because of assert() _sl = new_sl; } else { TRACEMCF(debug, "Value not changed."); } } //ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddccccc ddcui-0.3.0/src/feature_value_widgets/value_special_widget_x62.h000066400000000000000000000022001427175135000247740ustar00rootroot00000000000000/** @file value_special_widget_x62.h * Adjust audio volume */ // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_SPECIAL_WIDGET_X62_H_ #define VALUE_SPECIAL_WIDGET_X62_H_ #include #include "config.h" #include "base/ddcui_parms.h" #include "nongui/feature_value.h" #include "feature_value_widgets/value_simple_cont_widget.h" class ValueSpecialWidgetX62 : public ValueSimpleContWidget { Q_OBJECT public: // methods ValueSpecialWidgetX62(QWidget *parent = nullptr); ~ValueSpecialWidgetX62(); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; uint16_t getCurrentShSl() override; private: // methods void createInitialWidgets(); void layoutWidget(QHBoxLayout * layout) override; void loadComboBox(); private slots: // methods void combobox_activated(int index); private: // member variables const char * _cls; QComboBox * _cb; }; #endif // VALUE_SPECIAL_WIDGET_X62_H_ ddcui-0.3.0/src/feature_value_widgets/value_stacked_widget.cpp000066400000000000000000000410671427175135000246440ustar00rootroot00000000000000/** @file value_stacked_widget.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "feature_value_widgets/value_stacked_widget.h" #include #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_bytes_widget.h" #include "feature_value_widgets/value_cnc_widget_x14.h" #include "feature_value_widgets/value_nc_widget.h" #include "feature_value_widgets/value_new_cont_widget.h" #include "feature_value_widgets/value_std_widget.h" static bool dimensionReportShown = false; int ValueStackedWidget::nextId = 0; ValueStackedWidget::ValueStackedWidget(QWidget *parent) : QStackedWidget(parent) , _featureCode(0) // appease Coverity { bool debug = false; _cls = strdup(metaObject()->className()); _id = ++nextId; TRACECF(debug, "Starting. id=%d", _id); // _typedParent = dynamic_cast(parent); // this->setObjectName(QString::fromUtf8("value_stacked_widget")); // ambiguous // setGeometry(QRect(209,6, 181, 20)); _newContWidget = new ValueNewContWidget(this); _simpleContWidget = new ValueSimpleContWidget(this); _ncWidget = new ValueNcWidget(this); _stdWidget = new ValueStdWidget(this); _resetWidget = new ValueResetWidget(this); _2ButtonWidget = new Value2ButtonWidget(this); _cncWidgetX14 = new ValueCncWidgetX14(this); _bytesWidget = new ValueBytesWidget(this); _ncplusWidget = new ValueNcplusWidget(this); _specialWidgetX62 = new ValueSpecialWidgetX62(this); TRACECF(debug," _ncWidget->_id=%d, _cncWidgetX14->_id=%d, _ncplusWidget._id=%d", _ncWidget->_id, _cncWidgetX14->_id, _ncplusWidget->_id); _subwidget[_subwidgetCt++] = _stdWidget; _subwidget[_subwidgetCt++] = _newContWidget; _subwidget[_subwidgetCt++] = _simpleContWidget; _subwidget[_subwidgetCt++] = _ncWidget; _subwidget[_subwidgetCt++] = _resetWidget; _subwidget[_subwidgetCt++] = _2ButtonWidget; _subwidget[_subwidgetCt++] = _cncWidgetX14; _subwidget[_subwidgetCt++] = _bytesWidget; _subwidget[_subwidgetCt++] = _ncplusWidget; _subwidget[_subwidgetCt++] = _specialWidgetX62; assert(_subwidgetCt == ARRAY_SIZE(_subwidget)); // relying on _pageno_xxx order corresponds to addWidget() order _pageno_cont = 0; _pageno_nc = 1; _pageno_std = 2; _pageno_reset = 3; _pageno_2button = 4; _pageno_x14 = 5; _pageno_bytes = 6; _pageno_ncplus = 7; _pageno_simple_cont = 8; _pageno_x62 = 9; addWidget(_newContWidget); addWidget(_ncWidget); addWidget(_stdWidget); addWidget(_resetWidget); addWidget(_2ButtonWidget); addWidget(_cncWidgetX14); addWidget(_bytesWidget); addWidget(_ncplusWidget); addWidget(_simpleContWidget); addWidget(_specialWidgetX62); if (debugLayout) { if (!dimensionReportShown) { // printf("-------------------------------------------->\n"); reportFrameDimensions(this, _cls, __func__, "ValueStackedWidget dimensions"); dimensionReportShown = true; } this->setStyleSheet("background-color:red;"); } _pageno_selected = _pageno_std; // default // setCurrentIndex(_pageno_selected); setCurrentWidget(_stdWidget); _cur_stacked_widget = _stdWidget; // ValueStackedWidget * curWidget = this; // still treated as ValueBaseWidget* in SIGNAL/SLOT versions QWidget::connect(_newContWidget, &ValueNewContWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_simpleContWidget, &ValueSimpleContWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_specialWidgetX62, &ValueSpecialWidgetX62::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); // needed? QWidget::connect(_specialWidgetX62, &ValueSimpleContWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_ncWidget, &ValueNcWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_ncplusWidget, &ValueNcplusWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); // why disabled? // QWidget::connect(_cncWidgetX14, &ValueNcWidget::featureValueChanged, // this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_bytesWidget, &ValueBaseWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); QWidget::connect(_resetWidget, &ValueResetWidget::featureValueChanged, this, &ValueStackedWidget::forContainedWidgetChanged); #ifdef WORKS QWidget::connect(_ncWidget, SIGNAL(featureValueChanged( uint8_t, uint8_t, uint8_t)), curWidget, SLOT(forContainedWidgetChanged(uint8_t, uint8_t, uint8_t))); QWidget::connect(_ncWidget, SIGNAL(featureValueChanged( uint8_t, uint8_t, uint8_t)), curWidget, SLOT(forContainedWidgetChanged(uint8_t, uint8_t, uint8_t))); #endif QWidget::connect( GlobalState::instance()._ncValuesState, &NcValuesState::ncValuesSourceChanged, this, &ValueStackedWidget::setNcValuesSource ); // Initialize based on current UserInterfaceOptionsState value bool initialControlKeyRequired = GlobalState::instance()._uiOptionsState->_controlKeyRequired; TRACECF(debug, "calling setInstanceControlKeyRequired(%s)", SBOOL(initialControlKeyRequired)); setInstanceControlKeyRequired(initialControlKeyRequired); #ifdef NOT_NEEDED QWidget::connect( GlobalState::instance()._mainWindow, &MainWindow::signalControlKeyRequired, this, &ValueStackedWidget::setInstanceControlKeyRequired ); #endif QWidget::connect( GlobalState::instance()._uiOptionsState, &UserInterfaceOptionsState::controlKeyRequired_changed, this, &ValueStackedWidget::setInstanceControlKeyRequired ); QWidget::connect( GlobalState::instance()._mainWindow, &MainWindow::signalControlKeyPressed, this, &ValueStackedWidget::setInstanceControlKeyPressed ); TRACECF(debug, "Done."); } ValueStackedWidget::~ValueStackedWidget() { free((void*) _cls); } void ValueStackedWidget::enableSubwidgets() { bool debug = false; bool enabled = !_instanceControlKeyRequired || _instanceControlKeyPressed; TRACEMCF(debug, "_id=%d, _pageno_selected=%d, calling setEnabled(%s) for subwidgets", _id, _pageno_selected, SBOOL(enabled)); for (int ndx = 0; ndx < _subwidgetCt; ndx++) { _subwidget[ndx]->setEnabled(enabled); } // if called during initial setup, _cur_stacked_widget apparently wrong // _cur_stacked_widget->setEnabled(enabled); TRACEMCF(debug, "Done."); } // slot void ValueStackedWidget::setInstanceControlKeyRequired(bool onoff) { bool debug = false; debug = debug | debugValueWidgetSignals; TRACEMCF(debug, "_id=%d, _pageno_selected=%d, onoff=%s", _id, _pageno_selected, SBOOL(onoff)); _instanceControlKeyRequired = onoff; enableSubwidgets(); TRACEMCF(debug, "Done."); } void ValueStackedWidget::setInstanceControlKeyPressed(bool onoff) { bool debug = false; debug = debug | debugValueWidgetSignals; TRACEMCF(debug, "_id=%d, _pageno_selected=%d, onoff=%s", _id, _pageno_selected, SBOOL(onoff)); _instanceControlKeyPressed = onoff; enableSubwidgets(); TRACEMCF(debug, "Done."); } bool vspec_eq(DDCA_MCCS_Version_Spec vspec1, DDCA_MCCS_Version_Spec vspec2) { bool result = false; if (vspec1.major == vspec2.major && vspec1.minor == vspec2.minor) result = true; return result; } void ValueStackedWidget::setFeatureValue(const FeatureValue &fv) { bool debug = false; // debug = debug || (fv.featureCode() == 0xdf); // debug = debug || (fv.featureCode() == 0x14); debug = debug || debugValueWidgetSignals; TRACEMCF(debug, "Starting. this._id=%d, feature code: 0x%02x", _id, fv.featureCode()); // if (debug) // fv.dbgrpt(); // ValueBaseWidget::setFeatureValue(fv); _featureCode = fv.featureCode(); // needed since not calling ValueBaseWidget::setFeatureValue() DDCA_MCCS_Version_Spec vspec = fv.vspec(); // unused if (fv.ddcrc() != 0) { // use the default standard widget, set in constructor } // alt, test for PRESET, then xb0 (settings) or normal else if ( _featureCode == 0x04 || // Restore factory defaults _featureCode == 0x05 || // Restore factory brightness/contrast defaults _featureCode == 0x06 || // Restore factory geometry defaults _featureCode == 0x08 || // Restore factory color defaults _featureCode == 0x0a ) // Restore factory TV defaults { _pageno_selected = _pageno_reset; // setCurrentIndex(_pageno_reset); setCurrentWidget(_resetWidget); _cur_stacked_widget = _resetWidget; } else if (_featureCode == 0x0c) { // fv.flags marks it as DDCA_COMPLEX_CONT, but just treat it a normal continuous feature // printf("(ValueStackedWidget::%s) x0c\n", __func__); fflush(stdout); _pageno_selected = _pageno_cont; _cur_stacked_widget = _newContWidget; // setCurrentIndex(_pageno_selected); setCurrentWidget(_cur_stacked_widget); } else if (_featureCode == 0x14) { TRACEMCF(debug, "_feature_code == 0x14"); _pageno_selected = _pageno_ncplus; _cur_stacked_widget = _ncplusWidget; setCurrentWidget(_cur_stacked_widget); } else if (_featureCode == 0x62 // Audio volume && (vspec_eq(vspec, DDCA_VSPEC_V30) || vspec_eq(vspec, DDCA_VSPEC_V22) ) ) { // TRACEC( "setting _specialWidgetX62"); _pageno_selected = _pageno_x62; _cur_stacked_widget = _specialWidgetX62; // setCurrentIndex(_pageno_selected); setCurrentWidget(_cur_stacked_widget); } else if ( (vspec_eq(vspec, DDCA_VSPEC_V30) || vspec_eq(vspec, DDCA_VSPEC_V22) ) && ( _featureCode == 0x8f || // Audio Treble _featureCode == 0x91 || // Audio Bass _featureCode == 0x93 ) // Audio Balance ) { _pageno_selected = _pageno_simple_cont; _cur_stacked_widget = _simpleContWidget; // setCurrentIndex(_pageno_simple_cont); setCurrentWidget(_cur_stacked_widget); if (_featureCode == 0x93) _simpleContWidget->setRange(0x01, 0xfe); else _simpleContWidget->setRange(0x01, 0xff); } else if (_featureCode == 0xb0) { // printf("(%s::%s) B0\n", _cls, __func__); _2ButtonWidget->setButtonDetail( QString("Store"), 1, QString("Restore"), 2); _pageno_selected = _pageno_2button; _cur_stacked_widget = _2ButtonWidget; setCurrentWidget(_cur_stacked_widget); } else if ( _featureCode == 0xca) { _pageno_selected = _pageno_ncplus;; _cur_stacked_widget = _ncplusWidget; // setCurrentIndex(_pageno_ncplus); setCurrentWidget(_cur_stacked_widget); } else if ( _featureCode >= 0xe0) { // DDCA_Cap_Vcp * capvcp = fv.capVcp(); // TRACEMC("feature 0x%02x, capvcp = %p", _featureCode, capvcp); // TRACEMC("feature 0x%02x, value count %d", _featureCode, fv.capVcp()->value_ct); #ifdef TOO_MANY_EDGE_CASES if (capvcp && capvcp->value_ct > 0) { // segfaults if use fv.capvcp() instead of capvcp TRACEMC("capabilities string for feature 0x%02x has vcp value list, treat it as simple NC", _featureCode); _pageno_selected = _pageno_nc; _cur_stacked_widget = _ncWidget; setCurrentWidget(_cur_stacked_widget); } else { #endif _pageno_selected = _pageno_bytes; _cur_stacked_widget = _bytesWidget; // setCurrentIndex(_pageno_bytes); setCurrentWidget(_cur_stacked_widget); #ifdef TOO_MANY_EDIGE_CASES } #endif } #ifdef OUT // *** temp for comparison *** else if (_featureCode == 0x12 || _featureCode == 0x16 ) { _pageno_selected = _pageno_old_cont; _cur_stacked_widget = _contWidget; // setCurrentIndex(_pageno_selected); setCurrentWidget(_cur_stacked_widget); } #endif else if (fv.flags() & DDCA_STD_CONT) { // printf("(ValueStackedWidget::%s) DDCA_STD_CONT\n", __func__); fflush(stdout); _pageno_selected = _pageno_cont; _cur_stacked_widget = _newContWidget; // setCurrentIndex(_pageno_selected); setCurrentWidget(_cur_stacked_widget); } else if ( (fv.flags() & DDCA_SIMPLE_NC) && (fv.flags() & DDCA_WRITABLE) ) { TRACEMCF(debug, "DDCA_SIMPLE_NC"); _pageno_selected = _pageno_nc; _cur_stacked_widget = _ncWidget; // setCurrentIndex(_pageno_selected); setCurrentWidget(_cur_stacked_widget); } else { TRACEMCF(debug, "default case, _stdWidget"); _pageno_selected = _pageno_std; // setCurrentIndex(_pageno_selected); _cur_stacked_widget = _stdWidget; setCurrentWidget(_cur_stacked_widget); } #ifdef NO if (_pageno_selected == _pageno_nc || _pageno_selected == _pageno_ncplus) { QWidget::connect(GlobalState::instance()._ncValuesState, &NcValuesState::ncValuesSourceChanged, _ncWidget, &ValueNcWidget::reloadComboBox ); } else if (_pageno_selected == _pageno_ncplus) { QWidget::connect(GlobalState::instance()._ncValuesState, &NcValuesState::ncValuesSourceChanged, _ncplusWidget, &ValueNcWidget::reloadComboBox ); } #endif TRACECF(debug, "Calling _cur_stacked_widget->setFeatureValue(), _pageno_selected=%d", _pageno_selected ); _cur_stacked_widget->setFeatureValue(fv); TRACECF(debug, "Done"); } void ValueStackedWidget::setCurrentValue(uint16_t newval) { _cur_stacked_widget->setCurrentShSl(newval); } #ifdef UNUSED uint16_t ValueStackedWidget::getCurrentValue() { return _cur_stacked_widget->getCurrentValue(); } #endif // QSize ValueStackedWidget::sizeHint() const { // // printf("(%s::%s) Starting\n", _cls, __func__); fflush(stdout); // return QSize(100,50); // ??? // } void ValueStackedWidget::forContainedWidgetChanged(uint8_t feature_code, uint8_t sh, uint8_t sl) { bool debug = false; debug = debug || debugValueWidgetSignals; TRACECF(debug, "feature_code=0x%02x, sh=0x%02x, sl=0x%02x", feature_code, sh, sl); assert(feature_code == _featureCode); TRACECF(debug, "-> Calling emit stackedFeatureValueChanged(), feature_code=0x%02x, sh=0x%02x, sl=0x%02x", feature_code, sh, sl); emit stackedFeatureValueChanged(feature_code, sh, sl); // printf("(%s::%s) Calling simpleFeatueValueNotify() \n", _cls, __func__); fflush(stdout); // simpleFeatureValueNotify(SimpleFeatureValue(feature_code, sh, sl)); } #ifdef NC_FEATURE_VALUES2 bool ValueStackedWidget::hasSlTable() { bool result = (_pageno_selected == _pageno_nc || _pageno_selected == _pageno_ncplus); return result; } #endif void ValueStackedWidget::setNcValuesSource(NcValuesSource newValuesSource, bool newUseLatestNcValueNames) { bool debug = false; debug = debug || debugNcValues; TRACECF(debug, "newValuesSource=%d, newUseLatestNcValueNames=%s, _pageno_selected=%d, _pageno_nc=%d, _pageno_ncplus=%d", newValuesSource, SBOOL(newUseLatestNcValueNames), _pageno_selected, _pageno_nc, _pageno_ncplus); // if (_pageno_selected == _pageno_nc) { if (_cur_stacked_widget == _ncWidget) { _ncWidget->reloadComboBox(newValuesSource, newUseLatestNcValueNames); } // else if (_pageno_selected == _pageno_ncplus) { else if (_cur_stacked_widget == _ncplusWidget) { _ncplusWidget->reloadComboBox(newValuesSource, newUseLatestNcValueNames); } TRACECF(debug, "Done"); } ddcui-0.3.0/src/feature_value_widgets/value_stacked_widget.h000066400000000000000000000053771427175135000243150ustar00rootroot00000000000000/** @file value_stacked_widget.h */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_STACKED_WIDGET_H #define VALUE_STACKED_WIDGET_H #include #include "value_2button_widget.h" #include "value_base_widget.h" #include "value_bytes_widget.h" #include "value_cnc_widget_x14.h" #include "value_nc_widget.h" #include "value_ncplus_widget.h" #include "value_new_cont_widget.h" #include "value_reset_widget.h" #include "value_special_widget_x62.h" #include "value_std_widget.h" class QWidget; class QPaintEvent; class ValueStackedWidget : public QStackedWidget { Q_OBJECT public: explicit ValueStackedWidget(QWidget *parent = nullptr); ~ValueStackedWidget(); void setFeatureValue(const FeatureValue &fv); void setCurrentValue(uint16_t newval); // uint16_t getCurrentValue(); #ifdef NC_FEATURE_VALUES2 bool hasSlTable(); #endif public slots: void setNcValuesSource(NcValuesSource newsrc, bool newUseLatestNames); void setInstanceControlKeyRequired(bool onoff); void setInstanceControlKeyPressed(bool onoff); // QSize sizeHint() const override; // void paintEvent(QPaintEvent *event) override; signals: void stackedFeatureValueChanged(uint8_t feature_code, uint8_t sh, uint8_t sl); private slots: void forContainedWidgetChanged(uint8_t feature_code, uint8_t sh, uint8_t sl); private: void enableSubwidgets(); protected: static int nextId; private: const char * _cls; int _id; uint8_t _featureCode; int _pageno_selected; ValueBaseWidget* _cur_stacked_widget; int _pageno_std; int _pageno_cont; int _pageno_simple_cont; int _pageno_nc; int _pageno_reset; int _pageno_2button; int _pageno_x14; int _pageno_bytes; int _pageno_ncplus; int _pageno_x62; ValueStdWidget* _stdWidget; ValueNewContWidget* _newContWidget; ValueSimpleContWidget* _simpleContWidget; ValueNcWidget* _ncWidget; ValueResetWidget* _resetWidget; Value2ButtonWidget* _2ButtonWidget; ValueCncWidgetX14* _cncWidgetX14; ValueBytesWidget* _bytesWidget; ValueNcplusWidget* _ncplusWidget; ValueSpecialWidgetX62* _specialWidgetX62; ValueBaseWidget * _subwidget[10]; int _subwidgetCt = 0; bool _instanceControlKeyRequired = false; bool _instanceControlKeyPressed = false; }; #endif // VALUE_STACKED_WIDGET_H ddcui-0.3.0/src/feature_value_widgets/value_std_widget.cpp000066400000000000000000000155531427175135000240210ustar00rootroot00000000000000/** \file value_std_widget.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include "ddcutil_status_codes.h" #include "ddcutil_c_api.h" #include "base/core.h" #include "base/feature_selector.h" #include "base/widget_debug.h" #include "feature_value_widgets/value_std_widget.h" static bool showDimensionReport = false; static bool showBasicDims = false || debugFeatureDimensions; static bool showResizeEvents = false; void ValueStdWidget::layoutWidget() { // QFont font; // font.setPointSize(8); // QWidget::setFont(font); _valueField = new QLabel(); _valueField->setAlignment(Qt::AlignLeft); // _valueField->setFrameStyle(QFrame::Sunken | QFrame::Panel); // now set in ValueBaseWidget _valueField->setMinimumSize(400,10); _valueField->setFrameStyle( QFrame::Plain | QFrame::NoFrame); // ValueStdWidget has the frame, not Label // _valueField->setFont(font); _valueField->setFont(FeatureValueTextFont); _valueField->setIndent(5); #ifdef COMPILE_ERROR QSizePolicy& sp(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); sp.setHorizontalStretch(1); _valueField->setSizePolicy(sp); #endif QSizePolicy* sizePolicy = new QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); sizePolicy->setHorizontalStretch(1); _valueField->setSizePolicy(*sizePolicy); delete sizePolicy; QHBoxLayout * layout = new QHBoxLayout(); layout->setContentsMargins(0,0,0,0); layout->addSpacing(5); layout->addWidget(_valueField); setLayout(layout); if (debugLayout) { this->setStyleSheet("background-color:magenta;"); static bool dimensionReportShown = false; if (showDimensionReport && !dimensionReportShown) { TRACEC("_valueField dimensions"); reportWidgetDimensions(_valueField, _cls, __func__); TRACEC("ValueStdWidget dimensions"); reportWidgetDimensions(this, _cls, __func__); dimensionReportShown = true; } } static bool basicDimsShown = false; if (showBasicDims && !basicDimsShown) { REPORT_BASIC_WIDGET_DIMENSIONS(this); REPORT_BASIC_WIDGET_DIMENSIONS(this->_valueField); #ifdef TMI QObjectList childs = this->children(); for (int ndx = 0; ndx < childs.size(); ndx++) { QObject* curobj = childs.at(ndx); QString name = curobj->objectName(); const char * clsName = curobj->metaObject()->className(); printf(" Child: %s, type:%s\n", name.toLatin1().data(), clsName); } fflush(stdout); #endif basicDimsShown = true; } } ValueStdWidget::ValueStdWidget(QWidget *parent): ValueBaseWidget(parent) { bool debug = false; _cls = strdup(metaObject()->className()); // TRACE("Starting"); layoutWidget(); TRACEMCF(debug, "TRACECMF. After superclass call"); } ValueStdWidget::~ValueStdWidget() { free((void*) _cls); delete _valueField; } void ValueStdWidget::setValueField() { char * s_formatted = NULL; if (_ddcrc == 0) { DDCA_Non_Table_Vcp_Value valrec; valrec.mh = _mh; valrec.ml = _ml; valrec.sh = _sh; valrec.sl = _sl; // TRACE("Before calling ddca_format_non_table_vcp_value_by_dref() _featureCode=0x%02x", _featureCode); DDCA_Status rc = ddca_format_non_table_vcp_value_by_dref( _featureCode, _dref, &valrec, &s_formatted); // TRACE("ddca_format_non_table_vcp_value_by_dref() returned %d, s_formatted=%s", rc, s_formatted); if (rc != 0) s_formatted = strdup((char*) "invalid formatted value"); // cast to avoid compiler warning _valueField->setText(QString::fromUtf8(s_formatted)); free(s_formatted); } else { // need to make check at higher level where ValueStackedWidget is added to layout // need to check showUnimplementd if (_ddcrc == DDCRC_REPORTED_UNSUPPORTED || _ddcrc == DDCRC_DETERMINED_UNSUPPORTED) { FeatureSelector * fsel = _globalState._mainWindow->_feature_selector; bool showUnsupported = fsel->_showUnsupportedFeatures; // TRACEC("showUnsupported = %s", sbool(showUnsupported)); if (showUnsupported) { // TODO: Use QString !!! s_formatted = (char*) "Unsupported feature"; _valueField->setText(QString::fromUtf8(s_formatted)); } } else { // for shorter msg - ddca_rc_name() QString msg = QString::asprintf("DDC Error. Status code = %s - %s", ddca_rc_name(_ddcrc), ddca_rc_desc(_ddcrc)); _valueField->setText(msg); _valueField->setStyleSheet("color:red;"); } } } void ValueStdWidget::setFeatureValue(const FeatureValue &fv) { // n.b. does not invoke superclass method bool debug = false; debug = debug || debugValueWidgetSignals; TRACEMCF(debug, "featureCode=0x%02x, capVcp=%p, ddcrc=%d, Before ValueBaseWidget::setFeatureValue() call", fv.featureCode(), fv.capVcp(), fv.ddcrc()); ValueBaseWidget::setFeatureValue(fv); setValueField(); } void ValueStdWidget::setCurrentShSl(uint16_t newval) { ValueBaseWidget::setCurrentShSl(newval); setValueField(); } void ValueStdWidget::setEnabled(bool onoff) { bool debug = false; TRACEMCF(debug, "Executing. _id=%d", _id); } #ifdef DEBUG_PAINT void ValueStdWidget::paintEvent(QPaintEvent *event) { // printf("(%s::%s) Starting\n", _cls, __func__); fflush(stdout); const QRect rect = event->rect(); // const QRegion = event->region(); int x; int y; int width; int height; rect.getRect(&x, &y, &width, &height); printf("(ValueStdWidget::%s) event rectangle: x:%d, y:%d, width:%d, height:%d\n", __func__, x, y, width, height); fflush(stdout); this->ValueBaseWidget::paintEvent(event); } #endif void ValueStdWidget::resizeEvent(QResizeEvent * evt) { bool show = false; QSize oldSz = evt->oldSize(); QSize newSz = evt->size(); static bool sizeShown = false; if (showResizeEvents && !sizeShown) { show = true; sizeShown = true; } #ifdef ALT int oldWidth = oldSz.width(); int oldHeight = oldSz.height(); int newWidth = newSz.width(); int newHeight = newSz.width(); if (oldHeight != newHeight || oldWidth != newWidth) { show = true; } #endif if (show) { TRACEC("old size = %d, %d", oldSz.width(), oldSz.height()); TRACEC("new size = %d, %d", newSz.width(), newSz.height()); } evt->ignore(); } ddcui-0.3.0/src/feature_value_widgets/value_std_widget.h000066400000000000000000000015741427175135000234640ustar00rootroot00000000000000/* value_std_widget.h - Widget for displaying a formatted VCP feature value */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VALUE_STD_WIDGET_H #define VALUE_STD_WIDGET_H #include #include #include "feature_value_widgets/value_base_widget.h" class ValueStdWidget : public ValueBaseWidget { Q_OBJECT public: ValueStdWidget(QWidget *parent = nullptr); ~ValueStdWidget(); void setFeatureValue(const FeatureValue &fv) override; void setCurrentShSl(uint16_t newval) override; public slots: void setEnabled(bool onoff) override; protected: void resizeEvent(QResizeEvent * evt) override; private: void layoutWidget(); void setValueField(); private: const char * _cls; QLabel * _valueField; }; #endif // VALUE_STD_WIDGET_H ddcui-0.3.0/src/help/000077500000000000000000000000001427175135000143265ustar00rootroot00000000000000ddcui-0.3.0/src/help/help_browser.cpp000066400000000000000000000076701427175135000175370ustar00rootroot00000000000000// help_browser.cpp // Copyright (C) 2020-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // Adapted from C++ GUI Programming With Qt 4 #include #include #include #include #include #include "base/core.h" #include "help/help_browser.h" #ifdef DEBUG static void dbgrptQKeyEvent(QKeyEvent * event) { printf(" key: %d\n", event->key()); printf(" modifiers: 0x%x\n", (unsigned int) event->modifiers()); printf(" nativeModifiers: 0x%08x\n", event->nativeModifiers()); printf(" nativeScanCode: 0x%08x\n", event->nativeScanCode()); } #endif void HelpBrowser::showPage(const QString& page, bool navigable) { HelpBrowser * browser = new HelpBrowser(page, navigable); browser->resize(600,400); // browser->setMinimumSize(600,400); browser->show(); } void HelpBrowser::createWidgets(bool navigable) { _textBrowser = new QTextBrowser; if (navigable) { _homeButton = new QPushButton("&Home"); _homeButton->setShortcut(tr("H")); _backButton = new QPushButton("&Back"); _backButton->setShortcut(tr("B")); } // _closeButton = new QPushButton(QDialogButtonBox::Close); // doesn't compile _closeButton = new QPushButton("&Close"); _closeButton->setShortcut(tr("Esc")); _closeButton->setShortcut(tr("C")); _closeButton->setDefault(true); } #ifdef FAILURE void HelpBrowser::layoutWidgets(bool navigable) { _buttonBox = new QDialogButtonBox(); // _buttonBox->addButton(_backButton,QDialogButtonBox::InvalidRole); // _buttonBox->addButton(_homeButton); _buttonBox->addButton("Close2", QDialogButtonBox::RejectRole); _closeButton = _buttonBox->addButton(QDialogButtonBox::Close); #ifdef OLD QHBoxLayout* buttonLayout = new QHBoxLayout(); if (navigable) { buttonLayout->addWidget(_backButton); buttonLayout->addWidget(_homeButton); } buttonLayout->addStretch(); buttonLayout->addWidget(_closeButton); #endif QVBoxLayout* mainLayout = new QVBoxLayout(); mainLayout->addWidget(_textBrowser); #ifdef OLD mainLayout->addLayout(buttonLayout); #endif mainLayout->addWidget(_buttonBox); setLayout(mainLayout); } #endif void HelpBrowser::layoutWidgets(bool navigable) { QHBoxLayout* buttonLayout = new QHBoxLayout(); if (navigable) { buttonLayout->addWidget(_backButton); buttonLayout->addWidget(_homeButton); } buttonLayout->addStretch(); buttonLayout->addWidget(_closeButton); QVBoxLayout* mainLayout = new QVBoxLayout(); mainLayout->addWidget(_textBrowser); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); } HelpBrowser::HelpBrowser( const QString& page, bool navigable, QWidget* parent) : QWidget(parent) { // TRACEM("Starting. page=%s, navigable=%s", QS2S(page), SBOOL(navigable)); createWidgets(navigable); layoutWidgets(navigable); setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_GroupLeader); // setWindowModality(Qt::ApplicationModal); // choices: Qt::NonModal, Qt::WindowModal, Qt::ApplicationModal if (navigable) { QObject::connect(_homeButton, &QPushButton::clicked, _textBrowser, &QTextBrowser::home); QObject::connect(_backButton, &QPushButton::clicked, _textBrowser, &QTextBrowser::backward); } QObject::connect( _closeButton, &QPushButton::clicked, this, &QTextBrowser::close); QObject::connect( _textBrowser, &QTextBrowser::sourceChanged, this, &HelpBrowser::updateWindowTitle); _textBrowser->setSource(page); } void HelpBrowser::updateWindowTitle() { this->setWindowTitle(tr("Help: %1").arg(_textBrowser->documentTitle())); } void HelpBrowser::keyPressEvent(QKeyEvent * ev) { // dbgrptQKeyEvent(ev); if (ev->key() == Qt::Key_Escape || ev->key() == Qt::Key_Return || ev->key() == Qt::Key_Enter) { close(); } ev->ignore(); } ddcui-0.3.0/src/help/help_browser.h000066400000000000000000000016301427175135000171720ustar00rootroot00000000000000// help_browser.h // Copyright (C) 2020-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #ifndef HELP_BROWSER_H_ #define HELP_BROWSER_H_ class HelpBrowser : public QWidget { Q_OBJECT public: HelpBrowser(const QString& page, bool navigable, QWidget* parent = 0); static void showPage(const QString& page, bool navigable); private slots: void updateWindowTitle(); protected: void keyPressEvent(QKeyEvent * ev) override; private: //methods void createWidgets(bool navigable); void layoutWidgets(bool navigable); private: QTextBrowser * _textBrowser; QPushButton * _homeButton; QPushButton * _backButton; QPushButton * _closeButton; QDialogButtonBox * _buttonBox; }; #endif /* HELP_BROWSER_H_ */ ddcui-0.3.0/src/help/help_dialog.cpp000066400000000000000000000076351427175135000173140ustar00rootroot00000000000000// help_dialog.cpp // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include "base/core.h" #include "help_dialog.h" void HelpDialog::createWidgets() { _textBrowser = new QTextBrowser; _textBrowser->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); _textBrowser->setContextMenuPolicy(Qt::PreventContextMenu); _buttons = new QDialogButtonBox(QDialogButtonBox::Ok); } void HelpDialog::layoutWidgets() { setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_GroupLeader); Qt::WindowFlags flags = windowFlags(); flags &= ~Qt::WindowContextHelpButtonHint; setWindowFlags(flags); QVBoxLayout* mainLayout = new QVBoxLayout(); mainLayout->addWidget(_textBrowser); mainLayout->addWidget(_buttons); setLayout(mainLayout); setMinimumSize(600,400); } void HelpDialog::connectWidgets() { // QMetaObject::connect_slots_by_name(this); QObject::connect(_buttons, &QDialogButtonBox::rejected, this, &HelpDialog::on_buttonBox_rejected); QObject::connect(_buttons, &QDialogButtonBox::accepted, this, &HelpDialog::on_buttonBox_accepted); QObject::connect(_textBrowser, &QTextBrowser::sourceChanged, this, &HelpDialog::updateWindowTitle); } void HelpDialog::commonInit() { createWidgets(); layoutWidgets(); connectWidgets(); } HelpDialog::HelpDialog(QWidget* parent) : QDialog(parent) ,_cls(strdup(metaObject()->className() )) { commonInit(); } HelpDialog::HelpDialog(QString title, QString& htmlText, QWidget* parent) : QDialog(parent) ,_cls(strdup(metaObject()->className()) ) { TRACEC("title=%s, htmlText=%s", QS2S(title), QS2S(htmlText)); commonInit(); setWindowTitle(title); _textBrowser->setText(htmlText); show(); // not showing - why? } #ifdef UNFINISHED HelpDialog::HelpDialog(char * simpleFn, char * title, QWidget* parent) : QDialog(parent) ,_cls(strdup(metaObject()->className()) ) { commonInit(); setWindowtitle(title); } #endif HelpDialog::~HelpDialog() { free(_cls); delete _buttons; delete _textBrowser; } void HelpDialog::setText(QString& htmlText) { _textBrowser->setText(htmlText); } void HelpDialog::setSource(const char * source) { // TRACEC("Source: %s", source); _textBrowser->setSource(QUrl(source)); } // doesn't occur - there's only a Cancel button // but referenced in generated UI code void HelpDialog::on_buttonBox_accepted() { // TRACEC("Executing"); this->close(); } void HelpDialog::on_buttonBox_rejected() { // TRACEC("Executing"); this->close(); } // // Static methods // void HelpDialog::viewHelpByText(QString text, QString title, QWidget * parent) { HelpDialog* hd = new HelpDialog(parent); hd->setText(text); // hd->_textBrowser->setSource(fn); hd->setWindowTitle( title ); hd->exec(); } void HelpDialog::viewHelpByTextX(QString text, QString title, QFont font,QWidget * parent) { HelpDialog* hd = new HelpDialog(parent); hd->setFont(font); hd->setText(text); // hd->_textBrowser->setSource(fn); hd->setWindowTitle( title ); hd->exec(); // always modal } void HelpDialog::viewResourceHelp(QString simpleFn, QString title, QWidget * parent) { // QString fn = QString(simpleFn).prepend(":/docs/"); QUrl fn = QString("qrc:/docs/").append(simpleFn); #ifdef OLD QFile f(fn); f.open(QFile::ReadOnly | QFile::Text); QTextStream in(&f); QString htmlText = in.readAll(); // qDebug() << htmlText; HelpDialog* hd = new HelpDialog(parent); hd->setText(htmlText); #endif HelpDialog* hd = new HelpDialog(parent); hd->_textBrowser->setSource(fn); // hd->setWindowTitle( title ); hd->exec(); // delete hd; } void HelpDialog::updateWindowTitle() { setWindowTitle(tr("Help: %1").arg(_textBrowser->documentTitle())); } ddcui-0.3.0/src/help/help_dialog.h000066400000000000000000000025121427175135000167460ustar00rootroot00000000000000/** \file help_dialog.h */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef HELP_DIALOG_H_ #define HELP_DIALOG_H_ #include #include #include class QTextBrowser; class HelpDialog : public QDialog { Q_OBJECT public: static void viewResourceHelp(QString simpleFn, QString title, QWidget * parent = nullptr); static void viewHelpByText(QString text, QString title, QWidget * parent = nullptr); static void viewHelpByTextX(QString text, QString title, QFont font, QWidget *parent=nullptr); explicit HelpDialog(QWidget *parent = 0); HelpDialog( QString title, QString& htmlText, QWidget *parent = 0); #ifdef UNFINISHED HelpDialog(char * title, char * simpleFn, QWidget* parent) { #endif ~HelpDialog(); void setText(QString& htmlText); void setSource(const char * source); private slots: void on_buttonBox_accepted(); void on_buttonBox_rejected(); void updateWindowTitle(); private: // methods void createWidgets(); void layoutWidgets(); void connectWidgets(); void commonInit(); private: // member variables char * _cls; QTextBrowser* _textBrowser; QDialogButtonBox* _buttons; }; #endif /* HELP_DIALOG_H_ */ ddcui-0.3.0/src/help/help_dialog3.cpp000066400000000000000000000005221427175135000173630ustar00rootroot00000000000000// help_dialog3.cpp // Variant of HelpDialog that uses QTCreator to create dialog box // Incomplete - Do not use #include "help_dialog3.h" #include "ui_help_dialog3.h" HelpDialog3::HelpDialog3(QWidget *parent) : QDialog(parent), ui(new Ui::HelpDialog3) { ui->setupUi(this); } HelpDialog3::~HelpDialog3() { delete ui; } ddcui-0.3.0/src/help/help_dialog3.h000066400000000000000000000004541427175135000170340ustar00rootroot00000000000000#ifndef HELP_DIALOG3_H #define HELP_DIALOG3_H #include namespace Ui { class HelpDialog3; } class HelpDialog3 : public QDialog { Q_OBJECT public: explicit HelpDialog3(QWidget *parent = nullptr); ~HelpDialog3(); private: Ui::HelpDialog3 *ui; }; #endif // HELP_DIALOG3_H ddcui-0.3.0/src/help/help_dialog3.ui000066400000000000000000000027171427175135000172260ustar00rootroot00000000000000 HelpDialog3 0 0 400 300 Dialog 30 240 341 32 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() HelpDialog3 accept() 248 254 157 274 buttonBox rejected() HelpDialog3 reject() 316 260 286 274 ddcui-0.3.0/src/help/old/000077500000000000000000000000001427175135000151045ustar00rootroot00000000000000ddcui-0.3.0/src/help/old/help_dialog0.cpp000066400000000000000000000003401427175135000201340ustar00rootroot00000000000000#include "help_dialog0.h" #include "ui_help_dialog0.h" HelpDialog0::HelpDialog0(QWidget *parent) : QDialog(parent), ui(new Ui::HelpDialog0) { ui->setupUi(this); } HelpDialog0::~HelpDialog0() { delete ui; } ddcui-0.3.0/src/help/old/help_dialog0.h000066400000000000000000000004601427175135000176040ustar00rootroot00000000000000#ifndef HELP_DIALOG0_H #define HELP_DIALOG0_H #include namespace Ui { class HelpDialog0; } class HelpDialog0 : public QDialog { Q_OBJECT public: explicit HelpDialog0(QWidget *parent = 0); ~HelpDialog0(); private: Ui::HelpDialog0 *ui; }; #endif // HELP_DIALOG0_H ddcui-0.3.0/src/help/old/help_dialog0.ui000066400000000000000000000013201427175135000177660ustar00rootroot00000000000000 HelpDialog0 0 0 400 300 Dialog 5 31 391 251 271 251 ddcui-0.3.0/src/main/000077500000000000000000000000001427175135000143225ustar00rootroot00000000000000ddcui-0.3.0/src/main/main.cpp000066400000000000000000000277761427175135000157750ustar00rootroot00000000000000/** \file main.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include extern "C" { #include "c_util/debug_util.h" #include "c_util/ddcutil_config_file.h" #include "c_util/simple_ini_file.h" #include "c_util/string_util.h" #include "c_util/xdg_util.h" #include "cmdline/ddcui_parsed_cmd.h" #include "cmdline/ddcui_cmd_parser.h" } #include "base/ddcui_parms.h" #include "base/global_state.h" #include "base/core.h" #include "main/msgbox_thread.h" #include "main/mainwindow.h" /* See: https://www.qt.io/blog/2016/01/26/high-dpi-support-in-qt-5-6 */ void dbgrpt_hidpi_environment_vars() { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QStringList varnames = { "QT_AUTO_SCREEN_SCALE_FACTOR", "QT_SCALE_FACTOR", "QT_SCREEN_SCALE_FACTORS", "QT_ENABLE_HIGHDPI_SCALING", "QT_DEVICE_PIXEL_RATIO" // introduced 5.4, deprecated 5.6 }; for (int ndx = 0; ndx < varnames.size(); ndx++) { QString curvar= varnames.at(ndx); QString curval = env.value(curvar, "not set"); printf("%s = %s\n", QS2S(curvar), QS2S(curval)); } } const int TitleColumnSize = 25; void qrpt_Qstring(QString name, QString val) { printf(" %-*s: %s\n", TitleColumnSize, QS2S(name), QS2S(val)); } void qrpt_QSizef(QString name, QSizeF val) { qreal h = val.height(); qreal w = val.width(); printf(" %-*s: w = %f, h=%f\n", TitleColumnSize, QS2S(name), w, h); } void qrpt_qreal(QString name, qreal val) { printf(" %-*s: %f\n", TitleColumnSize, QS2S(name), val); } void qrpt_int(QString name, int val) { printf(" %-*s: %d\n", TitleColumnSize, QS2S(name), val); } void qrpt_QRect(QString name, QRect val) { int h = val.height(); int w = val.width(); int l = val.left(); int r = val.right(); printf(" %-*s: w = %d, h=%d, l=%d, r=%d\n", TitleColumnSize, QS2S(name), w, h, l, r); } void qrpt_QSize(QString name, QSize val) { int h = val.height(); int w = val.width(); printf(" %-*s: w = %d, h=%d\n", TitleColumnSize, QS2S(name), w, h); } void dbgrptQScreen(QScreen * screen) { QString s = screen->name(); // on X11, XRandr screen names qrpt_Qstring("name", s); #if QT_VERSION >= QT_VERSION_CHECK(5,9,0) s = screen->manufacturer(); // 5.9 qrpt_Qstring("manufacturer", s); s = screen->model(); // 5.9 qrpt_Qstring("model", s); s = screen->serialNumber(); // 5.9 qrpt_Qstring("serialNumber", s); #endif QSizeF sizef = screen->physicalSize(); qrpt_QSizef("physicalSize", sizef); QRect rect = screen->geometry(); rect = screen->availableGeometry(); qrpt_QRect("geometry", rect); rect = screen->availableVirtualGeometry(); qrpt_QRect("availableVirtualGeometry", rect); rect = screen->virtualGeometry(); qrpt_QRect("virtualGeometry", rect); QSize size = screen->size(); size = screen->availableSize(); size = screen->availableVirtualSize(); size = screen->virtualSize(); qreal r = screen->devicePixelRatio(); qrpt_qreal("devicePixelRatio", r); /* From https://github.com/owncloud/client/issues/5000: You can't rely on screen DPI there are a huge bunch of samsung monitors that get mm and inches swapped so the auto DPI is huge. I do the Plasma High DPI and we don't use this because the feedback we got is that it simply doesn't work. Also it messes with Plasma which manually sets the scale factor based on the user's settings. There is an alternate method to acheive the same result for you. qApp->setAttribute(Qt::AA_EnableHighDpiScaling, true); This will act the same as: qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); if and only if no other env vars are set. */ r = screen->logicalDotsPerInch(); // average of logicalDotsPerInchX, logicalDotsPerInchY qrpt_qreal("logicalDotsPerInch", r); r = screen->logicalDotsPerInchX(); qrpt_qreal("logicalDotsPerInchX", r); r = screen->logicalDotsPerInchY(); qrpt_qreal("logicalDotsPerInchY", r); r = screen->physicalDotsPerInch(); //average of X, Y qrpt_qreal("physicalDotsPerInch", r); r = screen->physicalDotsPerInchX(); qrpt_qreal("physicalDotsPerInchX", r); r = screen->physicalDotsPerInchY(); qrpt_qreal("physicalDotsPerInchY", r); int i = screen->depth(); // color depth qrpt_int("depth", i); } void dbgrpt_hidpiQApplication(QApplication& coreapp) { bool b = coreapp.testAttribute(Qt::AA_Use96Dpi); printf("AA_Use96Dpi: %s\n", SBOOL(b)); b = coreapp.testAttribute(Qt::AA_EnableHighDpiScaling); printf("AA_EnableHighDPIscaling: %s\n", SBOOL(b)); b = coreapp.testAttribute(Qt::AA_DisableHighDpiScaling); printf("AA_DisableHighDPIscaling: %s\n", SBOOL(b)); QScreen * primaryScreen = coreapp.primaryScreen(); // n. will want to use slot primaryScreenChanged(QScreen * screen); QString name = primaryScreen->name(); printf("primaryScreen: %s\n", QS2S(name)); const auto screens = coreapp.screens(); for (int ndx = 0; ndx < screens.count(); ndx++) { printf("Screen %d:\n", ndx); dbgrptQScreen(screens[ndx]); } } static bool init_ddcutil_library(Parsed_Ddcui_Cmd * parsed_cmd) { bool debug = false; if (debug) printf("(%s) Starting. parsed_cmd=%p\n", __func__, (void*)parsed_cmd); bool ok = true; if (parsed_cmd->traced_functions) { char * funcname = NULL; int ndx = 0; for (funcname = parsed_cmd->traced_functions[0]; funcname; funcname = parsed_cmd->traced_functions[++ndx]) { printf("(%s) adding traced function: %s\n", __func__, funcname); ddca_add_traced_function(funcname); } } if (parsed_cmd->traced_files) { char * filename = NULL; int ndx = 0; for (filename = parsed_cmd->traced_files[0]; filename; filename = parsed_cmd->traced_files[++ndx]) { printf("(%s) adding traced file: %s\n", __func__, filename); ddca_add_traced_file(filename); } } uint16_t work = 0; if (parsed_cmd->flags & CMD_FLAG_TIMESTAMP_TRACE) work |= DDCA_TRCOPT_TIMESTAMP; if (parsed_cmd->flags & CMD_FLAG_THREAD_ID_TRACE) work |= DDCA_TRCOPT_THREAD_ID; ddca_set_trace_options((DDCA_Trace_Options) work); // flunks --permissive // ddca_set_trace_options( // ( (parsed_cmd->flags & CMD_FLAG_TIMESTAMP_TRACE) ? DDCA_TRCOPT_TIMESTAMP : 0) | // ( (parsed_cmd->flags & CMD_FLAG_THREAD_ID_TRACE) ? DDCA_TRCOPT_THREAD_ID : 0) // ); ddca_add_trace_groups(parsed_cmd->traced_groups); // Must be called before any API call that triggers display identification // DDCA_Status rc = // unused, comment out for now, need to properly set // ddca_enable_usb_display_detection(parsed_cmd->flags & CMD_FLAG_NOUSB); // ddca_enable_udf( parsed_cmd->flags & CMD_FLAG_ENABLE_UDF); if (parsed_cmd->flags & CMD_FLAG_DDCDATA) ddca_enable_report_ddc_errors(true); if (parsed_cmd->flags & CMD_FLAG_REPORT_FREED_EXCP) ddca_enable_error_info(true); #ifdef USE_CONFIG_FILE if (parsed_cmd->max_tries[0] > 0) { ddca_set_max_tries( DDCA_WRITE_ONLY_TRIES, parsed_cmd->max_tries[0]); } if (parsed_cmd->max_tries[1] > 0) { ddca_set_max_tries( DDCA_WRITE_READ_TRIES, parsed_cmd->max_tries[1]); } if (parsed_cmd->max_tries[2] > 0) { ddca_set_max_tries( DDCA_MULTI_PART_TRIES, parsed_cmd->max_tries[2]); } if (parsed_cmd->sleep_multiplier != 1.0f) { ddca_set_default_sleep_multiplier(parsed_cmd->sleep_multiplier); } if (parsed_cmd->enable_sleep_suppression != TRIVAL_UNSET) { bool val = (parsed_cmd->enable_sleep_suppression == TRIVAL_TRUE) ? true : false; ddca_enable_sleep_suppression(val); } #endif if (debug) printf("(%s) Done. Returning %s\n", __func__, SBOOL(ok)); return ok; } int main(int argc, char *argv[]) { bool debug = false; if (debug) { printf("(%s) Starting\n", __func__); printf("(%s) prgname = %s, application_name = %s\n", __func__, g_get_prgname(), g_get_application_name() ); } // must be called before parsed_ddcui_command(), o.w. --help reports libddcutil as name // n. also sets application_name g_set_prgname("ddcui"); // will remove any arguments that it recognizes, e.g. --widgetcount QApplication application(argc, argv); application.setWindowIcon(QIcon(":/icons/ddcui_multires.ico")); GPtrArray * errmsgs = g_ptr_array_new_with_free_func(free); char ** new_argv = NULL; int new_argc = 0; char * combined_config_file_options = NULL; char * config_fn; if (debug) printf("(%s) Calling apply_config_file()\n", __func__); int apply_config_rc = apply_config_file( "ddcui", argc, argv, &new_argc, &new_argv, &combined_config_file_options, &config_fn, errmsgs); if (debug) { printf("(%s) apply_config_file() returned %d\n", __func__, new_argc); printf("(%s) combined_config_file_options=%s, config_fn=%s\n", __func__, combined_config_file_options, config_fn); printf("(%s) new_argc=%d, new_argv:\n", __func__, new_argc); ntsa_show(new_argv); } if (combined_config_file_options && strlen(combined_config_file_options) > 0) printf("Applying ddcui options from %s: %s\n", config_fn, combined_config_file_options); free(combined_config_file_options); if (errmsgs->len > 0) { printf("Errors reading ddcui configuration file %s:\n", config_fn); for (guint ndx = 0; ndx < errmsgs->len; ndx++) printf(" %s\n", (char*) g_ptr_array_index(errmsgs, ndx)); } g_ptr_array_free(errmsgs, true); free(config_fn); if (apply_config_rc < 0) return 1; Parsed_Ddcui_Cmd * parsed_cmd = parse_ddcui_command(new_argc, new_argv); if (!parsed_cmd) return 1; if (parsed_cmd->flags & CMD_FLAG_SHOW_STYLES) { QStringList styles = QStyleFactory::keys(); printf("Known styles:\n"); for (int ndx = 0; ndx < styles.size(); ndx++) printf(" %s\n", styles.at(ndx).toLocal8Bit().constData()); return 0; } if (parsed_cmd->flags & CMD_FLAG_SHOW_ACTIVE_STYLE) { const char * styleClass = QApplication::style()->metaObject()->className(); printf("Active style: %s\n", styleClass); } // local, not in ddcutil library enable_trace_show_time( parsed_cmd->flags & CMD_FLAG_TIMESTAMP_TRACE); enable_trace_show_thread_id(parsed_cmd->flags & CMD_FLAG_THREAD_ID_TRACE); if (!init_ddcutil_library(parsed_cmd)) return 1; if (parsed_cmd->flags & CMD_FLAG_F1) { dbgrpt_hidpi_environment_vars(); dbgrpt_hidpiQApplication(application); } GlobalState & globalState = GlobalState::instance(); init_core(); if (debug) printf("(%s) Calling MainWindow constructor\n", __func__); MainWindow w(parsed_cmd); if (debug) printf("(%s) MainWindow constructor completed\n", __func__); globalState._mainWindow = &w; globalState._application = &application; // without w.show(), initial serial message box does not appear over MainWindow w.show(); #ifdef PERSISTENT_SERIAL_MSG_BOX w.initSerialMsgbox(); // how to defer until after main event loop started, i.e. a.exec() called w.start_msgBoxThread(); #endif if (debug) printf("(%s) Calling Application::exec()\n", __func__); int mainStatus = application.exec(); if (debug) printf("(%s) Application::exec() returned %d\n", __func__, mainStatus); ddca_show_stats(parsed_cmd->stats_types, false, // include_per_thread_data 0); // depth // return mainStatus; exit(mainStatus); } ddcui-0.3.0/src/main/mainwindow.cpp000066400000000000000000001223631427175135000172110ustar00rootroot00000000000000/** \file mainwindow.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "main/mainwindow.h" #include #include #include #include #include #include #include #include #include // 5.9 #include #include "base/core.h" #include "base/global_state.h" #include "base/widget_debug.h" #include "help/help_dialog.h" #include "help/help_browser.h" #include "base/ddcui_parms.h" #include "base/global_state.h" #include "base/monitor.h" #include "core_widgets/spin_slider.h" #include "nongui/msgbox_queue.h" #include "nongui/vcpthread.h" // includes vcprequest.h #include "monitor_desc/monitor_desc_actions.h" #include "monitor_desc/monitor_desc_ui.h" #include "feature_value_widgets/value_stacked_widget.h" #include "feature_scrollarea/feature_widget.h" #include "feature_scrollarea/features_scrollarea_contents.h" #include "feature_scrollarea/features_scrollarea_ui.h" #include "feature_scrollarea/features_scrollarea_view.h" #include "option_dialogs/feature_selection_dialog.h" #include "option_dialogs/user_interface_options_dialog.h" #include "action_dialogs/debug_actions_dialog.h" #include "main/mainwindow_ui.h" #include "main/msgbox_thread.h" #include "main/mainwindow.h" #include "../base/nc_values_state.h" #include "../option_dialogs/nc_values_dialog.h" using namespace std; // // Constructor, Destructor, Initialization // // called from main.cpp before event mainwindow event loop started void MainWindow::initSerialMsgbox() { bool debug = false; TRACEMCF(debug, "Starting"); // QMessageBox for displaying error messages, one at a time // using persistent serial message box _serialMsgBox = new QMessageBox(this); _serialMsgBox->setStandardButtons(QMessageBox::Ok); _serialMsgBox->setWindowModality(Qt::WindowModal); _serialMsgBox->setFont(_ui->mainMenuFont); TRACECF(debug, "_msgboxQueue=%p, _msgBoxThread=%p", _msgBoxQueue, _msgBoxThread); QObject::connect(_serialMsgBox, &QMessageBox::finished, _msgBoxThread, &MsgBoxThread::msbgoxClosed); QObject::connect(_msgBoxThread, &MsgBoxThread::postSerialMsgBox, this, &MainWindow::showSerialMsgBox); // Defer until after MainWindow::show() so that dialog box appears over main window // _msgBoxThread->start(); TRACEMCF(debug, "Done"); } void MainWindow::start_msgBoxThread() { bool debug = false; TRACEMCF(debug, "Starting"); #ifdef DEFERRED_MSG_QUEUE TRACEMC("Putting %d MsgBoxQueueEntry on _msgBoxQueue", _deferredMsgs.count()); for (int ndx = 0; ndx < _deferredMsgs.count(); ndx++) { MsgBoxQueueEntry * qe = _deferredMsgs.at(ndx); _msgBoxQueue->put(qe); } #endif _msgBoxThread->start(); TRACEMCF(debug, "Done. _msgBoxThread started"); } void MainWindow::connectBaseModel(Monitor * curMonitor) { FeatureBaseModel * baseModel = curMonitor->_baseModel; QObject::connect(baseModel, &FeatureBaseModel::signalStartInitialLoad, this, &MainWindow::longRunningTaskStart); QObject::connect(baseModel, &FeatureBaseModel::signalEndInitialLoad, this, &MainWindow::longRunningTaskEnd); QObject::connect(baseModel, &FeatureBaseModel::signalStatusMsg, this, &MainWindow::setTransitoryStatusMsg); } void MainWindow::disconnectBaseModel(Monitor * curMonitor) { FeatureBaseModel * baseModel = curMonitor->_baseModel; QObject::disconnect(baseModel, &FeatureBaseModel::signalStatusMsg, this, &MainWindow::setTransitoryStatusMsg); QObject::disconnect(baseModel, &FeatureBaseModel::signalStartInitialLoad, this, &MainWindow::longRunningTaskStart); QObject::disconnect(baseModel, &FeatureBaseModel::signalEndInitialLoad, this, &MainWindow::longRunningTaskEnd); } void MainWindow::freeMonitors() { bool debug = false; TRACECF(debug, "Starting"); int ct0 = _monitors.size(); TRACECF(debug,"_monitors.size() = %d", ct0); for (int ndx = _monitors.size()-1; ndx >= 0; ndx--) { Monitor * curMonitor = _monitors.at(ndx); TRACECF(debug, "deleting monitor ndx=%d, curMonitor=%p, dispno=%d", ndx, curMonitor, curMonitor->_displayInfo->dispno); _monitors.removeAt(ndx); delete curMonitor; TRACECF(debug, "deleted monitor ndx=%d", ndx); } QObject::disconnect(_toolbarDisplayCB, SIGNAL(currentIndexChanged(int)), this, SLOT( displaySelectorCombobox_currentIndexChanged(int))); int ct = _toolbarDisplayCB->count(); TRACECF(debug,"_toolbarDisplayCB->size() = %d", ct); for (int ndx = ct-1; ndx >= 0; ndx--) { _toolbarDisplayCB->removeItem(ndx); } TRACECF(debug, "Done"); } void MainWindow::initOneMonitor(DDCA_Display_Info * info, int curIndex) { bool debug = false; TRACECF(debug, "Starting. info=%p, curIndex=%d", info, curIndex); // Add entry for monitor in display selector combo box QString mfg_id = info->mfg_id; QString model_name = info->model_name; QString sn = info->sn; #ifdef ALT QString mfg_id = _dlist->info[ndx].mmid.mfg_id; QString model_name = _dlist->info[ndx].mmid.model_name; #endif QString s = model_name; if (s.isEmpty() ) { if ( sn.isEmpty() ) s = QString("Laptop"); else s = QString("Unknown"); // don't expect this } int monitorNumber = curIndex+1; _toolbarDisplayCB->addItem(s, QVariant(monitorNumber)); // Create Monitor instance, initialize data structures Monitor * curMonitor = new Monitor(info, monitorNumber); _monitors.append(curMonitor); initMonitorInfoWidget(curMonitor, _ui->centralWidget); initCapabilitiesWidget(curMonitor, _ui->centralWidget); if (curMonitor->supportsDdc()) { initFeaturesScrollAreaView(curMonitor, curMonitor->_baseModel, _ui->centralWidget, _msgBoxQueue); connectBaseModel(curMonitor); // asynchronously get capabilities for current monitor // if (debug) // ddca_report_display_info(info, 3); curMonitor->_requestQueue->put(new LoadDfrRequest()); curMonitor->_requestQueue->put(new VcpCapRequest()); // TODO: disable Capabilities and Features Views _ui->actionCapabilities->setEnabled(true); _ui->actionFeaturesScrollArea->setEnabled(true); } else { _ui->actionCapabilities->setEnabled(false); _ui->actionFeaturesScrollArea->setEnabled(false); } TRACECF(debug, "Done."); } void MainWindow::setInitialDisplayIndex(Parsed_Ddcui_Cmd * parsed_cmd) { bool debug = false; int initialDisplayIndex = -1; if (parsed_cmd->model) { QString userModelParm(parsed_cmd->model); for (int ndx = 0; ndx < _toolbarDisplayCB->count(); ndx++) { QString curName(_toolbarDisplayCB->itemText(ndx)); // Check if the model name of this monitor matches one specified // on the command line. TRACECF(debug, "ndx=%d, parsed_cmd->model = |%s|, curname = |%s|", ndx, parsed_cmd->model, QS2S(curName)); if (userModelParm == curName) { initialDisplayIndex = ndx; TRACECF(debug, "model found, ndx=%d", ndx); break; } } TRACECF(debug, "after check model name, initialDisplayIndex = %d", initialDisplayIndex); if (initialDisplayIndex < 0) { // queue status dialog initialDisplayIndex = 0; QString qsTitle = QString("ddcutil Error"); QString qsDetail = QString("Invalid Model: %1").arg(parsed_cmd->model); QMessageBox::Icon icon = QMessageBox::Warning; MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(qsTitle, qsDetail, icon); #ifdef DEFERRED_MSG_QUEUE _deferredMsgs.append(qe); // not needed #endif TRACECF(debug, "Pre put, _msgBoxQueue=%p", _msgBoxQueue); _msgBoxQueue->put(qe); } } else { initialDisplayIndex = 0; } TRACECF(debug, "initialDisplayIndex (2) = %d", initialDisplayIndex); _toolbarDisplayCB->setCurrentIndex(initialDisplayIndex); } void MainWindow::initMonitors(Parsed_Ddcui_Cmd * parsed_cmd) { bool debug = false; TRACECF(debug, "Starting. parsed_cmd=%p", parsed_cmd); longRunningTaskStart(); statusBar()->showMessage(QString("Loading display information...")); #ifdef OLD TRACECF(debug, "Calling ddca_get_display_info_list2()"); DDCA_Status ddcrc = ddca_get_display_info_list2( true, // include invalid displays &_dlist); TRACECF(debug, "ddca_get_display_info_list2() returned %d", ddcrc); assert(ddcrc == 0); TRACECF(debug, "_dlist->ct = %d", _dlist->ct); #endif TRACECF(debug, "Calling ddca_get_display_refs()"); DDCA_Status ddcrc = ddca_get_display_refs(/*include invalid displays=*/true, &_drefs); TRACECF(debug, "ddca_get_display_refs() returned %d", ddcrc); assert(ddcrc == 0); DDCA_Error_Detail * errs = ddca_get_error_detail(); if (errs) { if (debug) ddca_report_error_detail(errs, 2); QString errMsg(errs->detail); bool permissionsError = false; if (errs->cause_ct > 0) { for (int ndx = 0; ndx < errs->cause_ct; ndx++) { DDCA_Error_Detail * cause = errs->causes[ndx]; TRACECF(debug, "errs->status_code=%d", errs->status_code); if (cause->status_code == -13) { // -EACCES permissionsError = true; } if (ndx == 0) errMsg.append(":\n\n"); else errMsg.append("\n"); // char * s = cause->detail; // QString thisMsg(s); QString thisMsg(cause->detail); errMsg.append(thisMsg); } // if (permissionsError) { // TRACECF(debug, "Appending URL"); // errMsg.append("

    For help, see ddcutil permissions"); // } } ddca_free_error_detail(errs); QString qsTitle = QString("ddcutil Error"); QString qsDetail = QString(errMsg); QMessageBox::Icon icon = QMessageBox::Warning; MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(qsTitle, qsDetail, icon); #ifdef DEFERRED_MSG_QUEUE _deferredMsgs.append(qe); // not needed #endif TRACECF(debug, "Pre put, _msgBoxQueue=%p", _msgBoxQueue); _msgBoxQueue->put(qe); } for (_drefs_ct=0; _drefs[_drefs_ct]; _drefs_ct++) {} TRACECF(debug, "_drefs_ct = %d", _drefs_ct); for (int ndx = 0; ndx < _drefs_ct; ndx++) { TRACECF(debug, "Processing display %d", ndx); DDCA_Display_Info * dinfo; DDCA_Status ddcrc = ddca_get_display_info(_drefs[ndx], &dinfo); assert(ddcrc == 0); initOneMonitor(dinfo, ndx); } _ui->actionMonitorSummary->setEnabled(false); _ui->actionCapabilities->setEnabled(false); _ui->actionFeaturesScrollArea->setEnabled(false); if (_drefs_ct > 0) { _ui->actionMonitorSummary->setEnabled(true); } else { MsgBoxQueueEntry * qe = new MsgBoxQueueEntry("ddcui", QString("No displays detected"), QMessageBox::Warning); TRACECF(debug, "Pre put, _msgBoxQueue=%p", _msgBoxQueue); _msgBoxQueue->put(qe); } #ifdef DEFERRED_MSG_QUEUE _deferredMsgs = QList(); // not needed, #endif setInitialDisplayIndex(parsed_cmd); connect(_toolbarDisplayCB, SIGNAL(currentIndexChanged(int)), this, SLOT( displaySelectorCombobox_currentIndexChanged(int))); #ifdef UNNEEDED connect(_toolbarDisplayCB, SIGNAL(activated(int)), this, SLOT( displaySelectorCombobox_activated(int))); #endif // connect(_toolbarDisplayCB, qOverload::of(&QComboBox::currentIndexChanged), // this &MainWindow::displaySelectorCombobox_currentIndexChanged); connect(this, &MainWindow::signalMonitorSummaryView, this, &MainWindow::on_actionMonitorSummary_triggered); connect(this, &MainWindow::signalCapabilitiesView, this, &MainWindow::on_actionCapabilities_triggered); connect(this, &MainWindow::signalFeaturesView, this, &MainWindow::on_actionFeaturesScrollArea_triggered); // Set message in status bar QString msg = QString("Detected ") + QString::number(_drefs_ct) + QString(" displays."); statusBar()->showMessage(msg); longRunningTaskEnd(); TRACECF(debug, "Done"); } void MainWindow::quitShortcut() { bool debug = false; TRACECF(debug, "Executing"); //close(); TRACECF(debug, "Before _application->exit()"); GlobalState::instance()._application->exit(0); } MainWindow::MainWindow(Parsed_Ddcui_Cmd * parsed_cmd, QWidget *parent) : QMainWindow(parent), _ui(new Ui_MainWindow(this)) // _ui(new Ui::MainWindow) // , PageChangeObserver() { bool debug = false; _cls = strdup(metaObject()->className()); TRACECF(debug, "Starting"); GlobalState& globalState = GlobalState::instance(); globalState._parsed_cmd = parsed_cmd; // in case of reinitialization // Register metatypes for primitive types here. // Metatypes for classes are registered with the class definition. qRegisterMetaType("uint8_t"); qRegisterMetaType("bool"); // needed? qRegisterMetaType("NcValuesSource"); qRegisterMetaType("QMessageBox::Icon"); // ComboBox for display selection QLabel* toolbarDisplayLabel = new QLabel("&Display: "); toolbarDisplayLabel->setFont(_ui->mainMenuFont); _toolbarDisplayCB = new QComboBox(); _toolbarDisplayCB->setObjectName("displaySelectorCombobox"); _toolbarDisplayCB->setStyleSheet("background-color:white; color:black;"); _toolbarDisplayCB->setFont(_ui->mainMenuFont); toolbarDisplayLabel->setBuddy(_toolbarDisplayCB); _ui->mainToolBar->addWidget( toolbarDisplayLabel); _ui->mainToolBar->addWidget( _toolbarDisplayCB); _msgBoxQueue = new MsgBoxQueue(); _msgBoxThread = new MsgBoxThread(_msgBoxQueue); globalState._msgBoxThread = _msgBoxThread; globalState._msgBoxQueue = _msgBoxQueue; // QShortcut * quit_shortcut = new QShortcut(QKeySequence(Qt::Key_Q | Qt::CTRL), this, SLOT(close())); _quit_shortcut = new QShortcut(QKeySequence(Qt::Key_Q | Qt::CTRL), this); _quit_shortcut->setContext(Qt::ApplicationShortcut); connect(_quit_shortcut, &QShortcut::activated, this, &MainWindow::quitShortcut); TRACECF(debug, "Before initMonitors()"); // reportWidgetChildren(ui->centralWidget, "Children of centralWidget, before initMonitors():"); initMonitors(parsed_cmd); // Initialize Options menu _feature_selector = new FeatureSelector(parsed_cmd); _otherOptionsState = new NcValuesState(parsed_cmd); _uiOptionsState = new UserInterfaceOptionsState(parsed_cmd); globalState._ncValuesState = _otherOptionsState; globalState._uiOptionsState = _uiOptionsState; QObject::connect( _uiOptionsState, &UserInterfaceOptionsState::controlKeyRequired_changed, this, &MainWindow::forControlKeyRequired_changed); QObject::connect( this, &MainWindow::featureSelectionChanged, this, &MainWindow::on_actionFeaturesScrollArea_triggered); // Start with Monitor Summary of first monitor instead if no view selected if (_monitors.size() > 0) { TRACECF(debug, "_monitors_size=%d. emitting signalMonitorSummaryView", _monitors.size()); emit signalMonitorSummaryView(); } #ifdef BAD // get dialog box that capabilities incomplete before main screen appears if (parsed_cmd->view == VIEW_UNSET || parsed_cmd->view == VIEW_SUMMARY) emit signalMonitorSummaryView(); else if (parsed_cmd->view == VIEW_CAPABILITIES) { emit signalCapabilitiesView(); } else { assert (parsed_cmd->view == VIEW_FEATURES); emit signalFeaturesView(); } #endif #ifdef DOESNT_SOLVE_PROBLEM // An attempt to address the problem of the Message Box for "early" messages // doesn't appear centered over the application. // The problem is that DialogBoxes have their own event loop, so can get ahead // of the main application. // This solution waits until the main application event loop is running // before starting the message box thread. // Should work, but it didn't. QObject::connect( this, &MainWindow::reportApplicationEventLoopStarted, this, &MainWindow::start_msgBoxThread); TRACEMC("Emitting reportApplicationEventLoopStarted()"); emit reportApplicationEventLoopStarted(); // will not be delivered until application event loop started #endif TRACECF(debug, "Done"); } MainWindow::~MainWindow() { bool debug = false; TRACECF(debug, "Starting"); delete _ui; delete _feature_selector; delete _otherOptionsState; delete _uiOptionsState; freeMonitors(); free(_drefs); TRACECF(debug, "Done"); free((void*) _cls); } void MainWindow::forControlKeyRequired_changed(bool onoff) { bool debug = false; TRACECF(debug, "Starting. onoff=%s", SBOOL(onoff)); ctrlKeyStatusMsg(); TRACECF(debug, "Done"); } void MainWindow::ctrlKeyStatusMsg() { bool debug = false; TRACECF(debug, "Starting"); if (_curView == View::FeaturesView && _uiOptionsState->_controlKeyRequired ) { statusBar()->addWidget(_ctlMsg); // Normal message, no timeout _ctlMsg->show(); } else { statusBar()->removeWidget(_ctlMsg); } TRACECF(debug, "Done"); } // // Status Message slots // void MainWindow::setTransitoryStatusMsg(QString msg) { bool debug = false; char * m = QS2S(msg); TRACECF(debug, "Starting. msg = %s", m); statusBar()->showMessage(msg,2000); TRACECF(debug, "Done"); } // Report API error in status bar void MainWindow::reportDdcApiError(QString funcname, int rc) const { QString msg = funcname + "() returned " + QString::number(rc) + " - " + ddca_rc_name(rc); statusBar()->showMessage(msg); // QErrorMessage * emsg; // invalid conversion from const QWidget* to QWidget* // emsg = new QErrorMessage(this); // emsg->showMessage("oy vey"); } // // SerialMsgBox slots // void MainWindow::showSerialMsgBox(QString title, QString text, QMessageBox::Icon icon) { bool debug = false; TRACEMCF(debug, "Starting. text=%s", QS2S(text)); // #ifdef DIALOG_BOX_STILL_ON_SEPARATE_SCREEN #ifdef NON_PERSISTENT QMessageBox * serialMbox2 = new QMessageBox(this); serialMbox2->setStandardButtons(QMessageBox::Ok); serialMbox2->setWindowModality(Qt::WindowModal); serialMbox2->setModal(true); serialMbox2->setFont(_ui->mainMenuFont); #endif // _serialMsgBox->setTextFormat(Qt::RichText); _serialMsgBox->setText(text); _serialMsgBox->setWindowTitle(title); _serialMsgBox->setIcon(icon); #ifdef NON_PERSISTENT QObject::connect( serialMbox2, &QMessageBox::finished, _msgBoxThread, &MsgBoxThread::msbgoxClosed ); #endif _serialMsgBox->exec(); TRACEMCF(debug, "Done. After serialMsgBox2->exec() returns."); // #endif #ifdef NO _serialMsgBox->setText(text); _serialMsgBox->setWindowTitle(title); _serialMsgBox->setIcon(icon); _serialMsgBox->show(); _serialMsgBox->exec(); #endif } // ** Miscellaneous Slots // Sets spinning cursor at start of a long running task // Both a direct call from initMonitors and a slot for FeatureBaseModel void MainWindow::longRunningTaskStart() { bool debug = false; // needs counter TRACECF(debug, "Executing"); // _spinner->start(); // _loadingMsgBox->show(); QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } // Restores normal cursor at the of a long running task // Both a direct call from initMonitors and a slot for FeatureBaseModel void MainWindow::longRunningTaskEnd() { bool debug = false; TRACECF(debug, "Executing"); // _spinner->stop(); // _loadingMsgBox->hide(); ctrlKeyStatusMsg(); QGuiApplication::restoreOverrideCursor(); TRACECF(debug, "Done"); } // // Display-selection combo box slots // void MainWindow::displaySelectorCombobox_currentIndexChanged(int index) { // printf("(%s::%s) index=%d\n", _cls, __func__, index); fflush(stdout); bool debug = false; TRACECF(debug, "index=%d", index); // From index, get the Monitor object // if not support DDC, always emit signalMonitorSummaryView switch(_curView) { case MonitorView: emit signalMonitorSummaryView(); break; case CapabilitiesView: emit signalCapabilitiesView(); break; case FeaturesView: emit signalFeaturesView(); break; case NoView: break; } } #ifdef UNNEEDED void MainWindow::displaySelectorCombobox_activated(int index) { printf("(%s::%s) index=%d\n", _cls, __func__, index); fflush(stdout); } #endif // // *** View menu slots // // View->Summary void MainWindow::on_actionMonitorSummary_triggered() { bool debug = false; // std::cout << "(MainWindow::on_actionMonitorSummary_triggered()" << endl; int monitorNdx = _toolbarDisplayCB->currentIndex(); TRACEMF(debug, "monitorNdx=%d", monitorNdx); if (monitorNdx < 0) { // _ui->centralWidget->hide(); } else { Monitor * monitor = _monitors[monitorNdx]; DDCA_Display_Info * dinfo = monitor->_displayInfo; // &_dlist->info[monitorNdx]; DDCA_Display_Ref dref = dinfo->dref; TRACECF(debug, "monitorNdx (%d), dref=%s", monitorNdx, ddca_dref_repr(dref)); char * s = MonitorDescActions::capture_display_info_report(dinfo); TRACECF(debug, "monitor=%p", monitor); QPlainTextEdit * moninfoPlainText = monitor->_moninfoPlainText; // int pageno = monitor->_pageno_moninfo; moninfoPlainText->setPlainText(s); free(s); _curView = View::MonitorView; _ui->actionRescan->setEnabled(false); _ui->actionMonitorSummary->setChecked(true); bool b = monitor->supportsDdc(); _ui->actionCapabilities->setEnabled(b); _ui->actionFeaturesScrollArea->setEnabled(b); // _ui->centralWidget->setCurrentIndex(pageno); _ui->centralWidget->setCurrentWidget(monitor->_page_moninfo); _ui->centralWidget->show(); } ctrlKeyStatusMsg(); // clears the message since not Features view TRACECF(debug, "_ui->actionCapabilities->isEnabled()=%s", SBOOL(_ui->actionCapabilities->isEnabled() )); } // View->Capabilities void MainWindow::on_actionCapabilities_triggered() { bool debug = false; int monitorNdx = _toolbarDisplayCB->currentIndex(); TRACECF(debug, "monitorNdx=%d", monitorNdx); if (monitorNdx < 0) { TRACECF(debug, "monitorNdx = %d is < 0, ignoring", monitorNdx); } else { Monitor * monitor = _monitors.at(monitorNdx); DDCA_Display_Info * dinfo = monitor->_displayInfo; // &_dlist->info[monitorNdx]; DDCA_Display_Ref dref = dinfo->dref; char * caps_report = NULL; TRACECF(debug, "dref=%s, valid display %s", QS2S(monitor->dref_repr()), SBOOL(monitor->supportsDdc()) ); if (!monitor->supportsDdc()) { QMessageBox::warning(this, "ddcutil", "Display does not support DDC (1)", QMessageBox::Ok); // emit signalMonitorSummaryView(); // doesn't work on_actionMonitorSummary_triggered(); } else if (!monitor->capabilitiesCheckComplete()) { QMessageBox::warning(this, "ddcutil", "Capabilities check still in progress", QMessageBox::Ok); // emit signalMonitorSummaryView(); // doesn't work on_actionMonitorSummary_triggered(); } else if (!monitor->capabilitiesCheckSuccessful()) { QMessageBox::warning(this, "ddcutil", "Display does not support DDC (2)", QMessageBox::Ok); // emit signalMonitorSummaryView(); // doesn't work on_actionMonitorSummary_triggered(); } else { DDCA_Status ddcrc = MonitorDescActions::capture_capabilities_report(monitor, dref, &caps_report); if (ddcrc != 0) { reportDdcApiError("ddca_open_display", ddcrc); TRACEC("capture_capabilites_report returned %d", ddcrc); } else { // cout << "Parsed capabilities: " << endl; // cout << caps_report << endl; Monitor * monitor = _monitors[monitorNdx]; QPlainTextEdit * capabilitiesPlainText = monitor->_capabilitiesPlainText; // int pageno = monitor->_pageno_capabilities; capabilitiesPlainText->setPlainText(caps_report); free(caps_report); // show widget _curView = View::CapabilitiesView; _ui->actionRescan->setEnabled(false); _ui->actionCapabilities->setChecked(true); // _ui->centralWidget->setCurrentIndex(pageno); // need proper constants _ui->centralWidget->setCurrentWidget(monitor->_page_capabilities); _ui->centralWidget->show(); } } } ctrlKeyStatusMsg(); // clears the message since not Features view } // View->Features void MainWindow::on_actionFeaturesScrollArea_triggered() { bool debug = false; debug = debug || debugFeatureSelection; if (debug) { TRACEC("Desired view: %d, feature list:", View::FeaturesView); this->_feature_selector->dbgrpt(); } int monitorNdx = _toolbarDisplayCB->currentIndex(); if (monitorNdx < 0) { TRACECF(debug, "monitorNdx = %d is < 0, ignoring", monitorNdx); } else { Monitor * monitor = _monitors[monitorNdx]; if (debug) { TRACEC("Current view: %d, feature list:", _curView); monitor->_curFeatureSelector.dbgrpt(); } if (!monitor->supportsDdc()) { QMessageBox::warning(this, "ddcui", "Display does not support DDC (3)", QMessageBox::Ok); // emit signalMonitorSummaryView(); // doesn't work on_actionMonitorSummary_triggered(); } else if (!monitor->capabilitiesCheckComplete()) { QMessageBox::warning(this, "ddcui", "Capabilities check incomplete", QMessageBox::Ok); on_actionMonitorSummary_triggered(); } else if (!monitor->capabilitiesCheckSuccessful()) { QMessageBox::warning(this, "ddcui", "Display does not support DDC (4)", QMessageBox::Ok); on_actionMonitorSummary_triggered(); } else { // TODO Combine View, features view if (_curView != View::FeaturesView || _curDisplayIndex != monitorNdx || monitor->_curFeatureSelector != *_feature_selector ) { loadMonitorFeatures(monitor); _curDisplayIndex = monitorNdx; _curView = View::FeaturesView; _ui->actionRescan->setEnabled(true); _ui->actionFeaturesScrollArea->setChecked(true); monitor->_curFeatureSelector = *_feature_selector; } else { TRACECF(debug, "Unchanged view and feature set, no need to load"); } } } ctrlKeyStatusMsg(); } void MainWindow::loadMonitorFeatures(Monitor * monitor) { bool debug = false; debug |= debugFeatureLists; TRACECF(debug, "monitor=%p", monitor); // monitor->dbgrpt(); QString msg = QString("Reading monitor features..."); _ui->statusBar->showMessage(msg); DDCA_Feature_List featuresToShow = DDCA_EMPTY_FEATURE_LIST; if (_feature_selector->_featureSubsetId == DDCA_SUBSET_CAPABILITIES) { featuresToShow = ddca_feature_list_from_capabilities(monitor->_baseModel->_parsed_caps); } else if (_feature_selector->_featureSubsetId == DDCA_SUBSET_CUSTOM) { featuresToShow = _feature_selector->_customFeatureList; } else { featuresToShow = monitor->getFeatureList(_feature_selector->_featureSubsetId); TRACECF(debug, "features_to_show: (%d) %s", ddca_feature_list_count(featuresToShow), ddca_feature_list_string(featuresToShow, NULL, (char*)" ")); if (_feature_selector->_includeOnlyCapabilities || _feature_selector->_includeAllCapabilities) { // need to test _parsed_caps is valid // n. simply manipulates data structures, does not perform monitor io DDCA_Feature_List caps_features = ddca_feature_list_from_capabilities(monitor->_baseModel->_parsed_caps); TRACECF(debug, "Capabilities features: (%d) %s", ddca_feature_list_count(caps_features), ddca_feature_list_string(caps_features, NULL, (char*)" ")); if (_feature_selector ->_includeOnlyCapabilities) featuresToShow = ddca_feature_list_and(featuresToShow, caps_features); else featuresToShow = ddca_feature_list_or(featuresToShow, caps_features); } } TRACECF(debug, "Final featuresToShow: (%d) %s", ddca_feature_list_count(featuresToShow), ddca_feature_list_string(featuresToShow, NULL, (char*)" ")); // causes async feature reads in VcpThread, then load feature values from model into widgets monitor->_baseModel->setFeatureList(featuresToShow); TRACECF(debug, "Done"); } // // *** Actions Menu Slots // // Actions->Rescan slots void MainWindow::on_actionRescan_triggered() { bool debug = false; TRACECF(debug, "Executing"); assert(_curView == FeaturesView); assert(_curDisplayIndex >= 0); _monitors[_curDisplayIndex]->_baseModel->reloadFeatures(); } void MainWindow::on_actionRedetect_triggered() { bool debug = false; TRACECF(debug, "Executing"); this->freeMonitors(); free(_drefs); // ddca_free_display_info_list(_dlist); // _dlist = NULL; TRACECF(debug, "Before ddca_redetect_displays"); DDCA_Status ddcrc = ddca_redetect_displays(); assert(ddcrc == 0); // always returns 0 _ui->actionMonitorSummary->setEnabled(false); _ui->actionCapabilities->setEnabled(false); _ui->actionFeaturesScrollArea->setEnabled(false); TRACECF(debug, "Before initMonitors()"); this->initMonitors(GlobalState::instance()._parsed_cmd); TRACECF(debug, "After initMonitors()"); // reinit UI to first monitor, summary view // if no monitors, set _curDisplayIndex = -1 // _curDisplayIndex = (_dlist->ct > 0) ? 0 : -1; _curDisplayIndex = (_drefs_ct > 0) ? 0 : -1; // HANDLE CASE OF NO DDC MONITORS? TRACECF(debug, "Emitting signalMonitorSummaryView"); emit signalMonitorSummaryView(); TRACECF(debug,"Done"); } // Actions->Debug: DebugActionsDialog slots void MainWindow::on_actionDebugActionsDialog_triggered() { // bool debug = false; // TODO: allocate once and save dialog, cf feature selection // display dialog box for selecting features // TRACECF(debug, "triggered"); // assert(false); // for testing DebugActionsDialog* dialog = new DebugActionsDialog(this); QObject::connect(dialog, &DebugActionsDialog::resetStats_triggered, this, &MainWindow::for_resetStats_triggered); QObject::connect(dialog, &DebugActionsDialog::reportStats_triggered, this, &MainWindow::for_reportStats_triggered); dialog->exec(); delete dialog; } void MainWindow::for_resetStats_triggered() { bool debug = false; TRACECF(debug, "triggered"); ddca_reset_stats(); } void MainWindow::for_reportStats_triggered(DDCA_Stats_Type stats_type, bool show_thread_data) { bool debug = false; TRACECF(debug, "triggered. stats_type = %d", stats_type); // TO DO: Make per/thread setting a checkbox on dialog // ddca_show_stats(stats_type, show_thread_data, 0); capture_stats(stats_type, show_thread_data); } void MainWindow::capture_stats(DDCA_Stats_Type stats_type, bool show_thread_data) { ddca_start_capture(DDCA_CAPTURE_NOOPTS); // DDCA_Output_Level saved_ol = ddca_get_output_level(); // ddca_set_output_level(DDCA_OL_VERBOSE); ddca_show_stats(stats_type, show_thread_data, 0); // ddca_set_output_level(saved_ol); char * s = ddca_end_capture(); // API's buffer, do not free QString qs(s); free(s); const QFont& textFont = QFont( "Monospace", 9, QFont::Normal); // viewHelpByTextX(qs, QString("Statistics Report"), textFont, this); HelpDialog* hd = new HelpDialog(this); hd->setFont(textFont); hd->setText(qs); hd->resize(650,40); // hd->_textBrowser->setSource(fn); hd->setWindowTitle( "Execution Statistics" ); hd->exec(); // always modal } // // Options Menu Slots // // Feature Selection slots: FeatureSelectionDialog void MainWindow::on_actionFeatureSelectionDialog_triggered() { bool debug = false; TRACECF(debug, "Executing. _fsd=%p", _fsd); // FeatureSelectionDialog* if (_fsd) { _fsd->useSelectorData(); } else { _fsd = new FeatureSelectionDialog(this, this->_feature_selector); QObject::connect(_fsd, &FeatureSelectionDialog::featureSelectionChanged, this, &MainWindow::for_actionFeatureSelectionDialog_accepted); } _fsd->exec(); // delete _fsd; } // named "for_action..." instead of "on_action..." to avoid the connectSlotsByName naming convention // FeatureSelectionDialog not allocated at time connectSlotsByName() called, must use // explicit connect() void MainWindow::for_actionFeatureSelectionDialog_accepted() { bool debugFunc = false; debugFunc = debugFunc || debugSignals || debugFeatureSelection; if (debugFunc) { TRACEC("Executing"); _feature_selector->dbgrpt(); } if (_curView == FeaturesView) { TRACECF(debugFunc, "in FeaturesView, signaling featureSelectionChanged()"); emit featureSelectionChanged(); } else { TRACECF(debugFunc, "Not in FeaturesView, so not signaling featureSelectionChanged()"); } #ifdef UNNEEDED // TODO need semaphore - wait until monitors initialized for(int ndx = 0; ndx < _monitors.size(); ndx++) { Monitor * monitor = _monitors[ndx]; FeatureSelector fsel = monitor->_curFeatureSelector; bool showUnsupported = fsel._showUnsupportedFeatures; VcpRequestQueue * curQueue = monitor->_requestQueue; VcpRequest request; curQueue->put(request); } #endif } #ifdef UNUSED DDCA_Feature_Subset_Id MainWindow::feature_list_id() const { return this->_feature_list_id; } void MainWindow::set_feature_list_id(DDCA_Feature_Subset_Id feature_list_id) { cout << "(set_feature_list_id) feature_list_id =" << feature_list_id <_feature_list_id = feature_list_id; } #endif // Options->OtherOptions slots void MainWindow::on_actionOtherOptionsDialog_triggered() { bool debug = false; // TODO: allocate once and save dialog, cf feature selection // display dialog box for selecting features TRACECF(debug, "triggered"); NcValuesDialog* dialog = new NcValuesDialog(this->_otherOptionsState, this); // QObject::connect(dialog, &OtherOptionsDialog::ncValuesSourceChanged, // this, &MainWindow::for_actionOtherOptionsDialog_ncValuesSourceChanged); // QObject::connect(_otherOptionsState, &OtherOptionsState::ncValuesSourceChanged, // this, &MainWindow::for_actionOtherOptionsDialog_ncValuesSourceChanged); dialog->exec(); delete dialog; TRACECF(debug, "Done"); } #ifdef OLD // named for_ .. instead of on_ so that connectSlotsByName doesn't report this as slot // for which it could find no signal void MainWindow::for_actionOtherOptionsDialog_ncValuesSourceChanged( NcValuesSource valuesSource, bool useLatestNcValueNames ) { bool debug = false; TRACECF(debug, "valuesSource=%d, useLatestNcValueNames=%s", valuesSource, SBOOL(useLatestNcValueNames)); if (_curView == FeaturesView ) { // need also check if FeaturesScrollAreaView int monitorNdx = _toolbarDisplayCB->currentIndex(); Monitor * monitor = _monitors[monitorNdx]; // or emit signal? monitor->_featuresScrollAreaView->onNcValuesSourceChanged(valuesSource, useLatestNcValueNames); } TRACECF(debug, "Done"); } #endif // Options->User Interface Options slots: UserInterfaceOptionsDialog // causes the dialog to display void MainWindow::on_actionUserInterfaceOptionsDialog_triggered() { bool debug = false; TRACECF(debug, "Executing. _uid=%p", _uid); #ifdef NO // don't bother keeping the dialog box around and hidden if (_uid) { _uid->_state = new UserInterfaceOptionsState(); } else { _uid = new UserInterfaceOptionsData(this, this->_userInterfaceOptionsData); QObject::connect(_uid, &UserInterfaceOptionsDialog::userInterfaceOptionsChanged, this, &MainWindow::for_UserInterfaceOptionsDialog_accepted); } _uid->exec(); // delete _uid; #endif UserInterfaceOptionsDialog* dialog = new UserInterfaceOptionsDialog(this->_uiOptionsState, this); QObject::connect(dialog, &UserInterfaceOptionsDialog::accepted, this, &MainWindow::for_actionUserInterfaceOptionsDialog_accept); // need a connection for reset? TRACECF(debug, "Calling setControKeyRequired(%s)", SBOOL(_uiOptionsState->_controlKeyRequired) ); dialog->setDialogBoxControlKeyRequired( _uiOptionsState->_controlKeyRequired); dialog->exec(); delete dialog; } void MainWindow::for_actionUserInterfaceOptionsDialog_accept() { bool debug = false; TRACECF(debug, "Executing, Emitting userIntefaceOptionsChanged"); emit userInterfaceOptionsChanged(); } // // Help Menu Slots // void MainWindow::on_actionContentsHelp_triggered() { // TRACEC("Executing"); HelpBrowser::showPage(QString("qrc:/docs/help_general.html"), /*navigable=*/ true); } void MainWindow::on_actionAbout_Qt_triggered() { QMessageBox::aboutQt(this, "About Qt"); } void MainWindow::on_actionAbout_triggered() { QString ddcutil_version = ddca_ddcutil_version_string(); uint8_t build_opts = ddca_build_options(); // QString ans1 = (build_opts & DDCA_BUILT_WITH_ADL) ? "true" : "false"; QString ans2 = (build_opts & DDCA_BUILT_WITH_USB) ? "true" : "false"; QString ans3 = (ddca_is_udf_enabled()) ? "true" : "false"; // QMessageBox mbox; // mbox.setText("About ddcutil"); QString copyright = "Copyright (C) 2014-2022 Sanford Rockowitz\n"; copyright = copyright + "Licensed under the terms of the GNU General Public License (GPL) "; copyright = copyright + "Version 2.0 or later."; QString msg = ""; msg = msg + "ddcui version: " + ddcui_version + "\n"; msg = msg + " User defined features enabled: " + ans3 + "\n\n"; msg = msg + "ddcutil version: " + ddcutil_version + "\n"; // msg = msg + " Built with support for ADL connected monitors: " + ans1 + "\n"; msg = msg + " Built with support for USB connected monitors: " + ans2; msg = msg + "\n\n"; msg = msg + copyright; // mbox.setInformativeText(msg); // mbox.exec(); // QMessageBox::information(this, "..", msg); QMessageBox::about(this, "About ddcui", msg); } // // Slots related to control key events // void MainWindow::keyPressEvent(QKeyEvent * ev) { bool debug = false; TRACEMCF(debug, "Executing"); if (debug) dbgrptQKeyEvent(ev); if (ev->key() == Qt::Key_Control) { // 68 _ctrl_key_is_pressed = true; TRACEMCF(debug, "Control key recognized. Emitting signalControlKeyPressed(true)"); signalControlKeyPressed(true); } QMainWindow::keyPressEvent(ev); ev->ignore(); } void MainWindow::keyReleaseEvent(QKeyEvent * ev) { bool debug = false; TRACEMCF(debug, "Executing"); if (debug) dbgrptQKeyEvent(ev); if (ev->key() == Qt::Key_Control) { // 68 _ctrl_key_is_pressed = false; TRACEMCF(debug, "Control key recognized. Emitting signalControlKeyPressed(false)"); signalControlKeyPressed(false); } QMainWindow::keyPressEvent(ev); ev->ignore(); } // // Archived Unused Slots // #ifdef UNUSED void MainWindow::pageChanged(int pageno) { printf("(%s::%s) pageno: %d\n", _cls, __func__, pageno); fflush(stdout); // std::cout << " objectName: " << objectName.toStdString() << std::endl; showCentralWidgetPage(pageno); } void MainWindow::pageChangedByWidget(QWidget * widget) { printf("(%s::%s) widget=%p\n", _cls, __func__, widget); fflush(stdout); // std::cout << " objectName: " << objectName.toStdString() << std::endl; showCentralWidgetByWidget(widget); } #endif #ifdef UNUSED void MainWindow::on_vcpTableView_clicked(const QModelIndex &index) { printf("-------------> (MainWindow::on_vcpTableView_clicked) row=%d, col=%d\n", index.row(), index.column() ); } void MainWindow::on_vcpTableView_doubleClicked(const QModelIndex &index) { printf("----------> (MainWindow::on_vcpTableView_doubleClicked) row=%d, col=%d\n", index.row(), index.column() ); } #endif ddcui-0.3.0/src/main/mainwindow.h000066400000000000000000000141051427175135000166500ustar00rootroot00000000000000/* mainwindow.h */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include "../base/nc_values_state.h" #include "cmdline/ddcui_parsed_cmd.h" #include "base/core.h" #include "base/user_interface_options_state.h" #include "nongui/msgbox_queue.h" class DebugActionsDialog; class FeatureBaseModel; class FeatureSelectionDialog; class FeatureSelector; class Monitor; class MsgBoxQueue; class MsgBoxThread; class NcValuesDialog; class NcValuesState; class QMessageBox; class UserInterfaceOptionsDialog; class UserInterfaceOptionsState; class VcpThread; // namespace Ui { // class MainWindow; // } class Ui_MainWindow; class MainWindow : public QMainWindow // , public PageChangeObserver { Q_OBJECT // n. MainWindow is also a singleton, combine with GlobalState? // to do, make private, use accessor function // GlobalState & _globalState; public: enum View { NoView, MonitorView, CapabilitiesView, FeaturesView }; // // Constructor, Destructor, Initialization methods // public: // explicit MainWindow(Parsed_Ddcui_Cmd * parsed_cmd, QWidget *parent = 0); ~MainWindow(); // *** public initialization methods void initSerialMsgbox(); void start_msgBoxThread(); // was originally factored out for use as a slot private: void connectBaseModel(Monitor * monitor); void disconnectBaseModel(Monitor * monitor); void freeMonitors(); void initOneMonitor(DDCA_Display_Info * info, int curIndex); void setInitialDisplayIndex(Parsed_Ddcui_Cmd * parsed_cmd); void initMonitors(Parsed_Ddcui_Cmd * parsed_cmd); void loadMonitorFeatures(Monitor * monitor); // // *** Signals // public: signals: void featureSelectionChanged(); void signalMonitorSummaryView(); void signalCapabilitiesView(); void signalFeaturesView(); void userInterfaceOptionsChanged(); #ifdef NOT_NEEDED void signalControlKeyRequired(bool onoff); #endif void showStats(); // needs parm for which void resetStats(); void reportApplicationEventLoopStarted(); void signalControlKeyPressed(bool onoff); // // *** Slots *** // public slots: void longRunningTaskStart(); void longRunningTaskEnd(); void setTransitoryStatusMsg(QString msg); void showSerialMsgBox(QString title, QString text, QMessageBox::Icon icon); void forControlKeyRequired_changed(bool onoff); protected slots: void keyPressEvent(QKeyEvent * ev) override; void keyReleaseEvent(QKeyEvent * ev) override; private slots: // View Menu void on_actionMonitorSummary_triggered(); void on_actionCapabilities_triggered(); void on_actionFeaturesScrollArea_triggered(); // Actions Menu void on_actionRescan_triggered(); void on_actionRedetect_triggered(); void on_actionDebugActionsDialog_triggered(); void for_resetStats_triggered(); void for_reportStats_triggered(DDCA_Stats_Type stats_type, bool showTheadData); // Options Menu void on_actionFeatureSelectionDialog_triggered(); void for_actionFeatureSelectionDialog_accepted(); void on_actionOtherOptionsDialog_triggered(); void on_actionUserInterfaceOptionsDialog_triggered(); void for_actionUserInterfaceOptionsDialog_accept(); #ifdef UNUSED void actionFeatureSelectionDialog_destroyed(QObject * obj); void on_actionFeatureSelection_triggered(); void featureSelectionAccepted(DDCA_Feature_Subset_Id feature_list); void on_actionOtherOptionsDialog_accepted(); #endif // Help Menu void on_actionContentsHelp_triggered(); void on_actionAbout_triggered(); void on_actionAbout_Qt_triggered(); // Tool Bar void displaySelectorCombobox_currentIndexChanged(int index); // void displaySelectorCombobox_activated(int index); // Shortcuts void quitShortcut(); // // *** General methods *** // public: void reportDdcApiError(QString funcname, int rc) const; private: // used only by slotfor_reportStats_triggered() void capture_stats(DDCA_Stats_Type stats_type, bool show_thread_data); void ctrlKeyStatusMsg(); // *** Unused Methods, public and private, all types #ifdef UNUSED void pageChanged(int pageno) override; void pageChangedByWidget(QWidget * widget) override; DDCA_Feature_Subset_Id feature_list_id() const; void set_feature_list_id(DDCA_Feature_Subset_Id feature_list_id); #endif // // *** Member Variables *** // public: UserInterfaceOptionsDialog * _uid = nullptr; FeatureSelector * _feature_selector = nullptr; MsgBoxQueue* _msgBoxQueue = nullptr; MsgBoxThread * _msgBoxThread = nullptr; QMessageBox* _serialMsgBox = nullptr; bool _ctrl_key_is_pressed = false; private: const char * _cls; // Ui::MainWindow* _ui; Ui_MainWindow * _ui; // DDCA_Display_Info_List * _dlist ; DDCA_Display_Ref * _drefs; int _drefs_ct = 0; int _curDisplayIndex = -1; View _curView = NoView; QComboBox * _toolbarDisplayCB; NcValuesState * _otherOptionsState = nullptr; UserInterfaceOptionsState* _uiOptionsState = nullptr; QVector _monitors; DDCA_Feature_Subset_Id _feature_list_id = DDCA_SUBSET_KNOWN; QVector _vcp_threads; QMessageBox* _loadingMsgBox; // Accumulates messages that will be shown in the SerialMsgBox once // initialization is sufficiently complete. Not needed. // QList _deferredMsgs; FeatureSelectionDialog* _fsd = nullptr; NcValuesDialog* _ood = nullptr; // for future use QShortcut * _quit_shortcut = nullptr; QLabel* _ctlMsg = new QLabel("CTRL key required to change feature values"); }; #endif // MAINWINDOW_H ddcui-0.3.0/src/main/mainwindow_ui.cpp000066400000000000000000000256041427175135000177060ustar00rootroot00000000000000/** \file mainwindow_ui.cpp */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // Note: This file cannot be named ui_mainwindow.cpp. // The cmake autouic directive regards the "ui_" prefix as special. // If a cpp file starts with "ui_", cmake looks for a corresponding // file with extension .ui to process. #include "base/core.h" #include "mainwindow_ui.h" #ifdef DEBUG static void dbgrptQKeyEvent(QKeyEvent * event) { printf(" key: %d\n", event->key()); printf(" modifiers: 0x%x\n", (unsigned int) event->modifiers()); printf(" nativeModifiers: 0x%08x\n", event->nativeModifiers()); printf(" nativeScanCode: 0x%08x\n", event->nativeScanCode()); } #endif Ui_MainWindow::Ui_MainWindow(QMainWindow* mainWindow) : _mainWindow(mainWindow) { bool debug = false; TRACECF(debug, "Starting"); setupUi(mainWindow); TRACECF(debug, "Done"); } void Ui_MainWindow::initActions(QMainWindow * MainWindow) { // View Menu Actions // n. QMetaObject::connectSlotsByName() depends on object name, // must match action__triggered() actionMonitorSummary = new QAction(MainWindow); actionMonitorSummary->setObjectName(QString::fromUtf8("actionMonitorSummary")); actionMonitorSummary->setCheckable(true); actionCapabilities = new QAction(MainWindow); actionCapabilities->setObjectName(QString::fromUtf8("actionCapabilities")); actionCapabilities->setCheckable(true); actionFeaturesScrollArea = new QAction(MainWindow); actionFeaturesScrollArea->setObjectName(QString::fromUtf8("actionFeaturesScrollArea")); actionFeaturesScrollArea->setCheckable(true); QActionGroup* viewGroup = new QActionGroup(MainWindow); viewGroup->addAction(actionMonitorSummary); viewGroup->addAction(actionCapabilities); viewGroup->addAction(actionFeaturesScrollArea); // actionMonitorSummary->setChecked(true); // ??? // Options->Feature Selection Dialog Actions // Feature Selection menu action actionFeatureSelectionDialog = new QAction(MainWindow); actionFeatureSelectionDialog->setObjectName(QString::fromUtf8("actionFeatureSelectionDialog")); actionFeatureSelectionDialog->setText( QApplication::translate("MainWindow", "&Feature Selection...", nullptr, -1)); actionFeatureSelectionDialog->setFont(mainMenuFont); // Options menu actions actionOtherOptionsDialog = new QAction(MainWindow); actionOtherOptionsDialog->setObjectName(QString::fromUtf8("actionOtherOptionsDialog")); actionOtherOptionsDialog->setText( QApplication::translate("MainWindow", "&NC Feature Values...", nullptr, -1)); // was "&Other Options" actionOtherOptionsDialog->setFont(mainMenuFont); // User Interface menu action actionUserInterfaceOptionsDialog = new QAction(MainWindow); actionUserInterfaceOptionsDialog->setObjectName(QString::fromUtf8("actionUserInterfaceOptionsDialog")); actionUserInterfaceOptionsDialog->setText( QApplication::translate("MainWindow", "&User Interface...", nullptr, -1)); actionUserInterfaceOptionsDialog->setFont(mainMenuFont); actionDebugActionsDialog = new QAction(MainWindow); // n.b. objectName used by connectSlotsByName() actionDebugActionsDialog->setObjectName(QString::fromUtf8("actionDebugActionsDialog")); actionDebugActionsDialog->setText( QApplication::translate("MainWindow", "&Execution Statistics...", nullptr, -1)); actionDebugActionsDialog->setFont(mainMenuFont); // Actions Menu Actions actionRescan = new QAction(MainWindow); actionRescan->setObjectName(QString::fromUtf8("actionRescan")); actionRedetect = new QAction(MainWindow); actionRedetect->setObjectName(QString::fromUtf8("actionRedetect")); // ?? // QActionGroup* actionsGroup = new QActionGroup(MainWindow); // actionsGroup->addAction(actionRescan); // actionsGroup->addAction(actionRescan); // Help Menu Actions actionContentsHelp = new QAction(MainWindow); actionContentsHelp->setObjectName(QString("actionContentsHelp")); actionAbout = new QAction(MainWindow); actionAbout->setObjectName(QString::fromUtf8("actionAbout")); actionAboutQt = new QAction(MainWindow); actionAboutQt->setObjectName(QString::fromUtf8("actionAbout_Qt")); } void Ui_MainWindow::setupMenus(QMainWindow *MainWindow) { // Menu Bar menuBar = new QMenuBar(MainWindow); menuBar->setObjectName(QString::fromUtf8("menuBar")); menuBar->setFont(mainMenuFont); // menuBar->setGeometry(QRect(0, 0, 800, 30)); // character shortcuts in menubar don't work, are passed to the // display combo box menuView = new QMenu(menuBar); menuView->setObjectName(QString::fromUtf8("menuView")); menuView->setTitle( QApplication::translate("MainWindow", "View", nullptr, -1)); menuView->setFont(mainMenuFont); // sets the font for menu entries // menuDisplays = new QMenu(menuBar); // menuDisplays->setObjectName(QString::fromUtf8("menuDisplays")); // menuDisplays->setTitle(QApplication::translate("MainWindow", "Displays", 0)); menuActions = new QMenu(menuBar); menuActions->setObjectName(QString::fromUtf8("menuActions")); menuActions->setTitle( QApplication::translate("MainWindow", "Actions", nullptr, -1)); menuActions->setFont(mainMenuFont); // font for Actions menu entries menuOptions = new QMenu(menuBar); menuOptions->setObjectName(QString::fromUtf8("menuOptions")); menuOptions->setTitle( QApplication::translate("MainWindow", "Options", nullptr, -1)); menuOptions->setFont(mainMenuFont); menuOptions->addAction(actionFeatureSelectionDialog); menuOptions->addAction(actionOtherOptionsDialog); menuOptions->addAction(actionUserInterfaceOptionsDialog); menuHelp = new QMenu(menuBar); menuHelp->setObjectName(QString::fromUtf8("menuHelp")); menuHelp->setTitle( QApplication::translate("MainWindow", "Help", nullptr, -1)); menuHelp->setFont(mainMenuFont); MainWindow->setMenuBar(menuBar); // Menu Bar actions menuBar->addAction(menuView->menuAction()); // menuBar->addAction(menuDisplays->menuAction()); menuBar->addAction(menuActions->menuAction()); menuBar->addAction(menuOptions->menuAction()); menuBar->addAction(menuHelp->menuAction()); menuView->addAction(actionMonitorSummary); menuView->addAction(actionCapabilities); menuView->addAction(actionFeaturesScrollArea); actionMonitorSummary->setText( QApplication::translate("MainWindow", "&Monitor Summary", nullptr, -1)); actionCapabilities->setText( QApplication::translate("MainWindow", "&Capabilities", nullptr, -1)); actionFeaturesScrollArea->setText(QApplication::translate("MainWindow", "&Features", nullptr, -1)); actionRescan->setText( QApplication::translate("MainWindow", "Rescan Feature &Values", nullptr, -1)); actionMonitorSummary->setEnabled(false); actionCapabilities->setEnabled(false); actionFeaturesScrollArea->setEnabled(false); actionRescan->setFont(mainMenuFont); actionRescan->setEnabled(false); actionRedetect->setText( QApplication::translate("MainWindow", "Re&detect Displays", nullptr, -1)); actionRedetect->setEnabled(true); actionRedetect->setFont(mainMenuFont); menuActions->addAction(actionRedetect); menuActions->addAction(actionRescan); menuActions->addAction(actionDebugActionsDialog); menuHelp->addAction(actionContentsHelp); menuHelp->addAction(actionAbout); menuHelp->addAction(actionAboutQt); actionContentsHelp->setText(QApplication::translate( "MainWindow", "&Contents...", nullptr, -1)); actionContentsHelp->setFont(mainMenuFont); actionAbout->setText(QApplication::translate( "MainWindow", "About ddcui", nullptr, -1)); actionAbout->setFont(mainMenuFont); actionAboutQt->setText(QApplication::translate("MainWindow", "About Qt", nullptr, -1)); actionAboutQt->setFont(mainMenuFont); // Tool Bar mainToolBar = new QToolBar(MainWindow); mainToolBar->setObjectName(QString::fromUtf8("mainToolBar")); MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar); // Status Bar statusBar = new QStatusBar(MainWindow); statusBar->setObjectName(QString::fromUtf8("statusBar")); statusBar->setFont(mainMenuFont); MainWindow->setStatusBar(statusBar); } void Ui_MainWindow::layoutCentralWidget(QMainWindow *MainWindow) { centralWidget = new QStackedWidget(MainWindow); centralWidget->setObjectName(QString::fromUtf8("centralWidget/views_stackedWidget")); QSizePolicy sizePolicy1(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); sizePolicy1.setHorizontalStretch(1); sizePolicy1.setVerticalStretch(1); sizePolicy1.setHeightForWidth(false); centralWidget->setSizePolicy(sizePolicy1); centralWidget->setMinimumSize(QSize(740, 400)); // affected by contents width // centralWidget->setMaximumSize(QSize(2000, 16777215)); centralWidget->setSizeIncrement(QSize(10, 10)); centralWidget->setFrameShape(QFrame::Panel); centralWidget->setFrameShadow(QFrame::Sunken); MainWindow->setCentralWidget(centralWidget); // reportWidgetChildren(centralWidget, "Children of centralWidget:"); // printf("(%s) Number of widgets contained by centralWidget: %d\n", // __func__, centralWidget->count() ); fflush(stdout); } void Ui_MainWindow::setupUi(QMainWindow *MainWindow) { bool debug = false; TRACECF(debug, "Starting"); // std::cout << "(setupUi) Starting" << std::endl; if (MainWindow->objectName().isEmpty()) MainWindow->setObjectName(QString::fromUtf8("MainWindow")); // MainWindow->resize(800, 400); // set MainWindow size policy QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); sizePolicy.setHorizontalStretch(1); sizePolicy.setVerticalStretch(1); // sizePolicy.setHeightForWidth(MainWindow->sizePolicy().hasHeightForWidth()); sizePolicy.setHeightForWidth(false); MainWindow->setSizePolicy(sizePolicy); // mainMenuFont = Styles::instance().mainMenuFont(); mainMenuFont = MainMenuFont2; initActions(MainWindow); layoutCentralWidget(MainWindow); setupMenus(MainWindow); MainWindow->setWindowTitle(QApplication::translate("MainWindow", "ddcui - Control Display Settings", nullptr, -1)); #ifdef UNUSED retranslateFeatureSelectionDialog(); #endif centralWidget->setCurrentIndex(0); // printf("(Ui_MainWindow::setupUi) Calling connectSlotsByName()...\n"); fflush(stdout); QMetaObject::connectSlotsByName(MainWindow); // std::cout << "(setupUi) Done" << std::endl; TRACECF(debug, "Done"); } // setupUi #ifdef FAILS void Ui_MainWindow::keyPressEvent(QKeyEvent * evt) { void dbgrptQKeyEvent(evt) switch (evt->key()) { case Qt::Key_H: menuHelp->menuAction(); // no event // menuHelp->trigger(); // doesn't compile break; } evt->accept(); } #endif ddcui-0.3.0/src/main/mainwindow_ui.h000066400000000000000000000051221427175135000173440ustar00rootroot00000000000000/* mainwindow_ui.h - Extracted from uic generated ui code */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef UI_MAINWINDOW2_H #define UI_MAINWINDOW2_H #include #include #include #include #include #include #include #include #include #include #include "base/core.h" #include "base/widget_debug.h" // QT_BEGIN_NAMESPACE class Ui_MainWindow { public: Ui_MainWindow(QMainWindow* mainWindow); private: QMainWindow * _mainWindow; // Menu Bar QMenuBar *menuBar = NULL; QMenu *menuView = NULL; QMenu *menuOptions = NULL; QMenu *menuActions = NULL; QMenu *menuHelp = NULL; public: // View Menu QAction *actionMonitorSummary= NULL; QAction *actionCapabilities= NULL; // Actions Menu QAction *actionRedetect = NULL; QAction *actionRescan = NULL; QAction *actionDebugActionsDialog = NULL; QAction *actionFeaturesScrollArea = NULL; QAction *actionUserInterfaceOptionsDialog = NULL; private: // Options Menu #ifdef IS_THIS_NEEDED QAction *actionFeatureSelection= NULL; QAction *actionShowUnsupportedFeatures= NULL; QAction *actionKnown= NULL; QAction *actionScan= NULL; QAction *actionColor= NULL; QAction *actionProfile = NULL; QAction *actionManufacturer = NULL; #endif QAction *actionFeatureSelectionDialog = NULL; QAction *actionOtherOptionsDialog = NULL; // Help Menu QAction *actionContentsHelp; QAction *actionAbout= NULL; QAction *actionAboutQt= NULL; #ifdef NOTHING_TO_OVERRIDE protected: void keyPressEvent(QKeyEvent * evt) override; #endif public: // Tool Bar QToolBar *mainToolBar= NULL; // Status Bar QStatusBar *statusBar= NULL; // Other QStackedWidget *centralWidget = NULL; QFont mainMenuFont; private: void initActions(QMainWindow * mainWindow); #ifdef UNUSED void retranslateFeatureSelectionDialog(); #endif void setupMenus(QMainWindow *MainWindow); void layoutCentralWidget(QMainWindow *MainWindow); // public: void setupUi(QMainWindow *MainWindow); private: const char * _cls = "UiMainWindow"; }; // namespace Ui { // class MainWindow: public Ui_MainWindow {}; // } // namespace Ui // QT_END_NAMESPACE #endif // UI_MAINWINDOW2_H ddcui-0.3.0/src/main/monitor.cpp000066400000000000000000000140211427175135000165130ustar00rootroot00000000000000/* monitor.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "base/monitor.h" #include #include #include #include #include "base/core.h" #include "nongui/vcpthread.h" // includes vcprequest.h #include "nongui/feature_value.h" Monitor::Monitor(DDCA_Display_Info * display_info, int monitorNumber) : _monitorNumber(monitorNumber) , _displayInfo(display_info) , _baseModel(NULL) , _requestQueue(NULL) , _cls( strdup(metaObject()->className()) ) { bool debug = false; TRACECF(debug, "Starting. monitorNumber=%d, dispno=%d, dref=%s", monitorNumber, display_info->dispno, ddca_dref_repr(display_info->dref)); _page_moninfo = _page_capabilities = NULL; _pageno_moninfo = _pageno_capabilities = 0; _moninfoPlainText = _capabilitiesPlainText = NULL; _vcpThread = NULL; // ddca_report_display_info(_displayInfo, 3); if (supportsDdc()) { _requestQueue = new VcpRequestQueue(); _baseModel = new FeatureBaseModel(this); // baseModel->setObjectName(QString::asprintf("baseModel-%s",ddca_dref_repr(_displayInfo->dref)); _vcpThread = new VcpThread(NULL, _displayInfo, _requestQueue, _baseModel); // never triggered ?? QObject::connect(_vcpThread, &VcpThread::finished, this, &Monitor::vcpThreadFinished); _vcpThread->start(); // _vcp_threads.append(curThread); QObject::connect(_baseModel, SIGNAL(signalVcpRequest(VcpRequest*)), this, SLOT( putVcpRequest(VcpRequest*))); } TRACECF(debug, "Done. _monitorNumber=%d, dref: %s", _monitorNumber, ddca_dref_repr(_displayInfo->dref)); // if (debug) // ddca_report_display_info(_displayInfo, 3); } Monitor::~Monitor() { bool debug = false; TRACECF(debug, "Starting. monitor=%p, _monitor_number=%d, _displayInfo->dispno=%d, _baseModel=%p", this, _monitorNumber, _displayInfo->dispno, _baseModel); if (supportsDdc()) { _requestQueue->put(new HaltRequest()); // wait for halt while (!_vcpThread->isFinished()) { TRACECF(debug, "Waiting for _vcpThread to finish"); QThread::msleep(100); } TRACECF(debug, "_vcpThread finished"); QObject::disconnect(_baseModel, SIGNAL(signalVcpRequest(VcpRequest*)), this, SLOT( putVcpRequest(VcpRequest*))); delete _requestQueue; delete _vcpThread; delete _baseModel; } ddca_free_display_info(_displayInfo); TRACECF(debug, "Done"); free((void*) _cls); } void Monitor::dbgrpt() { printf("_monitorNumber: %d\n", _monitorNumber); printf("_displayInfo->dref: %p -> %s\n", _displayInfo->dref, ddca_dref_repr(_displayInfo->dref)); fflush(stdout); } DDCA_Display_Ref Monitor::getDref() { return _displayInfo->dref; } QString Monitor::dref_repr() { if (!_displayInfo->dref) return QString("No dref"); else return QString( ddca_dref_repr(_displayInfo->dref) ); } DDCA_Feature_List Monitor::getFeatureList(DDCA_Feature_Subset_Id feature_list_id) { bool debugFunc = debugFeatureLists; debugFunc = false; TRACECF(debugFunc, "feature_list_id=%d-%s",feature_list_id, ddca_feature_list_id_name(feature_list_id)); bool include_table_features = false; // TODO get from feature selection dialog DDCA_Status ddcrc = 0; DDCA_Feature_List result; if (_features.contains(feature_list_id)) { result = _features.value(feature_list_id); } else { // ddca_report_display_info(_displayInfo, 3); ddcrc = ddca_get_feature_list_by_dref( feature_list_id, _displayInfo->dref, include_table_features, &result); TRACECF(debugFunc, "ddca_get_feature_list_by_dref() returned %d", ddcrc); if (ddcrc == 0) { // hack if (feature_list_id == DDCA_SUBSET_KNOWN) { DDCA_Feature_List mfgFeatureList; ddcrc = ddca_get_feature_list_by_dref( DDCA_SUBSET_MFG, _displayInfo->dref, include_table_features, &mfgFeatureList); TRACECF(debugFunc, "ddca_get_feature_list_by_dref(DDCA_SUBSET_MFG) returned %d", ddcrc); if (ddcrc == 0) { result = ddca_feature_list_or(result, mfgFeatureList); } } _features.insert(feature_list_id, result); } } TRACECF(debugFunc, "Returning: %d features: %s", ddca_feature_list_count(result), ddca_feature_list_string(result, NULL, (char*)" ")); return result; } // consider replacing 2 booleans with an enum with 3 states bool Monitor::capabilitiesCheckComplete() { bool debug = false; // considered complete if invalid display bool result = (supportsDdc()); if (result) result = (_baseModel->_caps_check_complete); TRACECF(debug, "dref=%s, returning %s", QS2S(dref_repr()), SBOOL(result)); return result; } bool Monitor::capabilitiesCheckSuccessful() { bool debug = false; bool result = (_displayInfo->dispno > 0); // dispno -1 if API found display invalid, -2 if phantom if (result) result = (_baseModel->_caps_status == 0 && _baseModel->_parsed_caps); // got capabilities? TRACECF(debug, "dref=%s, returning %s", QS2S(dref_repr()), SBOOL(result)); return result; } bool Monitor::supportsDdc() { bool debug = false; bool result = (_displayInfo->dispno > 0); // dispno -1 if API found display invalid, -2 if phantom TRACECF(debug, "dref=%s, returning %s", QS2S(dref_repr()), SBOOL(result)); return result; } // called by initFeaturesScrollAreaView void Monitor::putVcpRequest(VcpRequest * rqst) { bool debug = false; TRACECF(debug, "-> rqst->type=%d. Adding request to monitor's request queue", rqst->_type); _requestQueue->put(rqst); } // never called! void Monitor::vcpThreadFinished() { bool debug = true; TRACECF(debug, "vcp thread finished"); } ddcui-0.3.0/src/main/msgbox_thread.cpp000066400000000000000000000054421427175135000176610ustar00rootroot00000000000000/** \file msgbox_thread.cpp * * This thread reads from a queue of error messages to be displayed in a * dialog box. This avoids a flurry of simultaneous dialog boxes. */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include "base/core.h" #include "main/msgbox_thread.h" static bool debugThread = false; MsgBoxThread::MsgBoxThread(MsgBoxQueue* requestQueue) : QThread() , _requestQueue(requestQueue) { // bool debug = false; TRACECF(debugThread, "Executing"); _semaphore = new QSemaphore(1); } void MsgBoxThread::msbgoxClosed(int result) { TRACECF(debugThread, "Releasing semaphore"); _semaphore->release(); } void MsgBoxThread::run() { #ifdef NO // If this thread starts reading before the QApplication's event loop, // the dialog box will not appear on top of the main window // Trying to delay by triggering off a signal that the main event loop // has started // DIDN'T SOLVE PROBLEM. #endif // Crude but effective. Just sleep before starting loop reading messages and // displaying SerialMsgBox long initial_sleep_millis = MSGBOX_THREAD_RUN_DELAY_MILLIS; TRACECF(debugThread, "Sleeping for %d milliseconds", initial_sleep_millis); QThread::msleep(initial_sleep_millis); TRACECF(debugThread, "Initial sleep complete"); forever { TRACECF(debugThread, "Waiting to pop"); fflush(stdout); MsgBoxQueueEntry * rqst = this->_requestQueue->pop(); TRACECF(debugThread, "Popped: _boxTitle: %s, _boxText: %s", QS2S(rqst->_boxTitle), QS2S(rqst->_boxText)); _semaphore->acquire(); TRACECF(debugThread, "Acquired semaphore"); emit postSerialMsgBox(rqst->_boxTitle, rqst->_boxText, rqst->_boxIcon); // requires MainWindow; clearer since MainWindow::showSerialMsgBox is what gets called // but would require knowing MainWindow // showSerialMsgBox(rqst->_boxTitle, rqst->_boxText, rqst->_boxIcon); delete rqst; } } #ifdef NO void MsgBoxThread::showSerialMsgBox(QString title, QString text, QMessageBox::Icon icon) { // #ifdef DIALOG_BOX_STILL_ON_SEPARATE_SCREEN QMessageBox * serialMbox2 = new QMessageBox(parent); serialMbox2->setStandardButtons(QMessageBox::Ok); serialMbox2->setWindowModality(Qt::WindowModal); serialMbox2->setModal(true); // serialMbox2->setFont(_ui->mainMenuFont); serialMbox2->setText(text); serialMbox2->setWindowTitle(title); serialMbox2->setIcon(icon); QObject::connect( serialMbox2, &QMessageBox::finished, this, &MsgBoxThread::msbgoxClosed ); serialMbox2->exec(); } #endif ddcui-0.3.0/src/main/msgbox_thread.h000066400000000000000000000017471427175135000173320ustar00rootroot00000000000000/** \file msgbox_thread.h * * This thread reads from a queue of error messages to be displayed in a * dialog box. This avoids a flurry of simultaneous dialog boxes. */ // Copyright (C) 2020 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef MSGBOX_THREAD_H #define MSGBOX_THREAD_H #include #include #include #include "nongui/msgbox_queue.h" class QString; class MsgBoxThread : public QThread { Q_OBJECT public: MsgBoxThread(MsgBoxQueue *requestQueue); void run() override; signals: void postSerialMsgBox(QString boxTitle, QString boxText, QMessageBox::Icon boxIcon); public slots: void msbgoxClosed(int result); private: // void showSerialMsgBox(QString title, QString text, QMessageBox::Icon icon); const char * _cls = "MsgBoxThread"; MsgBoxQueue * _requestQueue = nullptr; QSemaphore * _semaphore = nullptr; }; #endif // MSGBOX_THREAD_H ddcui-0.3.0/src/monitor_desc/000077500000000000000000000000001427175135000160635ustar00rootroot00000000000000ddcui-0.3.0/src/monitor_desc/monitor_desc_actions.cpp000066400000000000000000000034111427175135000227730ustar00rootroot00000000000000// monitor_desc_actions.cpp // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include "ddcutil_c_api.h" #include "base/monitor.h" #include "nongui/feature_base_model.h" #include "monitor_desc_actions.h" namespace MonitorDescActions { char * capture_display_info_report( DDCA_Display_Info * dinfo) { bool debug = false; if (debug) { printf("(%s) Starting. dinfo=%p\n", __func__, (void*)dinfo); fflush(stdout); } ddca_start_capture(DDCA_CAPTURE_NOOPTS); DDCA_Output_Level saved_ol = ddca_set_output_level(DDCA_OL_VERBOSE); ddca_report_display_info(dinfo, 0); ddca_set_output_level(saved_ol); char * s = ddca_end_capture(); if (debug) { printf("(%s) Done.\n", __func__); fflush(stdout); } return s; } DDCA_Status capture_capabilities_report( Monitor * monitor, DDCA_Display_Ref dref, char ** caps_report_loc) { *caps_report_loc = NULL; DDCA_Status ddcrc = 0; // Hacky. Need to handle async, wait if caps not yet fetched ddcrc = monitor->_baseModel->_caps_status; if (ddcrc == 0) { DDCA_Capabilities *parsed_caps = monitor->_baseModel->_parsed_caps; // DDCA_Monitor_Model_Key mmid = ddca_monitor_model_key_from_dref(dref); // wrap in collector DDCA_Output_Level saved_ol = ddca_get_output_level(); ddca_set_output_level(DDCA_OL_VERBOSE); ddca_start_capture(DDCA_CAPTURE_NOOPTS); ddca_report_parsed_capabilities_by_dref(parsed_caps, dref, 0); char * caps_report = ddca_end_capture(); ddca_set_output_level(saved_ol); *caps_report_loc = caps_report; } return ddcrc; } } // namespace MonitorDescActions ddcui-0.3.0/src/monitor_desc/monitor_desc_actions.h000066400000000000000000000011021427175135000224330ustar00rootroot00000000000000// monitor_desc_actions.h // Copyright (C) 2018 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef MONITOR_DESC_ACTIONS_H_ #define MONITOR_DESC_ACTIONS_H_ #include "ddcutil_c_api.h" #include "base/monitor.h" namespace MonitorDescActions { char * capture_display_info_report( DDCA_Display_Info * dinfo); DDCA_Status capture_capabilities_report( Monitor * monitor, DDCA_Display_Ref dref, char ** caps_report_loc); } // namespace MonitorDescActions #endif /* MONITOR_DESC_ACTIONS_H_ */ ddcui-0.3.0/src/monitor_desc/monitor_desc_ui.cpp000066400000000000000000000073451427175135000217620ustar00rootroot00000000000000// monitor_desc_ui.cpp // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "monitor_desc/monitor_desc_ui.h" #include #include #include #include #include // #include #include "base/monitor.h" // Common initialization for monitor info and capabilities static void initPlaintextWidget( const char * name, int monitorNumber, QStackedWidget * stackedWidget, // central widget of GUI QWidget ** page_loc, int * pageno_loc, QPlainTextEdit ** pagePlainText_loc) { // TODO: CLEAN UP AND SIMPLIFY! QSizePolicy sizePolicy1(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); // not needed // sizePolicy1.setHorizontalStretch(1); // sizePolicy1.setVerticalStretch(1); // sizePolicy1.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); sizePolicy1.setHeightForWidth(false); // Layout stacked widget page: page_widget, contains moninfoPlainText QWidget * page_widget = new QWidget(); QPlainTextEdit *plainTextWidget; // sizePolicy1.setHeightForWidth(page_widget->sizePolicy().hasHeightForWidth()); page_widget->setSizePolicy(sizePolicy1); plainTextWidget = new QPlainTextEdit(page_widget); plainTextWidget->setObjectName(QString::asprintf("plainTextWidget-%s-%d", name, monitorNumber)); plainTextWidget->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); plainTextWidget->setGeometry(QRect(6, 6, 700, 191)); // was 574,191 // sizePolicy1.setHeightForWidth(plainTextWidget->sizePolicy().hasHeightForWidth()); plainTextWidget->setSizePolicy(sizePolicy1); plainTextWidget->setMaximumSize(QSize(2000, 16777215)); // 574->2000 // plainTextWidget->setLineWrapMode(QPlainTextEdit::NoWrap); plainTextWidget->setLineWrapMode(QPlainTextEdit::WidgetWidth); plainTextWidget->setReadOnly(true); QFont fixedFont("Courier"); fixedFont.setPointSize(10); plainTextWidget->setFont(fixedFont); // AMEN! QHBoxLayout * pageMoninfoLayout = new QHBoxLayout(page_widget); pageMoninfoLayout->setSpacing(6); // pageMoninfoLayout->setContentsMargins(11, 11, 11, 11); pageMoninfoLayout->setObjectName(QString::asprintf("pageLayout-%s-%d", name, monitorNumber)); pageMoninfoLayout->addWidget(plainTextWidget); int pageno_widget = stackedWidget->count(); stackedWidget->addWidget(page_widget); page_widget->setObjectName( QString::asprintf("page_widget-%s-%d-pageno-%d", name, monitorNumber, pageno_widget)); *page_loc = page_widget; *pageno_loc = pageno_widget; *pagePlainText_loc = plainTextWidget; } QWidget * initMonitorInfoWidget( Monitor * curMonitor, QStackedWidget * stackedWidget) { initPlaintextWidget( "MonitorInfo", curMonitor->_monitorNumber, // 1 based stackedWidget, &curMonitor->_page_moninfo, &curMonitor->_pageno_moninfo, &curMonitor->_moninfoPlainText); return curMonitor->_page_moninfo; } QWidget * initCapabilitiesWidget( Monitor * curMonitor, QStackedWidget * stackedWidget) { initPlaintextWidget( "Capabilities", curMonitor->_monitorNumber, // 1 based stackedWidget, &curMonitor->_page_capabilities, &curMonitor->_pageno_capabilities, &curMonitor->_capabilitiesPlainText); return curMonitor->_page_capabilities; } ddcui-0.3.0/src/monitor_desc/monitor_desc_ui.h000066400000000000000000000010701427175135000214140ustar00rootroot00000000000000// monitor_desc_ui.h // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later/endcopyright> #ifndef MONITOR_DESC_UI_H_ #define MONITOR_DESC_UI_H_ class QWidget; class Monitor; class QStackedWidget; QWidget * initMonitorInfoWidget( Monitor * curMonitor, QStackedWidget * stackedWidget); // central widget of GUI QWidget * initCapabilitiesWidget( Monitor * curMonitor, QStackedWidget * stackedWidget); // central widget of GUI #endif /* MONITOR_DESC_UI_H_ */ ddcui-0.3.0/src/nongui/000077500000000000000000000000001427175135000146755ustar00rootroot00000000000000ddcui-0.3.0/src/nongui/.gitignore000066400000000000000000000000101427175135000166540ustar00rootroot00000000000000unused/ ddcui-0.3.0/src/nongui/ddca_simulator.cpp000066400000000000000000000106711427175135000204000ustar00rootroot00000000000000// ddca_simulator.cpp // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "ddcutil_status_codes.h" #include "ddcutil_types.h" #include "ddcutil_c_api.h" #include #include "base/core.h" #include "ddca_simulator.h" typedef struct { uint8_t feature_code; const char * feature_name; DDCA_MCCS_Version_Spec vspec; DDCA_Status ddcrc; uint8_t mh; uint8_t ml; uint8_t sh; uint8_t sl; } SimTableEntry; SimTableEntry simTable[] = { {0x62, "Volume", DDCA_VSPEC_V21, DDCRC_OK, 0,100, 0, 50}, {0x62, "Volume", DDCA_VSPEC_V22, DDCRC_OK, 0,0,0,20}, {0x8f, "Audio treble", DDCA_VSPEC_V21, DDCRC_OK, 0,100,0,30}, {0x8f, "Audio treble", DDCA_VSPEC_V22, DDCRC_OK, 0,0,0,50}, {0x91, "Audio bass", DDCA_VSPEC_V21, DDCRC_DETERMINED_UNSUPPORTED, 0,0,0,0}, {0x91, "Audio bass", DDCA_VSPEC_V22, DDCRC_DETERMINED_UNSUPPORTED, 0,0,0,0}, // {0x10, "Brightness", DDCA_VSPEC_V21, DDCRC_DDC_DATA, 0,0,0,0} {0x1a, "Blue Gain", DDCA_VSPEC_V21, DDCRC_DDC_DATA, 0,0,0,0} }; int simTableCt = sizeof(simTable)/sizeof(SimTableEntry); // Maintains values that have been set by simulated ddca_set_non_table_vcp_value(): QHash simVals; static bool vspec_eq(DDCA_MCCS_Version_Spec vspec1, DDCA_MCCS_Version_Spec vspec2) { bool result = false; if (vspec1.major == vspec2.major && vspec1.minor == vspec2.minor) result = true; return result; } int findSimTableEntry(uint8_t feature_code, DDCA_MCCS_Version_Spec vspec) { int result = -1; for (int ndx = 0; ndx < simTableCt; ndx++) { if (simTable[ndx].feature_code == feature_code && vspec_eq( simTable[ndx].vspec, vspec) ) { result = ndx; break; } } // printf("(%s) feature_code=0x%02x, vspec=%d.%d, returning %d\n", // __func__, feature_code, vspec.major, vspec.minor, result); return result; } DdcaSimulator::DdcaSimulator() { _cls = strdup(metaObject()->className()); } DdcaSimulator::~DdcaSimulator() { free((void*)_cls); } bool DdcaSimulator::DdcaSimulator::simulateGetNonTableVcpValue( DDCA_MCCS_Version_Spec vspec, DDCA_Display_Handle dh, uint8_t featureCode, DDCA_Non_Table_Vcp_Value* valrec, DDCA_Status * pddcrc) { bool debug = true; if (!simulationEnabled) return false; bool simulated = false; DDCA_Status ddcrc = DDCRC_DETERMINED_UNSUPPORTED; int ndx = findSimTableEntry(featureCode, vspec); if (ndx >= 0) { valrec->mh = simTable[ndx].mh; valrec->ml = simTable[ndx].ml; valrec->sh = simTable[ndx].sh; valrec->sl = simTable[ndx].sl; ddcrc = simTable[ndx].ddcrc; if (ddcrc == DDCRC_OK) { if (simVals.contains(featureCode)) { // override with value set by a previous call uint16_t savedVal = simVals.value(featureCode); valrec->sh = savedVal >> 8; valrec->sl = savedVal & 0xff; // TRACEC("feature 0x%02x, returning simulated sh=0x%02x, sl=0x%02x", // featureCode, valrec->sh, valrec->sl); } } *pddcrc = ddcrc; simulated = true; } if (simulated) TRACECF(debug, "Feature 0x%02x, vspec=%d.%d, returning %s. ddcrc=%s. mh=0x%02x, ml=0x%02x, sh=0x%02x, sl=0x%02x", featureCode, vspec.major, vspec.minor, SBOOL(simulated), ddca_rc_name(ddcrc), valrec->mh, valrec->ml, valrec->sh, valrec->sl); return simulated; } bool DdcaSimulator::simulateSetNonTableVcpValue( DDCA_MCCS_Version_Spec vspec, DDCA_Display_Handle dh, uint8_t featureCode, uint8_t sh, uint8_t sl, DDCA_Status * pddcrc) { bool debug = true; if (!simulationEnabled) return false; bool simulated = false; *pddcrc = DDCRC_OK; int ndx = findSimTableEntry(featureCode, vspec); if (ndx >= 0) { uint16_t shsl = sh << 8 | sl; simVals.insert(featureCode, shsl); simulated = true; TRACEC("Simulating set feature 0x%02x, shsl=0x%04x", featureCode, shsl); *pddcrc = DDCRC_OK; } if (simulated) TRACECF(debug, "Feature 0x%02x, vspec=%d.%d. returning %s. ddcrc=%s", featureCode, vspec.major, vspec.minor, SBOOL(simulated), ddca_rc_name(*pddcrc) ); return simulated; } ddcui-0.3.0/src/nongui/ddca_simulator.h000066400000000000000000000021401427175135000200350ustar00rootroot00000000000000// ddca_simulator.h - Basic API call simulator for libddcutil // Copyright (C) 2020-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCA_SIMULATOR_H_ #define DDCA_SIMULATOR_H_ #include #include "ddcutil_types.h" class DdcaSimulator: public QObject { Q_OBJECT public: DdcaSimulator(); ~DdcaSimulator(); bool simulateGetNonTableVcpValue( DDCA_MCCS_Version_Spec vspec, DDCA_Display_Handle dh, uint8_t featureCode, DDCA_Non_Table_Vcp_Value* valrec, DDCA_Status * pddcrc); bool simulateSetNonTableVcpValue( DDCA_MCCS_Version_Spec vspec, DDCA_Display_Handle dh, uint8_t featureCode, uint8_t sh, uint8_t sl, DDCA_Status * pddcrc); private: const char * _cls; // className bool simulationEnabled = false; // eventually make this externally controllable }; #endif /* DDCA_SIMULATOR_H_ */ ddcui-0.3.0/src/nongui/feature_base_model.cpp000066400000000000000000000410451427175135000212120ustar00rootroot00000000000000/* feature_base_model.cpp * * This was the UI independent portion of the data model when trying to use * QListView and QTableView. */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "nongui/feature_base_model.h" #include #include #include #include #include #include #include #include #include "c_util/data_structures.h" #include "base/core.h" #include "base/global_state.h" #include "base/monitor.h" #include "base/ddca_utils.h" #include "nongui/feature_value.h" using namespace std; static bool debugModel = false; FeatureBaseModel::FeatureBaseModel(Monitor * monitor) : _cls(strdup(metaObject()->className())) , _monitor(monitor) { bool debug = false; TRACECF(debug, "Starting. dref=%s", ddca_dref_repr(_monitor->_displayInfo->dref)); setObjectName(QString::asprintf("baseModel-%s",ddca_dref_repr(_monitor->_displayInfo->dref))); _featureValues = new QVector(); #ifdef FEATURE_CHANGE_OBSERVER _featureChangeObservers = new QVector; #endif ddca_feature_list_clear(&_featuresChecked); // Features that need to be reread if feature x14 is changed // There ought to be a cleaner way _featuresTouchedByX14 = DDCA_EMPTY_FEATURE_LIST; ddca_feature_list_add(&_featuresTouchedByX14, 0x16); ddca_feature_list_add(&_featuresTouchedByX14, 0x18); ddca_feature_list_add(&_featuresTouchedByX14, 0x1a); ddca_feature_list_add(&_featuresTouchedByX14, 0x6c); ddca_feature_list_add(&_featuresTouchedByX14, 0x6e); ddca_feature_list_add(&_featuresTouchedByX14, 0x70); ddca_feature_list_add(&_featuresTouchedByX14, 0x0b); ddca_feature_list_add(&_featuresTouchedByX14, 0x0c); TRACECF(debug, "Constructor complete. _monitor -> dispno=%d, model=%s, dref=%p", _monitor->_displayInfo->dispno, _monitor->_displayInfo->model_name, _monitor->_displayInfo->dref); } FeatureBaseModel::~FeatureBaseModel() { bool debug = false; TRACECF(debug, "Executing. _monitor=%p, monitor number %d, dref: %s", _monitor, _monitor->_displayInfo->dispno, _monitor->_displayInfo->dref); delete _featureValues; TRACECF(debug, " _caps+string=%p->%s", _caps_string, _caps_string); free(_caps_string); // raw capabilities ddca_free_parsed_capabilities(_parsed_caps); TRACECF(debug, "Done."); free((void*) _cls); } /** Returns the index of the entry for the specified feature in _feature_values * * \param feature_code * \return index of entry, -1 if not found */ int FeatureBaseModel::modelVcpValueIndex(uint8_t feature_code) { int result = -1; for (int ndx = 0; ndx < _featureValues->count(); ndx++) { FeatureValue * cur = _featureValues->at(ndx); if (cur->featureCode() == feature_code) { result = ndx; break; } } return result; } /** Returns the #FeatureValue instance for the specified feature. * * \param feature_code * \return pointer to FeatureValue instance, NULL if not found */ FeatureValue * FeatureBaseModel::modelVcpValueFind(uint8_t feature_code) { FeatureValue * result = NULL; for (int ndx = 0; ndx < _featureValues->count(); ndx++) { FeatureValue * cur = _featureValues->at(ndx); if (cur->featureCode() == feature_code) { result = cur; break; } } return result; } FeatureValue * FeatureBaseModel::modelVcpValueFilteredFind(uint8_t feature_code) { bool debug = false; FeatureValue * result = NULL; if (ddca_feature_list_contains(_featuresToShow, feature_code)) { result = modelVcpValueFind(feature_code); if (result) { DDCA_Status ddcrc = result->ddcrc(); bool showUnsupported = GlobalState::instance()._mainWindow->_feature_selector->_showUnsupportedFeatures; if (!showUnsupported && (ddcrc == DDCRC_REPORTED_UNSUPPORTED || ddcrc == DDCRC_DETERMINED_UNSUPPORTED)) { TRACECF(debug, "Filtering out feature 0x%02x because UNSUPPORTED", result->featureCode()); result = NULL; } } } return result; } /** Returns a #FeatureValue instance based on its location in * #_featureValues * * \param ndx index in _featureValues vector * \return pointer to FeatureValue instance, NULL if invalid index */ FeatureValue * FeatureBaseModel::modelVcpValueAt(int ndx) const { assert(ndx >= 0); FeatureValue * result = NULL; if (ndx < _featureValues->count() ) result = _featureValues->at(ndx); return result; } /** Returns the number of #FeatureValue instances. */ int FeatureBaseModel::modelVcpValueCount(void) const { return _featureValues->count(); } // IDEA: Separate function for update? // modelVcpValueAdd() // modelVcpValueUpdate() /** Sets the current VCP value in the model. * This function is invoked from VcpThread::getvcp() * * ddcrc != 0 indicates that getvcp failed. * This method notes the error for reporting. * * @param feature_code VCP feature code * @param dref * @param metadata feature metadata * @param feature_value feature value * @param ddcrc */ void FeatureBaseModel::modelVcpValueSet( uint8_t feature_code, DDCA_Display_Ref dref, DDCA_Feature_Metadata * metadata, DDCA_Non_Table_Vcp_Value * feature_value, DDCA_Status ddcrc) { bool debugFunc = false; // || (feature_code == 0x14); debugFunc = debugFunc || debugModel; if (debugFunc) TRACEMCF(debugFunc, "Starting. feature_code=0x%02x, mh=0x%02x, ml=0x%02x, sh=0x%02x, sl=0x%02x, ddcrc = %s, _initialLoadActive=%s", feature_code, feature_value->mh, feature_value->ml, feature_value->sh, feature_value->sl, ddca_rc_name(ddcrc), SBOOL(_initialLoadActive)); int ndx = modelVcpValueIndex(feature_code); if (ndx < 0) { // TRACECF(debugFunc, "Creating new FeatureValue"); DDCA_Cap_Vcp * cap_vcp = NULL; if (_parsed_caps) cap_vcp = ddcutil_find_cap_vcp(_parsed_caps, feature_code); FeatureValue * fv = new FeatureValue( feature_code, dref, metadata, cap_vcp, *feature_value, ddcrc); _featureValues->append(fv); TRACECF(debugFunc, "Created new FeatureValue. id = %d, observedNcValues=%s", fv->_id, bs256_to_string(fv->_observedNcValues, "", " ")); // Not needed, only thing that matters is end initial load // if (debugSignals) // printf("(%s::%s) Emitting signalFeatureAdded()\n", _cls, __func__); fflush(stdout); // emit signalFeatureAdded(*fv); // notifyFeatureChangeObservers(feature_code); // alternative } else { FeatureValue * fv = _featureValues->at(ndx); TRACECF(debugFunc, "Modifying existing FeatureValue, _id=%d, initial _observedNcValues=%s", fv->_id, bs256_to_string(fv->observedNcValues(), ""," " ) ); // fv->_value.sh = feature_value->sh; // fv->_value.sl = feature_value->sl; if ( ddcrc == fv->ddcrc() ) { fv->setCurrentValue(feature_value->sh, feature_value->sl); // sets _observedNcValues TRACECF(debugFunc, "Updated FeatureValue _observedNcValues=%s", bs256_to_string(fv->observedNcValues(), ""," " ) ); TRACECF(debugFunc || debugSignals, "Emitting signalFeatureUpdated3(), feature code: 0x%02x, sl: 0x%02x", fv->featureCode(), feature_value->sl); emit signalFeatureUpdated3(__func__, fv->featureCode(), feature_value->sh, feature_value->sl); } else { TRACEMCF(debugFunc, "Unexpected status code %s for previously read feature 0x%02x", ddca_rc_name(ddcrc), fv->featureCode() ); } } } // called from VcpThread::setvcp() void FeatureBaseModel::modelVcpValueUpdate( uint8_t feature_code, uint8_t sh, uint8_t sl) { bool debugFunc = false; // || (feature_code == 0x14); debugFunc = debugFunc || debugModel; TRACECF(debugFunc, "feature_code=0x%02x, sh=0x%02x, sl=0x%02x, _initialLoadActive=%s", feature_code, sh, sl, SBOOL(_initialLoadActive)); int ndx = modelVcpValueIndex(feature_code); assert (ndx >= 0); FeatureValue * fv = _featureValues->at(ndx); TRACECF(debugFunc, "Found FeatureValue instance, _observedNcValues=%s", bs256_to_string(fv->observedNcValues(), ""," " ) ); // updates fv to the current value, sets _observedNcValues if appropriate fv->setCurrentValue(sh,sl); TRACECF(debugFunc, "Updated FeatureValue: _observedNcValues=%s", bs256_to_string(fv->observedNcValues(), ""," " ) ); TRACECF(debugFunc || debugSignals, "Emitting signalFeatureUpdated3()"); // -> &FeaturesScrollAreaView::onModelValueChanged emit signalFeatureUpdated3(__func__, feature_code, sh, sl); #ifdef FUTURE if (!_initialLoadActive) { if (feature_code == 0x14) { TRACECF(debugFunc, "_featuresTouchedByX14: %s", ddca_feature_list_string(_featuresTouchedByX14, "x", ", ")); TRACECF(debugFunc, "_featuresToShow: %s", ddca_feature_list_string(_featuresToShow, "x", ", ")); DDCA_Feature_List featuresTouched = ddca_feature_list_and(_featuresToShow, _featuresTouchedByX14 ); TRACECF(debugFunc, "featuresTouched: %s", ddca_feature_list_string(featuresTouched, "x", ", ")); // there ought to be an iterator for (int vcp_code = 0; vcp_code < 256; vcp_code++) { if ( ddca_feature_list_contains(featuresTouched, vcp_code) ) { TRACECF(debugFunc, "putting VcpGetRequest for feature 0x%02x on queue", vcp_code); bool needMetadata = false; _monitor->_requestQueue->put( new VcpGetRequest(vcp_code, needMetadata) ); } } } } #endif } // This really belongs in Monitor void FeatureBaseModel::setCapabilities( DDCA_Status ddcrc, char * capabilities_string, DDCA_Capabilities * parsed_capabilities) { bool debug = false; TRACECF(debug, "ddcrc = %s, capabilities_string=|%s|", ddca_rc_name(ddcrc), capabilities_string); _caps_check_complete = true; _caps_status = ddcrc; _caps_string = capabilities_string; _parsed_caps = parsed_capabilities; } #ifdef UNUSED void FeatureBaseModel::modelMccsVersionSet( DDCA_MCCS_Version_Spec vspec) { _vspec = vspec; } DDCA_MCCS_Version_Spec FeatureBaseModel::mccsVersionSpec() { return _vspec; } #endif void FeatureBaseModel::setFeatureList( DDCA_Feature_List featureList) { bool debugFunc = false; debugFunc = debugFunc || debugFeatureLists; TRACECF(debugFunc, "Starting. %d features: %s", ddca_feature_list_count(featureList), ddca_feature_list_string(featureList, NULL, (char*) " ") ); _featuresToShow = featureList; DDCA_Feature_List unchecked_features = ddca_feature_list_and_not(_featuresToShow, _featuresChecked); if (debugFeatureLists) { TRACECF(debugFunc, "Unchecked features: %s", ddca_feature_list_string(unchecked_features, NULL, (char*) " ")); } //bool showUnsupported = _monitor->_curFeatureSelector._showUnsupportedFeatures; // TRACEF(debugFunc, "_monitor->curFeatureSelector._showUnsupportedFeatures = %s", sbool(showUnsupported)); _monitor->_requestQueue->put(new VcpStartInitialLoadRequest); for (int ndx = 0; ndx <= 255; ndx++) { uint8_t vcp_code = (uint8_t) ndx; if ( ddca_feature_list_contains(unchecked_features, vcp_code)) { bool needMetadata = true; _monitor->_requestQueue->put( new VcpGetRequest(vcp_code, needMetadata) ); } } _monitor->_requestQueue->put(new VcpEndInitialLoadRequest); TRACECF(debugFunc, "Done"); } // reload specific features, but only if they were already loaded // used when setting one feature requires rereading others void FeatureBaseModel::reloadSpecificFeatures(int ct, uint8_t* features) { bool debugFunc =true; for (int ndx = 0; ndx < ct; ndx++) { DDCA_Vcp_Feature_Code vcp_code = features[ndx]; if (ddca_feature_list_contains(_featuresChecked, vcp_code)) { TRACECF(debugFunc, "vcp_code = 0x%02x, in _features_checked", vcp_code); FeatureValue * fv = modelVcpValueFind(vcp_code); // should always exist, but just in case if (fv) { bool needMetadata = false; TRACECF(debugFunc, "Putting VcpGetRequest(0x%02x) on _requestQueue", vcp_code); _monitor->_requestQueue->put( new VcpGetRequest(vcp_code, needMetadata)); } else TRACECF(debugFunc, "FeatureValue for 0x%02x not found", vcp_code); } else { TRACECF(debugFunc, "vcp_code = 0x%02x not in _features_checked", vcp_code); } } } void FeatureBaseModel::setFeatureChecked(uint8_t featureCode) { ddca_feature_list_add(&_featuresChecked, featureCode); } // called from MainWindow::on_actionRescan_triggered(), // FeaturesScrollAreaView::onUIValueChanged() - reloading for features that affect multiple void FeatureBaseModel::reloadFeatures() { bool debug = false; debug = debug || debugFeatureLists; TRACECF(debug, "Starting."); _monitor->_requestQueue->put(new VcpStartInitialLoadRequest); int ct = modelVcpValueCount(); for (int ndx = 0; ndx < ct; ndx++) { FeatureValue* fv = modelVcpValueAt(ndx); // only rescan if previous scan was successful // the logic modelVcpValueSet is too convoluted if not if (fv->ddcrc() == 0) { DDCA_Feature_Flags flags = fv->flags(); if (flags & DDCA_READABLE) { uint8_t featureCode = fv->featureCode(); bool needMetadata = false; _monitor->_requestQueue->put( new VcpGetRequest(featureCode, needMetadata)); } } } _monitor->_requestQueue->put(new VcpEndInitialLoadRequest); TRACECF(debug, "Done"); } /** Debugging function to report the contents of the current * #FeatureBaseModel instance. */ // TODO: report feature_info, feature_name void FeatureBaseModel::dbgrpt() { printf("(FeatureBaseModel::report)\n"); int ct = _featureValues->count(); for (int ndx = 0; ndx < ct; ndx++) { FeatureValue* fv = _featureValues->at(ndx); // printf(" feature_code: 0x%02x\n", fv->_feature_code); printf(" code=0x%02x, mh=0x%02x, ml-0x%02x, sh=0x%02x, sl=0x%02x\n", fv->featureCode(), fv->val().mh, fv->val().ml, fv->val().sh, fv->val().sl); } } void FeatureBaseModel::modelStartInitialLoad(void) { bool debug = false; _initialLoadActive = true; TRACECF(debug, "=> Emitting signalStartInitialLoad"); emit signalStartInitialLoad(); } void FeatureBaseModel::modelEndInitialLoad(void) { bool debug = false; _initialLoadActive = false; TRACECF(debug, "=> Emitting signalEndInitialLoad"); signalEndInitialLoad(); } void FeatureBaseModel::setStatusMsg(QString msg) { // printf("(%s::%s) => msg=%s\n", _cls, __func__, msg.toLatin1().data()); fflush(stdout); emit signalStatusMsg(msg); } #ifdef FEATURE_CHANGE_OBSERVER void FeatureBaseModel::addFeatureChangeObserver(FeatureChangeObserver* observer) { _featureChangeObservers->append(observer); } void FeatureBaseModel::notifyFeatureChangeObservers(uint8_t feature_code) { if (debugSignals) printf("(%s::%s) Disabled\n", _cls, __func__); fflush(stdout); #ifdef DISABLED int ct = _featureChangeObservers->count(); printf("(%s) Starting ct=%d\n", __func__, ct); fflush(stdout); for (int ndx = 0; ndx < ct; ndx++) { printf("(%s) Notifying observer\n", __func__); fflush(stdout); FeatureChangeObserver* observer = _featureChangeObservers->at(ndx); observer->featureChanged(feature_code); } #endif } #endif ddcui-0.3.0/src/nongui/feature_base_model.h000066400000000000000000000100511427175135000206500ustar00rootroot00000000000000/* feature_base_model.h - Records all VCP feature values for a single monitor */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURE_BASE_MODEL_H #define FEATURE_BASE_MODEL_H #include #include "ddcutil_types.h" #include "nongui/feature_value.h" #include "nongui/vcprequest.h" #ifdef FEATURE_CHANGE_OBSERVER #include "nongui/feature_change_observer.h" #endif // #include "nongui/ddc_error_subject.h" // typedef void (*NotifyFeatureChanged)(uint8_t feature_code); class Monitor; /** Records all VCP values for a single monitor. * * For alternative (unused) feature views that use QListWidgets etc. * this class is contained in FeatureTableModel etc. */ class FeatureBaseModel : public QObject // , DdcFeatureErrorSubject { Q_OBJECT public: FeatureBaseModel(Monitor * monitor); virtual ~FeatureBaseModel(); FeatureValue* modelVcpValueFind(uint8_t feature_code); FeatureValue* modelVcpValueFilteredFind(uint8_t feature_code); FeatureValue* modelVcpValueAt(int ndx) const; int modelVcpValueCount(void) const; void modelVcpValueSet( uint8_t feature_code, DDCA_Display_Ref dref, // unnecessary, can get from monitor DDCA_Feature_Metadata * metadata, DDCA_Non_Table_Vcp_Value * feature_value, DDCA_Status ddcrc); // and/or full blown DDC_Error_info? void modelVcpValueUpdate( uint8_t feature_code, uint8_t sh, uint8_t sl); #ifdef UNUSED void modelMccsVersionSet(DDCA_MCCS_Version_Spec vspec); DDCA_MCCS_Version_Spec mccsVersionSpec(); #endif void modelStartInitialLoad(void); void modelEndInitialLoad(void); void setStatusMsg(QString msg); void setCapabilities( DDCA_Status ddcrc, char * capabilities_string, DDCA_Capabilities * parsed_capabilities); void dbgrpt(); #ifdef FEATURE_CHANGE_OBSERVER // void addFeatureChangedObserver(NotifyFeatureChanged func); void addFeatureChangeObserver(FeatureChangeObserver *observer); #endif void setFeatureList(DDCA_Feature_List featureList); void setFeatureChecked(uint8_t featureCode); void reloadFeatures(); void reloadSpecificFeatures(int ct, uint8_t* features); // *** Public Member Variables *** const char * _cls; // className Monitor * _monitor; bool _caps_check_complete = false; DDCA_Status _caps_status = -999; // a value that's undefined char * _caps_string = NULL; DDCA_Capabilities * _parsed_caps = NULL; signals: void signalStartInitialLoad(void); void signalEndInitialLoad(void); void signalFeatureAdded(FeatureValue fv); // void signalFeatureUpdated(char feature_code); void signalFeatureUpdated3(const char * caller, uint8_t feature_code, uint8_t sh, uint8_t sl); void signalVcpRequest(VcpRequest * rqst); // used to call into monitor void signalModelError(uint8_t featureCode, QString msg); void signalStatusMsg(QString msg); protected: #ifdef FEATURE_CHANGE_OBSERVER void notifyFeatureChangeObservers(uint8_t feature_code); #endif private: int modelVcpValueIndex(uint8_t feature_code); QVector * _featureValues; // DDCA_Feature_Metadata * _featureMetadata[256] = {NULL}; //unused // DDCA_Status _featureStatusCode[256]; // side table for now, include in FeatureValue? UNUSED DDCA_Feature_List _featuresToShow; DDCA_Feature_List _featuresChecked; // ifdef FUTURE DDCA_Feature_List _featuresTouchedByX14 = DDCA_EMPTY_FEATURE_LIST; // #endif bool _initialLoadActive = false; #ifdef UNUSED DDCA_MCCS_Version_Spec _vspec; #endif #ifdef FEATURE_CHANGE_OBSERVER QVector * _featureChangeObservers; #endif }; #endif // FEATURE_BASE_MODEL_H ddcui-0.3.0/src/nongui/feature_value.cpp000066400000000000000000000120201427175135000202230ustar00rootroot00000000000000/* feature_value.cpp */ // Copyright (C) 2018-2023 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // #include #include #include #include "ddcutil_types.h" #include "ddcutil_c_api.h" #include "base/core.h" #include "nongui/feature_value.h" int FeatureValue::nextId = 0; FeatureValue::FeatureValue() { // memset(&_finfo, 0, sizeof(_finfo)); // avoid -Wmissing-field-initializers _finfo = nullptr; _value.mh = _value.ml = _value.sh = _value.sl = 0; _id = ++nextId; } FeatureValue::FeatureValue( uint8_t feature_code, DDCA_Display_Ref dref, DDCA_Feature_Metadata * finfo, DDCA_Cap_Vcp * cap_vcp, DDCA_Non_Table_Vcp_Value val, DDCA_Status getvcpStatus) : _featureCode(feature_code) , _dref(dref) , _finfo(finfo) , _capVcp(cap_vcp) , _value(val) , _getvcpStatus(getvcpStatus) // , _cls( strdup(metaObject()->className()) ) { // _cls = strdup(metaObject()->className()); _cls = "FeatureValue"; _id = ++nextId; bool debugFunc = false; // debugFunc = debugFunc || (_featureCode == 0x14); // debugFunc = debugFunc || (_featureCode == 0xf5); if (debugFunc) { TRACEC("_id=%d, feature_code=0x%02x, finfo=%p, cap_vcp=%p, sh=0x%02x, sl=0x%02x, getvcpStatus=%s", _id, _featureCode, _finfo, cap_vcp, val.sh, val.sl, ddca_rc_name(getvcpStatus)); ddca_dbgrpt_feature_metadata(_finfo, 2); } if (_finfo) { // when would it be NULL ? if getvcp failed assert(_featureCode == _finfo->feature_code); // alt: if (_finfo->feature_flags & DDCA_SIMPLE_NC ) if (_finfo->sl_values && (getvcpStatus == 0) ) { _observedNcValues = bs256_insert(EMPTY_BIT_SET_256, val.sl); } } TRACECF(debugFunc, "Done. _observedNcValues = %s", bs256_to_string(_observedNcValues, "", " ")); } FeatureValue::~FeatureValue() { bool debugFunc = false; debugFunc = debugFunc || (_featureCode == 0x14); TRACEC("Executing. _id=%d, _featureCode=0x%02x", _id, _featureCode); ddca_free_display_ref(_dref); // n. not checking return code ddca_free_feature_metadata(_finfo); } uint8_t FeatureValue::featureCode() const { return _featureCode; } DDCA_Display_Ref FeatureValue::dref() const { return _dref; } DDCA_MCCS_Version_Spec FeatureValue::vspec() const { return _finfo->vcp_version; } DDCA_Feature_Metadata * FeatureValue::finfo() const { return _finfo; } DDCA_Feature_Flags FeatureValue::flags() const { return _finfo->feature_flags; } DDCA_Cap_Vcp * FeatureValue::capVcp() const { return _capVcp; } DDCA_Non_Table_Vcp_Value FeatureValue::val() const { return _value; } void FeatureValue::setCurrentValue(uint8_t sh, uint8_t sl) { bool debugFunc = false; // (_featureCode == 0x14); _value.sh = sh; _value.sl = sl; if (_finfo->sl_values) { _observedNcValues = bs256_insert(_observedNcValues, _value.sl); } TRACECF(debugFunc, "Finished. _observedNcValues = %s", bs256_to_string(_observedNcValues, "", " ")); } void FeatureValue::setCurrentValue(uint16_t newval) { setCurrentValue(newval >> 8, newval & 0xff); ///_value.sh = newval >> 8; //_value.sl = newval & 0xff; //if (_finfo->sl_values) { // _observedNcValues = bs256_insert(_observedNcValues, _value.sl); // } } DDCA_Status FeatureValue::ddcrc() const { return _getvcpStatus; } // void FeatureValue::setObservedValues(Bit_Set_256 values) { // _observedValues = values; // } Bit_Set_256 FeatureValue::observedNcValues() const { return _observedNcValues; } //DDCA_Monitor_Model_Key FeatureValue::mmid() const { // // return _mmid; // DDCA_Monitor_Model_Key result = DDCA_UNDEFINED_MONITOR_MODEL_KEY; // if (_finfo.mmid) // result = *_finfo.mmid; // return result; //} void FeatureValue::dbgrpt() const { printf("(FeatureValue::report) FeatureValue:\n"); printf(" _id: %d\n", _id); printf(" _feature_code: 0x%02x\n", _featureCode); printf(" dref: %s\n", ddca_dref_repr(dref())); // printf(" _vspec: %d.%d\n", _finfo.vspec.major, _finfo.vspec.minor); printf(" _feature_flags: 0x%04x\n", _finfo->feature_flags); printf(" _value.mh: 0x%02x\n", _value.mh); printf(" _value.ml: 0x%02x\n", _value.ml); printf(" _value.sh: 0x%02x\n", _value.sh); printf(" _value.sl: 0x%02x\n", _value.sl); printf(" _cap_vcp: %p\n", (void*) _capVcp); printf(" _observedNcValues: %s", bs256_to_string(_observedNcValues, ""," ")); ddca_dbgrpt_feature_metadata(_finfo, 1); #ifdef NO if (_finfo.mmid) { printf(" _finfo.mmid->mfg_id: %s\n", _finfo.mmid->mfg_id); printf(" _finfo.mmid->model_name: %s\n", _finfo.mmid->model_name); printf(" _finfo.mmid->product_code: %u\n", _finfo.mmid->product_code); } else { printf(" _finfo.mmid: Not set\n"); } #endif fflush(stdout); } ddcui-0.3.0/src/nongui/feature_value.h000066400000000000000000000044651427175135000177060ustar00rootroot00000000000000/* feature_value.h */ // Copyright (C) 2018-2019 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURE_VALUE_H #define FEATURE_VALUE_H #include #include "ddcutil_types.h" #include "c_util/data_structures.h" class FeatureValue { public: // no-arg constructor needed for Q_METATYPE FeatureValue(); FeatureValue( uint8_t featureCode, DDCA_Display_Ref dref, DDCA_Feature_Metadata * finfo, DDCA_Cap_Vcp * capVcp, DDCA_Non_Table_Vcp_Value val, DDCA_Status getvcpStatus=0 // experiment ); ~FeatureValue(); uint8_t featureCode() const; DDCA_Display_Ref dref() const; DDCA_MCCS_Version_Spec vspec() const; DDCA_Feature_Metadata* finfo() const; DDCA_Feature_Flags flags() const; DDCA_Cap_Vcp * capVcp() const; DDCA_Non_Table_Vcp_Value val() const; DDCA_Status ddcrc() const; void setCurrentValue(uint8_t sh, uint8_t sl); void setCurrentValue(uint16_t newval); void dbgrpt() const; // void setObservedValues(Bit_Set_256 values); // *** EXPERIMENTAL *** Bit_Set_256 observedNcValues() const; // DDCA_Monitor_Model_Key mmid() const; private: // disable - fails, QT uses copy constructor // FeatureValue(const FeatureValue& original); // FeatureValue& operator=(const FeatureValue& original); public: Bit_Set_256 _observedNcValues = EMPTY_BIT_SET_256; int _id; protected: static int nextId; private: const char * _cls = "FeatureValue"; uint8_t _featureCode = 0; DDCA_Display_Ref _dref = NULL; DDCA_Feature_Metadata * _finfo = NULL; DDCA_Cap_Vcp * _capVcp = NULL; DDCA_Non_Table_Vcp_Value _value; // use this or individual bytes? DDCA_Non_Table_Value needed for get_formatted_value call DDCA_Status _getvcpStatus = 0; // an experiment }; Q_DECLARE_METATYPE(FeatureValue) #endif // FEATURE_VALUE_H ddcui-0.3.0/src/nongui/msgbox_queue.cpp000066400000000000000000000076331427175135000201150ustar00rootroot00000000000000/* msgbox_queue.cpp - MsgBoxQueue and the MsgBoxQueueEntry class that populates it */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include "base/core.h" #include "nongui/msgbox_queue.h" static bool debugClass = false; /* MsgBoxQueueEntry and subclasses */ MsgBoxQueueEntry::MsgBoxQueueEntry( QString title, QString text, QMessageBox::Icon icon) : _boxTitle(title) , _boxText(text) , _boxIcon(icon) { TRACECF(debugClass, "Constructor. title=%s, text=%s, icon=%d", QS2S(_boxTitle), QS2S(_boxText), _boxIcon); } MsgBoxQueueEntry::~MsgBoxQueueEntry() { TRACECF(debugClass, "Executing"); } QString MsgBoxQueueEntry::repr() { // qDebug() << "_boxTitle: " << _boxTitle; // qDebug() << "_boxText: " << _boxText; // qDebug() << "_boxIcon: " << _boxIcon; QString msg = QString("[title=0x%1, text=%2, icon=%3]") .arg(_boxTitle) .arg(_boxText) .arg(_boxIcon); // qDebug() << "Assembled: " << msg; // printf("(MsgBoxQueueEntry::repr) returning: %s\n", QS2S(msg)); fflush(stdout); return msg; } /* MsgBoxQueue */ MsgBoxQueue::MsgBoxQueue() { bool debugFunc = debugClass; debugFunc = false; _queue = QQueue(); #ifdef USE_MUTEX // _mutex = QMutex(QMutex::Recursive); #else _freeBytes = new QSemaphore(9999); _usedBytes = new QSemaphore(); // -Wnon-pod-varrags says will abort at runtime: // TRACECF(debugFunc, "this=%p, queue=%p, _usedBytes=%p, _freeBytes=%p", this, _queue, _usedBytes, _freeBytes); #endif } void MsgBoxQueue::put(MsgBoxQueueEntry * request) { // bool debugFunc = false || debugClass; // TRACECF(debugFunc, "-> Starting. request: |%s|", QS2S(request->repr())); assert(request); #ifdef USE_MUTEX _mutex.lock(); _queue.enqueue(request); _queueNonempty.wakeOne(); _mutex.unlock(); #else _freeBytes->acquire(); _queue.enqueue(request); _usedBytes->release(); #endif // dbgrpt_nolock(); // TRACECF(debugFunc, "Done"); } void MsgBoxQueue::putMessages(QString qstitle, QMessageBox::Icon icon, char** msgs) { bool debugFunc = false || debugClass; TRACECF(debugFunc, "Starting"); if (msgs) { if (debugFunc) { int ct = 0; while(msgs[ct]) ct++; TRACEC("%d error messages", ct); } for (int ndx = 0; msgs[ndx]; ndx++) { QString qsexpl = QString::asprintf("%s", msgs[ndx]); MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(qstitle,qsexpl,icon); TRACECF(debugFunc, "Calling _msgboxQueue.put() for qe: %s", __func__, QS2S(qe->repr()) ); put(qe); } } TRACECF(debugFunc, "Done"); } MsgBoxQueueEntry * MsgBoxQueue::pop() { bool debugFunc = debugClass; debugFunc = false; TRACECF(debugFunc, "Starting"); #ifdef USE_MUTEX _mutex.lock(); TRACECF(debugFunc, "After lock, before wait"); if (_queue.empty()) _queueNonempty.wait(&_mutex); MsgBoxQueueEntry * rqst = _queue.dequeue(); // this->dbgrpt_nolock(); _mutex.unlock(); #else _usedBytes->acquire(); MsgBoxQueueEntry * rqst = _queue.dequeue(); _freeBytes->release(); // TRACECF(debugFunc, "-> After releasing _freeBytes. available=%d, request: |%s|", // _freeBytes->available(), QS2S(rqst->repr())); #endif TRACECF(debugFunc, "<- Done. Returning request: %s", QS2S(rqst->repr()) ); return rqst; } void MsgBoxQueue::dbgrpt_nolock() { int ct = _queue.size(); TRACEC("Queue contains %d entries", ct); for (int ndx = 0; ndx < ct; ndx++) { MsgBoxQueueEntry * rqst = _queue.at(ndx); TRACEC(" %s", QS2S(rqst->repr()) ); } } void MsgBoxQueue::dbgrpt() { _mutex.lock(); dbgrpt_nolock(); _mutex.unlock(); } ddcui-0.3.0/src/nongui/msgbox_queue.h000066400000000000000000000025361427175135000175570ustar00rootroot00000000000000/* msgbox_queue.h - MsgBoxQueue and the MsgBoxQueueEntry class that populates the queue */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef MSGBOX_QUEUE_H #define MSGBOX_QUEUE_H #include #include #include #include #include #include /* MsgBoxQueue entries */ class MsgBoxQueueEntry { public: MsgBoxQueueEntry(QString title, QString text, QMessageBox::Icon icon); ~MsgBoxQueueEntry(); QString repr(); QString _boxTitle; QString _boxText; QMessageBox::Icon _boxIcon; private: const char * _cls = "MsgBoxQueueEntry"; }; /* MsgBoxQueue */ class MsgBoxQueue { // Q_OBJECT public: MsgBoxQueue(); MsgBoxQueueEntry* pop(); void put(MsgBoxQueueEntry* request); void putMessages(QString qstitle, QMessageBox::Icon icon, char** msgs); void dbgrpt(); private: void dbgrpt_nolock(); const char * _cls = "MsgBoxQueue"; QMutex _mutex; QQueue _queue; QWaitCondition _queueNonempty; QSemaphore * _freeBytes; QSemaphore * _usedBytes; }; #endif // MSGBOX_QUEUE_H ddcui-0.3.0/src/nongui/vcprequest.cpp000066400000000000000000000063041427175135000176050ustar00rootroot00000000000000/* vcprequest.cpp - VcpRequestQueue and the classes that populate it */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later // #include #include "nongui/vcprequest.h" /* VcpRequest and subclasses */ VcpRequest::VcpRequest(VcpRequestType type) : _type(type) { // _type = type; } VcpRequest::~VcpRequest() { } #ifdef NOT_NEEDED VcpDumpStatsRequest::VcpDumpStatsRequest(DDCA_Stats_Type stats_type) : VcpRequest::VcpRequest(VcpRequestType::RQDumpStats) , _stats_type(stats_type) { } VcpResetStatsRequest::VcpResetStatsRequest() : VcpRequest::VcpRequest(VcpRequestType::RQResetStats) { } #endif VcpCapRequest::VcpCapRequest() : VcpRequest::VcpRequest(VcpRequestType::RQCapabilities) { } LoadDfrRequest::LoadDfrRequest() : VcpRequest::VcpRequest(VcpRequestType::RQLoadDfr) { } HaltRequest::HaltRequest() : VcpRequest::VcpRequest(VcpRequestType::RQHalt) { } VcpGetRequest::VcpGetRequest(DDCA_Vcp_Feature_Code featureCode, bool needMetadata ) : VcpRequest::VcpRequest(VcpRequestType::RQGetVcp) , _featureCode(featureCode) , _needMetadata(needMetadata) { } VcpSetRequest::VcpSetRequest(DDCA_Vcp_Feature_Code featureCode, uint8_t newSh, uint8_t newSl, bool writeOnly) : VcpRequest::VcpRequest(VcpRequestType::RQSetVcp) , _featureCode(featureCode) , _newSh(newSh) , _newSl(newSl) , _writeOnly(writeOnly) { // _featureCode = feature_code; // _newval = newval; // _writeOnly = writeOnly; } VcpStartInitialLoadRequest::VcpStartInitialLoadRequest(void) : VcpRequest::VcpRequest(VcpRequestType::RQStartInitialLoad) { } VcpEndInitialLoadRequest::VcpEndInitialLoadRequest(void) : VcpRequest::VcpRequest(VcpRequestType::RQEndInitialLoad) { } /* VcpRequestQueue */ VcpRequestQueue::VcpRequestQueue() { _queue = QQueue(); } VcpRequestQueue::~VcpRequestQueue() { bool debug = false; if (debug) printf("(%s) Executing VcpRequestQueue destructor\n", __func__); } void VcpRequestQueue::put(VcpRequest * request) { // printf("VcpRequestQueue::put) -> request type: %d\n" , request->_type); _mutex.lock(); _queue.enqueue(request); _queueNonempty.wakeOne(); _mutex.unlock(); } VcpRequest * VcpRequestQueue::pop() { _mutex.lock(); if (_queue.empty()) _queueNonempty.wait(&_mutex); VcpRequest * rqst = _queue.dequeue(); // to do: scan queue for superceding requests // if (this->m_queue.empty()) // do something with queueNonempty? _mutex.unlock(); // printf("VcpRequesQueue::pop) <- Done. request type: %d\n", rqst->_type); return rqst; } void VcpRequestQueue::halt() { _mutex.lock(); // purge the queue while (!_queue.empty()) { VcpRequest * rqst = _queue.dequeue(); delete rqst; } HaltRequest * rqst = new HaltRequest(); _queue.enqueue(rqst); _mutex.unlock(); } void VcpRequestQueue::dbgrpt() { _mutex.lock(); int ct = _queue.size(); printf("Queue contains %d entries", ct); for (int ndx = 0; ndx < ct; ndx++) { VcpRequest * rqst = _queue.at(ndx); printf(" type: %d\n", rqst->_type); } _mutex.unlock(); } // VcpRequest VcpRequestQueue::peek() { } ddcui-0.3.0/src/nongui/vcprequest.h000066400000000000000000000047621427175135000172600ustar00rootroot00000000000000/* vcprequest.h - VcpRequestQueue and the VcpRequest classes that populate the queue */ // Copyright (C) 2018-2021 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VCPREQUEST_H #define VCPREQUEST_H #include #include #include #include #include enum VcpRequestType { RQGetVcp, RQSetVcp, RQStartInitialLoad, RQEndInitialLoad, RQCapabilities, RQLoadDfr, #ifdef NOT_NEEDED RQDumpStats, RQResetStats #endif RQHalt, }; /* VcpRequest classes */ class VcpRequest { public: VcpRequest(VcpRequestType type); ~VcpRequest(); VcpRequestType _type; }; #ifdef NOT_NEEDED class VcpDumpStatsRequest: public VcpRequest { public: VcpDumpStatsRequest(DDCA_Stats_Type stats_type); ~VcpDumpStatsRequest(); DDCA_Stats_Type _stats_type; }; class VcpResetStatsRequest: public VcpRequest { public: VcpResetStatsRequest(); ~VcpResetStatsRequest(); }; #endif class VcpCapRequest: public VcpRequest { public: VcpCapRequest(); ~VcpCapRequest(); }; class LoadDfrRequest: public VcpRequest { public: LoadDfrRequest(); ~LoadDfrRequest(); }; class HaltRequest: public VcpRequest { public: HaltRequest(); ~HaltRequest(); }; class VcpGetRequest: public VcpRequest { public: VcpGetRequest(uint8_t featureCode, bool needMetadata); ~VcpGetRequest(); DDCA_Vcp_Feature_Code _featureCode; bool _needMetadata; }; class VcpSetRequest: public VcpRequest { public: VcpSetRequest(uint8_t featureCode, uint8_t newSh, uint8_t newSl, bool writeOnly=false); ~VcpSetRequest(); DDCA_Vcp_Feature_Code _featureCode = 0; uint8_t _newSh = 0; uint8_t _newSl = 0; bool _writeOnly = false; }; class VcpStartInitialLoadRequest : public VcpRequest { public: VcpStartInitialLoadRequest(); ~VcpStartInitialLoadRequest(); }; class VcpEndInitialLoadRequest : public VcpRequest { public: VcpEndInitialLoadRequest(void); }; /* VcpRequestQueue */ class VcpRequestQueue { // Q_OBJECT public: VcpRequestQueue(); ~VcpRequestQueue(); VcpRequest* pop(); // VcpRequest* popCondensed(); // future void halt(); void dbgrpt(); // public slots: void put(VcpRequest* request); private: // Monitor* monitor; QMutex _mutex; QQueue _queue; QWaitCondition _queueNonempty; }; #endif // VCPREQUEST_H ddcui-0.3.0/src/nongui/vcpthread.cpp000066400000000000000000000553331427175135000173720ustar00rootroot00000000000000/* vcpthread.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include "ddcutil_status_codes.h" // using quotes allows Eclipse to find in workspace #include "ddcutil_c_api.h" #include #include "base/core.h" #include "base/ddca_utils.h" #include "base/global_state.h" #include "nongui/vcpthread.h" using namespace std; static bool debugThread = false; VcpThread::VcpThread( QObject* parent, DDCA_Display_Info * dinfo, VcpRequestQueue* requestQueue, FeatureBaseModel * baseModel) : QThread(parent) , _dinfo(dinfo) , _requestQueue(requestQueue) , _baseModel(baseModel) { bool debug = false; debug |= debugThread; TRACECF(debug, "Starting"); _dref = dinfo->dref; _ddcaSimulator = new DdcaSimulator(); // ddca_report_display_info(dinfo, 4); // ddca_dbgrpt_display_ref(_dref, 4); TRACECF(debug, "Done. _dref=%s", ddca_dref_repr(_dref)); } VcpThread::~VcpThread() { bool debug = false; debug |= debugThread; TRACECF(debug, "Starting. _dref=%s", ddca_dref_repr(_dref)); delete _ddcaSimulator; TRACECF(debug, "Done."); } // // *** Error Reporting // void VcpThread::rpt_feature_error( enum FeatureOp op, uint8_t featureCode, const char * ddcaFuncName, DDCA_Status ddcrc) { bool debug = false; TRACEMCF(debug, "Starting.op=%d, featureCode=0x%02x, ddcrc=%d", op, featureCode, ddcrc); char * opText = (char *) "reading"; if (op == FeatureWrite) opText = (char *) "writing"; if (op == FeatureMetadata) opText = (char *) "fetching metadata for"; QString qsexpl = QString::asprintf( "Error %s for feature x%02x, display %d - %s\n\n" "API function %s returned %s (%d)", opText, featureCode, _dinfo->dispno, _dinfo->model_name, ddcaFuncName, ddca_rc_name(ddcrc), ddcrc); MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(QString("ddcutil API Error"), qsexpl, QMessageBox::Warning); TRACEMCF(debug, "Calling _msgboxQueue.put() for qe: %s", QS2S(qe->repr())); GlobalState::instance()._msgBoxQueue->put(qe); TRACEMCF(debug, "Done"); } void VcpThread::rpt_nonfeature_error( const char * action, const char * ddcaFuncName, DDCA_Status ddcrc, DDCA_Error_Detail * erec) { bool debug = false; TRACECF(debug, "Starting.action=%s, ddcaFuncName=%s, ddcrc=%d", action, ddcaFuncName, ddcrc); QString qsexpl = QString(""); if (erec) { QString smooshed = ddcutil_format_error_detail(erec, QString(""), 3); qsexpl = QString("Error %1 for display %2 - %3.\n\n" "API function %4 returned %5(%6): %7") .arg(action) .arg(_dinfo->dispno) .arg(_dinfo->model_name) .arg(ddcaFuncName) .arg(ddca_rc_name(ddcrc)) .arg(smooshed); } else { qsexpl = QString::asprintf( "Error %s for display %d - %s.\n\n" "API function %s returned %s (%d)", action, _dinfo->dispno, _dinfo->model_name, ddcaFuncName, ddca_rc_name(ddcrc), ddcrc); } MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(QString("ddcutil API Error"), qsexpl, QMessageBox::Warning); TRACECF(debug, "Calling _msgboxQueue.put() for qe: %s", QS2S(qe->repr())); GlobalState::instance()._msgBoxQueue->put(qe); TRACECF(debug, "Done"); } void VcpThread::rpt_nonfeature_error( const char * action, const char * ddcaFuncName, DDCA_Status ddcrc) { rpt_nonfeature_error(action, ddcaFuncName, ddcrc, nullptr); } static uint8_t abs8(uint8_t v1, uint8_t v2) { uint8_t result; if (v1 >= v2) result = v1 - v2; else result = v2 - v1; return result; } static uint8_t max8(uint8_t v1, uint8_t v2) { if (v1 > v2) return v1; return v2; } void VcpThread::rpt_verify_error( uint8_t featureCode, const char * function, uint8_t expectedSh, uint8_t expectedSl, uint8_t observedSh, uint8_t observedSl ) { VcpThread::rpt_verify_error( featureCode, function, expectedSh << 8 | expectedSl, observedSh << 8 | observedSl); } void VcpThread::rpt_verify_error( uint8_t featureCode, const char * function, uint16_t expectedValue, uint16_t observedValue) { bool debug = false; debug = debug || debugThread; TRACECF(debug, "featureCode=0x%02x, expectedValue=0x%04x, observedValue=0x%04x", featureCode, expectedValue, observedValue); // DdcVerifyError* perec = new DdcVerifyError(featureCode, function, expectedValue, observedValue); if ( max8(abs8(expectedValue >> 8, observedValue >> 8), abs8(expectedValue & 0xff, observedValue & 0xff) ) <= 1) { TRACECF(debug, "difference <= 1, suppressing error"); } else { QString qsexpl = QString("Verification failed after value change for feature 0x%1.\n\n" "Expected value: %2 (0x%3), Reported value: %4 (0x%05)") .arg(featureCode, 2, 16, QLatin1Char('0')) .arg(expectedValue) .arg(expectedValue, 4, 16, QLatin1Char('0')) .arg(observedValue) .arg(observedValue, 4, 16, QChar('0')); MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(QString("Verification Error"), qsexpl, QMessageBox::Warning); TRACECF(debug, "Calling _msgboxQueue.put() for qe: %s", QS2S(qe->repr())); GlobalState::instance()._msgBoxQueue->put(qe); TRACECF(debug, "Done"); } } // // *** Open and Close *** // DDCA_Status VcpThread::perform_open_display(DDCA_Display_Handle * dh_loc) { bool debugFunc = false; debugFunc = debugFunc || debugThread; TRACECF(debugFunc, "Starting. dref=%s", ddca_dref_repr(this->_dref)); DDCA_Status ddcrc = ddca_open_display2(this->_dref, false, dh_loc); // if (ddcrc == 0) ddcrc = -EBUSY; if (ddcrc != 0) { rpt_nonfeature_error("performing open", "ddca_open_display2", ddcrc); } if (ddcrc == 0 && !_threadDescriptionPublished) { TRACECF(debugFunc, "calling ddca_set_thread_description()"); // ddca_register_thread_dref(this->_dref); ddca_append_thread_description( ddca_dref_repr(this->_dref) ); _threadDescriptionPublished = true; } TRACECF(debugFunc, "Returning %d", ddcrc); return ddcrc; } DDCA_Status VcpThread::perform_close_display(DDCA_Display_Handle dh) { bool debugFunc = false; debugFunc = debugFunc || debugThread; DDCA_Status ddcrc = ddca_close_display(dh); TRACECF(debugFunc, "ddca_close_display() returned %d, dref=%s", ddcrc, ddca_dref_repr(this->_dref)); if (ddcrc != 0) { // n. returns DDCRC_INVALID_STATE if already closed rpt_nonfeature_error("performing close", "ddca_close_display", ddcrc); } return ddcrc; } // // *** Request Handlers *** // // Process RQLoadDfr void VcpThread::loadDynamicFeatureRecords() { bool debugFunc = debugThread; debugFunc = debugFunc || debugThread; TRACECF(debugFunc, "Starting. dref=%s", ddca_dref_repr(this->_dref)); DDCA_Display_Handle dh; DDCA_Status ddcrc = perform_open_display(&dh); if (ddcrc == 0) { ddcrc = ddca_dfr_check_by_dh(dh); if (ddcrc != 0) { if (ddcrc == DDCRC_NOT_FOUND) { TRACECF(debugFunc, "ddca_dfr_check_by_dh() returned DDCRC_NOT_FOUND"); } else { TRACECF(debugFunc, "ddca_dfr_check_by_dh() returned %s", ddca_rc_name(ddcrc)); DDCA_Error_Detail * erec = ddca_get_error_detail(); ddca_report_error_detail(erec, 4); rpt_nonfeature_error("loading dynamic feature records", "ddca_dfr_check_by_dh", ddcrc, erec); ddca_free_error_detail(erec); } } ddcrc = perform_close_display(dh); } TRACECF(debugFunc, "Done. dref=%s", ddca_dref_repr(this->_dref)); } #ifdef TEST_ADJUST_RETRIES void VcpThread::adjustRetries() { bool debugFunc = true; // TRACECF(debugFunc, "Starting"); // quick and dirty just to test the functionality // TODO: Wrap in reads/writes in lock uint16_t writeReadMax = ddca_get_max_tries(DDCA_WRITE_READ_TRIES); uint16_t multiMax = ddca_get_max_tries(DDCA_MULTI_PART_READ_TRIES); uint16_t newWriteReadMax = (writeReadMax/2) + 1; uint16_t newMultiMax = (multiMax/2) + 1; TRACECF(debugFunc, "writeReadMax %d -> %d, multiMax %d -> %d", writeReadMax, newWriteReadMax, multiMax, newMultiMax); ddca_set_max_tries(DDCA_WRITE_READ_TRIES, newWriteReadMax); ddca_set_max_tries(DDCA_MULTI_PART_READ_TRIES, newMultiMax); } #endif // Process RQCapabilities void VcpThread::capabilities() { bool debugFunc = debugThread; debugFunc = false; bool debugRetry = false; debugFunc = debugFunc || debugThread; debugRetry = debugRetry || debugFunc; // debugFunc = false; TRACECF(debugFunc, "Starting. dref=%s", ddca_dref_repr(this->_dref)); DDCA_Display_Handle dh; char * caps = NULL; DDCA_Capabilities * parsed_caps = NULL; int retry_count = 0; DDCA_Status ddcrc = perform_open_display(&dh); if (ddcrc == 0) { // TRACEF(debugFunc,"Sleeping for 1000000 msec"); // usleep(1000000); bool retryable = true; // Why retrying here? Retries already occurred in libddcutil? (4/2020) while (retryable) { retryable = false; ddcrc = ddca_get_capabilities_string(dh, &caps); // ddcrc = DDCRC_ALL_TRIES_ZERO; if (ddcrc != 0) { TRACECF(debugRetry, "Error getting capabilities string for %s, ddcrc=%s", ddca_dref_repr(this->_dref), ddca_rc_name(ddcrc)); // DDCA_Error_Detail * err_detail = ddca_get_error_detail(); // ddca_report_error_detail(err_detail, 2); double curmult = ddca_get_sleep_multiplier(); if (ddcrc == -EBADF) { TRACEC("EBADF"); continue; } if (curmult <= 2.0f) { // retry possible curmult = curmult * 2; TRACECF(debugRetry, "Adjusting thread sleep multiplier for %s to %5.2f", ddca_dref_repr(this->_dref), curmult); // todo: output message in status bar that retrying // RETRYING DOESN"T HELP // ddca_set_sleep_multiplier(curmult); // adjustRetries(); retryable = true; retry_count++; } // end, ddca_get_capabilities_string() failure, retry possible else { // failure, can't retry if (retry_count > 0) TRACECF(debugRetry || true, "Capabilities check failed after %d retries, retries exhausted", retry_count); rpt_nonfeature_error("getting capabilities string", "ddca_get_capabilitis_string", ddcrc); } // end, failure, can't retry } // ddca_get_capabilities() failed else if (retry_count > 0) { TRACECF(debugRetry || true, "Capabilities check succeeded after %d retries", retry_count); } } // end of while() loop calling ddca_get_capabilities_string() if (ddcrc == 0) { // ddca_get_capabilities_string() succeeded, try to parse ddcrc = ddca_parse_capabilities_string(caps, &parsed_caps); if (ddcrc != 0) { rpt_nonfeature_error("parsing capabilities string", "ddca_parse_capabilitis_string", ddcrc); } // free(caps); } // rpt_ddca_status(0, __func__, "dummy function", -99); // *** TEMP *** // if ddcrc != 0, caps may be NULL, parsed_caps definitely NULL // whatever the case, tell _baseModel the result _baseModel->setCapabilities(ddcrc, caps, parsed_caps); if (ddcrc == -EBADF) { TRACECF(debugFunc, "ddca_get_capabilities_string() returned -EBADF. Skipping close. dh=%s", ddca_dref_repr(this->_dref)); } else { TRACECF(debugFunc, "Closing %s", ddca_dref_repr(this->_dref) ); ddcrc = perform_close_display(dh); } } // open succeeded TRACECF(debugFunc, "Done. dref=%s, retry_count=%d", ddca_dref_repr(this->_dref), retry_count); } // function // Process RQGetVcp void VcpThread::getvcp(uint8_t featureCode, bool needMetadata) { bool debugFunc = false; // || (featureCode == 0x14); debugFunc = debugFunc || debugThread; TRACECF(debugFunc, "Starting. featureCode=0x%02x, needMetadata = %s", featureCode, SBOOL(needMetadata)); DDCA_Display_Handle dh; DDCA_Non_Table_Vcp_Value valrec; DDCA_Feature_Metadata * finfo; DDCA_Status ddcrc = perform_open_display(&dh); if (ddcrc == 0) { QString msg; _baseModel->setStatusMsg(msg.asprintf("Reading feature 0x%02x",featureCode)); bool simulated = _ddcaSimulator->simulateGetNonTableVcpValue( _dinfo->vcp_version, dh, featureCode, &valrec, &ddcrc); if (!simulated) { // TRACEC("non-simulated"); ddcrc = ddca_get_non_table_vcp_value(dh, featureCode, &valrec); } TRACECF(debugFunc, "feature_code=0x%02x, ddca_get_non_table_vcp_value() returned %d - %s", featureCode, ddcrc, ddca_rc_name(ddcrc)); // don't need to call rpt_ddca_status() if error, error will be reported // in the value field for the feature code #ifdef OLD if (ddcrc != 0) { if (ddcrc != DDCRC_REPORTED_UNSUPPORTED) { rpt_ddca_status(featureCode, __func__, "ddca_get_nontable_vcp_value", ddcrc); } } else { // printf("ddca_get_nontable_vcp_value() returned:\n"); // printf(" opcode: 0x%02x, mh=0x%02x, ml=0x%02x, sh=0x%02x, sl=0x%02x\n", // feature_code, valrec.mh, valrec.ml, valrec.sh, valrec.sl); } #endif // if (ddcrc == 0) { // if get_nontable_vcp_value() succeeded // TODO: get metadata once and cache DDCA_Status ddcrc2 = ddca_get_feature_metadata_by_dh( featureCode, dh, true, // create_default_if_not_found &finfo); TRACECF(debugFunc, "ddca_get_feature_metadata_by_dh() for feature 0x%02x returned %d - %s", featureCode, ddcrc2, ddca_rc_name(ddcrc2)); // if (featureCode == 0xdf || featureCode == 0xf4 || featureCode == 0xf5) // ddca_dbgrpt_feature_metadata(finfo, 1); // if (debugFunc && ddcrc2 == 0) { // // OLD: ddcui_dbgrpt_ddca_feature_metadata(finfo); // ddca_dbgrpt_feature_metadata(finfo, 1); // } if (ddcrc2 != 0) { rpt_feature_error(FeatureMetadata, featureCode, "ddca_get_capabilitis_string", ddcrc); // cout << "ddca_get_feature_metadata() returned " << ddcrc << endl; } // whether or not succeeded, set feature info in _baseModel so FeatureValueWidget can display error _baseModel->modelVcpValueSet(featureCode, this->_dref, finfo, &valrec, ddcrc); _baseModel->setFeatureChecked(featureCode); // } // end, get value succeeded ddcrc = perform_close_display(dh); } // open succeeded TRACECF(debugThread, "Done"); } // Process RQSetVcp void VcpThread::setvcp(uint8_t feature_code, bool writeOnly, uint16_t shsl) { bool debugFunc = false; // || (feature_code == 0x14); debugFunc = debugFunc || debugThread; TRACECF(debugFunc, "Starting. feature_code=0x%02x. shsl=0x%04x, writeOnly=%s", feature_code, shsl, SBOOL(writeOnly)); uint8_t sh = (shsl >> 8); uint8_t sl = (shsl & 0xff); TRACECF(debugFunc, "sh: 0x%02x, sl: 0x%02x", sh, sl); // rpt_ddca_status(feature_code, __func__, "ddca_bogus", 0); DDCA_Display_Handle dh; DDCA_Status ddcrc = perform_open_display(&dh); if (ddcrc == 0) { ddca_enable_verify(false); // TRACE( "ddca_is_verify_enabled() returned: %s", SBOOL( ddca_is_verify_enabled())); // ddca_enable_verify(!writeOnly); // uint8_t verified_hi_byte = 0; // unused // uint8_t verified_lo_byte = 0; // unused // need to update mh, ml, use a valrec // ddcrc = ddca_set_non_table_vcp_value_verify(dh, feature_code, 0, sl, &verified_hi_byte, &verified_lo_byte); bool simulated = _ddcaSimulator->simulateSetNonTableVcpValue( _dinfo->vcp_version, dh, feature_code, sh, sl, &ddcrc); if (!simulated) { // TRACEC("non-simulated"); ddcrc = ddca_set_non_table_vcp_value(dh, feature_code, sh, sl); } if (ddcrc != 0) { TRACECF(debugFunc, "ddca_set_non_table_vcp_value() returned %d = %s", ddcrc, ddca_rc_name(ddcrc)); rpt_feature_error(FeatureWrite, feature_code, "ddca_set_non_table_vcp_value", ddcrc); goto bye; } if (!writeOnly) { DDCA_Non_Table_Vcp_Value valrec; // Special handling for feature x60, can trigger Null Response if sleep-multiplier is too low. if (feature_code == 0x60) { int msec = 100; TRACECF(debugFunc, "Special %d millisecond sleep before verifying feature x60", msec); QThread::msleep(msec); } bool simulated = _ddcaSimulator->simulateGetNonTableVcpValue( _dinfo->vcp_version, dh, feature_code, &valrec, &ddcrc); if (!simulated) { // TRACEC("non-simulated"); ddcrc = ddca_get_non_table_vcp_value(dh, feature_code, &valrec); } if (ddcrc != 0) { rpt_feature_error(FeatureRead, feature_code, "ddca_get_nontable_vcp_value", ddcrc); } else { TRACECF(debugFunc, "ddca_get_nontable_vcp_value() after ddca_set_non_table_vcp_value():"); TRACECF(debugFunc, " opcode: 0x%02x, requested: sh=0x%02x, sl=0x%02x, observed: mh=0x%02x, ml=0x%02x, sh=0x%02x, sl=0x%02x", feature_code, sh, sl, valrec.mh, valrec.ml, valrec.sh, valrec.sl); FeatureValue* fv = _baseModel->modelVcpValueFind(feature_code); DDCA_Feature_Metadata * finfo = fv->finfo(); bool ok = true; if (finfo->feature_flags & (DDCA_SIMPLE_NC | DDCA_NC_CONT)) { ok = (sl == valrec.sl); } else { ok = (sl == valrec.sl && sh == valrec.sh); } if (!ok) { // TRACE("Calling rpt_verify_error()"); rpt_verify_error(feature_code, "ddca_set_non_table_vcp_value", sh, sl, valrec.sh, valrec.sl); } // ddca_set_non_table_vcp_value() succeeded // 10/2019 coming here even if verify error??? TRACECF(debugFunc, "Calling _baseModel->modelVcpValueUpdate()"); _baseModel->modelVcpValueUpdate(feature_code, valrec.sh, valrec.sl); } // ddca_get_non_table_vcp_value() succeeded } // !writeOnly bye: ddcrc = ddca_close_display(dh); TRACECF(debugFunc, "ddca_close_display() returned %d", ddcrc); if (ddcrc != 0) { TRACECF(debugFunc, "ddca_close_display() returned %d", ddcrc); rpt_nonfeature_error("performing close", "ddca_close_display", ddcrc); } } // open succeeded TRACECF(debugFunc, "Done"); } // Process RQStartInitailLoad void VcpThread::startInitialLoad(void) { TRACECF(debugThread, "Executing"); // _baseModel->beginResetModel(); _baseModel->modelStartInitialLoad(); #ifdef UNUSED _baseModel->modelMccsVersionSet(_dinfo->vcp_version); #endif } // Process RQEndInitialLoad void VcpThread::endInitialLoad(void) { TRACECF(debugThread, "Starting"); // _baseModel->report(); // _baseModel->endResetModel(); _baseModel->modelEndInitialLoad(); // emit signalStatusMsg(QString("Loading complete")); _baseModel->setStatusMsg(QString("Loading complete")); } // // *** Main Loop *** // void VcpThread::run() { bool debug = false; forever { VcpRequest * rqst = this->_requestQueue->pop(); switch(rqst->_type) { case VcpRequestType::RQGetVcp: { VcpGetRequest* getRqst = static_cast(rqst); // printf("(VcpThread::run) VcpGetRequest. feature_code=0x%02x\n", getRqst->_featureCode); // TRACE("VcpGetRequest. feature code = 0x%02x", getRqst->_featureCode); getvcp(getRqst->_featureCode, getRqst->_needMetadata); break; } case VcpRequestType::RQSetVcp: { VcpSetRequest* setRqst = static_cast(rqst); // if (debugThread) // printf("(VcpThread::run) RQSetVcp. feature code=0x%02x, newval=%d\n", // setRqst->_featureCode, setRqst->_newval); fflush(stdout); uint16_t newval = (setRqst->_newSh << 8) | (setRqst->_newSl ); setvcp(setRqst->_featureCode, setRqst->_writeOnly, newval); break; } case VcpRequestType::RQStartInitialLoad: startInitialLoad(); break; case VcpRequestType::RQEndInitialLoad: endInitialLoad(); break; case VcpRequestType::RQCapabilities: capabilities(); break; case VcpRequestType::RQLoadDfr: loadDynamicFeatureRecords(); break; case VcpRequestType::RQHalt: TRACECF(debug, "RQHalt"); delete rqst; return; break; default: cout << "Unexpected request type: " << rqst->_type << endl; } delete rqst; } } ddcui-0.3.0/src/nongui/vcpthread.h000066400000000000000000000055061427175135000170340ustar00rootroot00000000000000/** vcpthread.h * * Thread for executing ddca_ API calls, which can perform I2C IO and so can be * slow. There is one instance of this class, i.e. one thread, for each monitor. */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef VCPTHREAD_H #define VCPTHREAD_H #include #include #include "ddcutil_c_api.h" #include "nongui/ddca_simulator.h" #include "nongui/feature_base_model.h" #include "nongui/vcprequest.h" class QString; class VcpThread : public QThread { public: VcpThread( QObject* parent, DDCA_Display_Info *dinfo, VcpRequestQueue *requestQueue, FeatureBaseModel *baseModel); ~VcpThread(); void run() override; // Perhaps an init function not in the constructor that opens the display? enum FeatureOp { FeatureRead, FeatureWrite, FeatureMetadata }; private: // member functions void getvcp(uint8_t feature_code, bool needMetadata); void setvcp(uint8_t feature_code, bool writeOnly, uint16_t newval); void adjustRetries(); DDCA_Status perform_open_display(DDCA_Display_Handle * dh_loc); DDCA_Status perform_close_display(DDCA_Display_Handle dh); void capabilities(); void loadDynamicFeatureRecords(); void startInitialLoad(void); void endInitialLoad(void); void rpt_feature_error( enum FeatureOp op, uint8_t featureCode, const char * ddcaFuncName, DDCA_Status ddcrc); void rpt_nonfeature_error( const char * action, const char * ddcaFuncName, DDCA_Status ddcrc); void rpt_nonfeature_error( const char * action, const char * ddcaFuncName, DDCA_Status ddcrc, DDCA_Error_Detail * erec); void rpt_verify_error( uint8_t featureCode, const char * function, uint16_t expectedValue, uint16_t observedValue); void rpt_verify_error( uint8_t featureCode, const char * function, uint8_t expectedSh, uint8_t expectedSl, uint8_t observedSh, uint8_t observedSl); private: // member variables const char * _cls = "VcpThread"; //= strdup(metaObject()->className()); DDCA_Display_Ref _dref; DDCA_Display_Info* _dinfo; VcpRequestQueue* _requestQueue = NULL; FeatureBaseModel* _baseModel; DDCA_Display_Handle _dh = NULL; bool _threadDescriptionPublished = false; DdcaSimulator * _ddcaSimulator = NULL; }; #endif // VCPTHREAD_H ddcui-0.3.0/src/option_dialogs/000077500000000000000000000000001427175135000164105ustar00rootroot00000000000000ddcui-0.3.0/src/option_dialogs/feature_selection_dialog.cpp000066400000000000000000000374361427175135000241500ustar00rootroot00000000000000/** @file feature_selection_dialog.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include // for memcmp() #include #include "feature_selection_dialog.h" #include #include #include #include "base/core.h" #include "base/feature_list.h" #include "base/global_state.h" #include "help/help_dialog.h" #include "help/help_browser.h" #include "nongui/msgbox_queue.h" #include "ui_feature_selection_dialog.h" // generated by uic from feature_selection_dialog.ui using namespace std; DDCA_Feature_List FeatureSelectionDialog::validateCustomFeatureList(char * newval) { bool debugFunc = false; DDCA_Feature_List customFlist = DDCA_EMPTY_FEATURE_LIST; TRACECF(debugFunc, "Starting. text: |%s|", newval); char ** error_msgs = NULL; customFlist = parse_custom_feature_list(newval, &error_msgs); assert(!(ddca_feature_list_count(customFlist) > 0 && error_msgs)); if (ddca_feature_list_count(customFlist) == 0) { QString qstitle("Feature Code Error"); QMessageBox::Icon icon = QMessageBox::Critical; MsgBoxQueue * msgboxQueue = GlobalState::instance()._mainWindow->_msgBoxQueue; if (error_msgs) { TRACECF(debugFunc, "Calling msgboxQueue->putMessages()"); msgboxQueue->putMessages(qstitle, icon, error_msgs); ntsa_free(error_msgs, true); } else { QString qsexpl("No custom features specified"); MsgBoxQueueEntry * qe = new MsgBoxQueueEntry(qstitle,qsexpl,icon); TRACECF(debugFunc, "Calling msgboxQueue->put() for qe: %s", QS2S(qe->repr())); msgboxQueue->put(qe); } } // feature_list_count == 0 const char * s = ddca_feature_list_string(customFlist, "x", ","); TRACECF(debugFunc, "Done. Returning custom feature list: %s", s); return customFlist; } void FeatureSelectionDialog::useSelectorData(FeatureSelector * fsel) { bool debugFunc = false; debugFunc = debugFunc || debugFeatureSelection; if (debugFunc) { TRACEC("Setting dialog box widgets from FeatureSelector:"); fsel->dbgrpt(); } QRadioButton * curButton; // switch is exhaustive, so curButton is always assigned, however -Wmaybe-uninitialized // flags the curButton->setChecked() line Assign a dummy value to quiet the warning curButton = _ui->known_radioButton; // dummy value DDCA_Feature_Subset_Id local_fsid = fsel->_featureSubsetId; switch(local_fsid) { case DDCA_SUBSET_KNOWN: curButton = _ui->known_radioButton; _ui->custom_lineEdit->setEnabled(false); _ui->allCapabilities_checkbox->setEnabled(true); _ui->onlyCapabilities_checkbox->setEnabled(true); break; case DDCA_SUBSET_COLOR: curButton = _ui->color_radioButton; _ui->custom_lineEdit->setEnabled(false); _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); break; case DDCA_SUBSET_PROFILE: // removed from dialog, case left to satisfy that all cases addressed // curButton = _ui->profile_radioButton; assert(false); break; case DDCA_SUBSET_MFG: curButton = _ui->mfg_radioButton; _ui->custom_lineEdit->setEnabled(false); _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); break; case DDCA_SUBSET_CAPABILITIES: curButton = _ui->capabilities_radioButton; _ui->custom_lineEdit->setEnabled(false); _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(false); break; case DDCA_SUBSET_SCAN: curButton = _ui->scan_radioButton; _ui->custom_lineEdit->setEnabled(false); _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(false); break; case DDCA_SUBSET_CUSTOM: { curButton = _ui->custom_radioButton; const char * s = ddca_feature_list_string(fsel->_customFeatureList, "x", " "); _ui->custom_lineEdit->setText( s); _ui->custom_lineEdit->setEnabled(true); _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); } break; case DDCA_SUBSET_UNSET: assert(false); break; } _ui->showUnsupported_checkbox->setEnabled(true); // true for all feature sets curButton->setChecked(true); // to do: enable/disable other buttons as appropriate if (debugFunc) { TRACEC("fsel before setting flag checkboxes:"); fsel->dbgrpt(); } _ui->includeTable_checkbox->setChecked( fsel->_includeTableFeatures); _ui->showUnsupported_checkbox->setChecked( fsel->_showUnsupportedFeatures); _ui->onlyCapabilities_checkbox->setChecked(fsel->_includeOnlyCapabilities); _ui->allCapabilities_checkbox->setChecked( fsel->_includeAllCapabilities); TRACECF(debugFunc, "Done. _ui->custom_lineEdit->isEnabled() = %s", SBOOL(_ui->custom_lineEdit->isEnabled()) ); } void FeatureSelectionDialog::useSelectorData() { useSelectorData(_featureSelector); } FeatureSelectionDialog::FeatureSelectionDialog( QWidget * parent, FeatureSelector * featureSelector ) : QDialog(parent) , _cls(strdup(metaObject()->className())) , _ui(new Ui::FeatureSelectionDialog) , _featureSelector(featureSelector) { // TRACE("_ui=%p, _featureSelector = %p\n", _ui, _featureSelector); _ui->setupUi(this); setWindowFlag(Qt::WindowContextHelpButtonHint, false); #ifdef NO this->setContextMenuPolicy(Qt::PreventContextMenu); Qt::WindowFlags flags = windowFlags(); flags &= ~Qt::WindowContextHelpButtonHint; flags &= ~Qt::WindowMaximizeButtonHint; flags &= ~Qt::WindowMinMaxButtonsHint; flags |= Qt::CustomizeWindowHint; // = Qt::Dialog | // Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | // Qt::WindowCloseButtonHint; setWindowFlags(flags); #endif QObject::connect(_ui->known_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_known_radioButton_clicked); QObject::connect(_ui->capabilities_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_capabilities_radioButton_clicked); QObject::connect(_ui->mfg_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_mfg_radioButton_clicked); QObject::connect(_ui->color_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_color_radioButton_clicked); QObject::connect(_ui->scan_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_scan_radioButton_clicked); QObject::connect(_ui->custom_radioButton, &QAbstractButton::clicked, this, &FeatureSelectionDialog::on_custom_radioButton_clicked); // QObject::connect(_ui->custom_lineEdit, &QLineEdit::returnPressed, // this, &FeatureSelectionDialog::on_custom_lineEdit_returnPressed ); // QObject::connect(_ui->custom_lineEdit, &QLineEdit::editingFinished, // this, &FeatureSelectionDialog::on_custom_lineEdit_editingFinished ); // QObject::connect(_ui->custom_lineEdit, &QLineEdit::textEdited, // this, &FeatureSelectionDialog::on_custom_lineEdit_textEdited ); // closes only this dialog box, not the application // QShortcut * quit_shortcut = // new QShortcut(QKeySequence(Qt::Key_Q | Qt::CTRL), // parent, // SLOT(close())); useSelectorData(_featureSelector); } FeatureSelectionDialog::~FeatureSelectionDialog() { delete _ui; free((void*) _cls); } // // Radio Buttons // void FeatureSelectionDialog::on_known_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(true); _ui->onlyCapabilities_checkbox->setEnabled(true); _ui->custom_lineEdit->setEnabled(false); } void FeatureSelectionDialog::on_capabilities_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(false); _ui->allCapabilities_checkbox->setChecked(false); _ui->onlyCapabilities_checkbox->setChecked(false); _ui->custom_lineEdit->setEnabled(false); } void FeatureSelectionDialog::on_mfg_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); _ui->allCapabilities_checkbox->setChecked(false); _ui->custom_lineEdit->setEnabled(false); } void FeatureSelectionDialog::on_color_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); _ui->allCapabilities_checkbox->setChecked(false); _ui->custom_lineEdit->setEnabled(false); } #ifdef NO_PROFILE_BUTTON void FeatureSelectionDialog::on_profile_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(true); _ui->allCapabilities_checkbox->setChecked(false); } #endif void FeatureSelectionDialog::on_scan_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->onlyCapabilities_checkbox->setEnabled(false); _ui->allCapabilities_checkbox->setChecked(false); _ui->onlyCapabilities_checkbox->setChecked(false); _ui->custom_lineEdit->setEnabled(false); } void FeatureSelectionDialog::on_custom_radioButton_clicked(bool checked) { _ui->allCapabilities_checkbox->setEnabled(false); _ui->allCapabilities_checkbox->setChecked(false); _ui->onlyCapabilities_checkbox->setEnabled(true); _ui->onlyCapabilities_checkbox->setChecked(false); _ui->custom_lineEdit->setEnabled(true); // move cursor to custom_lineEdit _ui->custom_lineEdit->setFocus(Qt::OtherFocusReason); } // // Checkboxes // void FeatureSelectionDialog::on_onlyCapabilities_checkbox_stateChanged(int arg1) { // cout << "(on_onlyCapabilities_checkBox_stateChanged) arg1 = " << arg1 << endl; if (_ui->onlyCapabilities_checkbox->isChecked() ) { // or != 0 _ui->allCapabilities_checkbox->setCheckState(Qt::Unchecked); } } void FeatureSelectionDialog::on_allCapabilities_checkbox_stateChanged(int arg1) { // cout << "(on_allCapabilities_checkBox_stateChanged) arg1 = " << arg1 << endl; if (arg1 == 2) { _ui->onlyCapabilities_checkbox->setCheckState(Qt::Unchecked); } } // // Button Box buttons // // Accept void FeatureSelectionDialog::on_buttonBox_accepted() { bool debug = false; debug = debug || debugFeatureSelection; TRACECF(debug, "Starting."); DDCA_Feature_List customFlist = DDCA_EMPTY_FEATURE_LIST; DDCA_Feature_Subset_Id fsid = DDCA_SUBSET_UNSET; // assignment to avoid warning re uninitialized var // Which feature selection button is currently checked? if (_ui->color_radioButton->isChecked()) fsid = DDCA_SUBSET_COLOR; else if (_ui->known_radioButton->isChecked()) fsid = DDCA_SUBSET_KNOWN; else if (_ui->mfg_radioButton->isChecked()) fsid = DDCA_SUBSET_MFG; #ifdef NO_PROFILE_BUTTON else if (_ui->profile_radioButton->isChecked()) fsid = DDCA_SUBSET_PROFILE; #endif else if (_ui->capabilities_radioButton->isChecked()) fsid = DDCA_SUBSET_CAPABILITIES; else if (_ui->scan_radioButton->isChecked()) fsid = DDCA_SUBSET_SCAN; // Custom radio button else if (_ui->custom_radioButton->isChecked()) { fsid = DDCA_SUBSET_CUSTOM; QString text = _ui->custom_lineEdit->text().trimmed(); TRACECF(debug, "custom radioButton: text: |%s|", QS2S(text)); customFlist = validateCustomFeatureList(QS2S(text)); if (ddca_feature_list_count(customFlist) == 0) { TRACECF(debug, "Custom feature error, returning"); return; // there's a custom feature error, don't exit dialog } TRACECF(debug, "custom feature list: %s", ddca_feature_list_string(customFlist, "x", ", ") ); } // custom_radioButton else // no radio button checked assert(false); // should never occur // end, custom radio button assert(fsid != DDCA_SUBSET_UNSET); TRACECF(debug, "Checking for any changes...fsid=%d, _featureSelector->featureSubsetId = %d", fsid, _featureSelector->_featureSubsetId); bool changed = false; if (fsid != _featureSelector->_featureSubsetId) { _featureSelector->_featureSubsetId = fsid; _featureSelector->_customFeatureList = customFlist; changed = true; TRACECF(debug,"feature set changed"); } else if (fsid == DDCA_SUBSET_CUSTOM) { DDCA_Feature_List old_flist = _featureSelector->_customFeatureList; if (!ddca_feature_list_eq(customFlist, old_flist)) { _featureSelector->_customFeatureList = customFlist; changed = true; } } if (_ui->includeTable_checkbox->isChecked() != _featureSelector->_includeTableFeatures) { _featureSelector->_includeTableFeatures = _ui->includeTable_checkbox->isChecked(); changed = true; } if (_featureSelector->_showUnsupportedFeatures !=_ui->showUnsupported_checkbox->isChecked()) { _featureSelector->_showUnsupportedFeatures = _ui->showUnsupported_checkbox->isChecked(); changed = true; } if (_featureSelector->_includeOnlyCapabilities != _ui->onlyCapabilities_checkbox->isChecked() ) { _featureSelector->_includeOnlyCapabilities = _ui->onlyCapabilities_checkbox->isChecked(); changed = true; } if (_featureSelector->_includeAllCapabilities != _ui->allCapabilities_checkbox->isChecked() ) { _featureSelector->_includeAllCapabilities = _ui->allCapabilities_checkbox->isChecked(); changed = true; } if (_featureSelector->_showUnsupportedFeatures != _ui->showUnsupported_checkbox->isChecked() ) { _featureSelector->_showUnsupportedFeatures = _ui->showUnsupported_checkbox->isChecked(); changed = true; } if (_featureSelector->_includeTableFeatures != _ui->includeTable_checkbox->isChecked() ) { _featureSelector->_includeTableFeatures = _ui->includeTable_checkbox->isChecked(); changed = true; } if (debug) { TRACEC("_feature_selector:"); _featureSelector->dbgrpt(); } if (changed) { TRACECF(debug, "Signaling featureSelectionChanged()"); emit featureSelectionChanged(); // emit featureSelectionAccepted(fsid); } else { TRACECF(debug, "NOT Signaling featureSelectionChanged()"); } accept(); } // Reset void FeatureSelectionDialog::on_buttonBox_clicked(QAbstractButton* button) { if(button == (QAbstractButton*) _ui->buttonBox->button(QDialogButtonBox::Reset) ){ // TRACE("Reset"); FeatureSelector * defaultSelector = new FeatureSelector; useSelectorData(defaultSelector); delete defaultSelector; } } // Help void FeatureSelectionDialog::on_buttonBox_helpRequested() { // TRACE(); // QString fn(":/docs/feature_selection.html"); // QString fn("qrc:docs/help_feature_selection.html"); // QFile f(fn); // f.open(QFile::ReadOnly | QFile::Text); // QTextStream in(&f); // QString htmlText = in.readAll(); // qDebug() << htmlText; // HelpDialog2(htmlText, this); // HelpDialog2* hd = new HelpDialog2(this); // hd->setText(htmlText); // hd->setSource(fn); // hd->setWindowTitle("ddcui Help - Feature Selection"); // hd->show(); // HelpBrowser::showPage(fn, false); HelpDialog* hd = new HelpDialog(this); hd->setSource("qrc:docs/help_feature_selection.html"); hd->exec(); } ddcui-0.3.0/src/option_dialogs/feature_selection_dialog.h000066400000000000000000000033731427175135000236060ustar00rootroot00000000000000/** feature_selection_dialog.h */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef FEATURESELECTIONDIALOG_H #define FEATURESELECTIONDIALOG_H #include #include #include #include "base/feature_selector.h" namespace Ui { class FeatureSelectionDialog; } class FeatureSelectionDialog : public QDialog { Q_OBJECT public: explicit FeatureSelectionDialog(QWidget *parent,FeatureSelector* featureSelector); ~FeatureSelectionDialog(); void useSelectorData(FeatureSelector * fsel); void useSelectorData(); signals: // void featureSelectionAccepted(DDCA_Feature_Subset_Id feature_list); void featureSelectionChanged(); private slots: void on_buttonBox_accepted(); void on_buttonBox_helpRequested(); void on_buttonBox_clicked(QAbstractButton* button); void on_known_radioButton_clicked(bool checked); void on_capabilities_radioButton_clicked(bool checked); void on_mfg_radioButton_clicked(bool checked); void on_color_radioButton_clicked(bool checked); void on_scan_radioButton_clicked(bool checked); void on_custom_radioButton_clicked(bool checked); void on_allCapabilities_checkbox_stateChanged(int arg1); void on_onlyCapabilities_checkbox_stateChanged(int arg1); // void on_showUnsupported_checkbox_stateChanged(int arg1); // not needed private: // methods DDCA_Feature_List validateCustomFeatureList(char *); private: // member variables // keep in order for constructor initializers char * _cls; Ui::FeatureSelectionDialog* _ui; FeatureSelector* _featureSelector; }; #endif // FEATURESELECTIONDIALOG_H ddcui-0.3.0/src/option_dialogs/feature_selection_dialog.ui000066400000000000000000000172371427175135000240000ustar00rootroot00000000000000 FeatureSelectionDialog 0 0 584 443 ddcui - Feature Selection 30 370 341 61 10 Qt::StrongFocus Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset true 30 20 171 31 14 <html><head/><body><p><span style=" font-size:12pt;">Feature Groups</span></p></body></html> 40 50 511 166 3 true 10 50 false false <html><head/><body><p>This is whats this text</p></body></html> CAPABILITIES - Features specified in the capabilities string true 0 23 10 50 false false <html><head/><body><p>This is tooltip text</p></body></html> &MCCS - Features defined in the Monitor Control Command Set 10 SCAN - All possible feature codes 10 &MANUFACTURER - Manufacturer specific features 10 COLOR - Color related features 10 CUSTOM 30 220 171 31 14 <html><head/><body><p><span style=" font-size:12pt;">Feature Filters</span></p></body></html> 40 260 313 22 10 Include all features in the capabilities string 40 290 313 23 10 Include only features in the capabilities string true 40 320 313 20 10 false Show unsupported features true false 40 350 313 23 10 false Include Table type features false buttonBox rejected() FeatureSelectionDialog reject() 316 260 286 274 ddcui-0.3.0/src/option_dialogs/nc_values_dialog.cpp000066400000000000000000000054341427175135000224200ustar00rootroot00000000000000/** @file nc_values_dialog.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "nc_values_dialog.h" #include #include #include "base/core.h" #include "help/help_dialog.h" #include "help/help_browser.h" #include "ui_nc_values_dialog.h" // generated by UIC void NcValuesDialog::setUiSource(NcValuesSource source) { bool debugFunc = false; TRACEMF(debugFunc, "Executing. source=%d=%s", source, ncValuesSourceName(source) ); switch(source) { case NcValuesFromCapabilities: ui->capabilitiesNcValuesButton->setChecked(true); break; case NcValuesFromMccs: ui->mccsNcValuesButton->setChecked(true); break; case NcValuesFromBoth: ui->bothNcValuesButton->setChecked(true); break; } } // void OtherOptionsDialog::setUseLatestNcValueNames(bool newval) { // ui->latestNcValueNamesCheckbox->setChecked(newval); // } NcValuesDialog::NcValuesDialog(NcValuesState * state, QWidget *parent) : QDialog(parent), ui(new Ui::NcValuesDialog), _cls( strdup(metaObject()->className()) ), _state(state) { ui->setupUi(this); // this->setContextMenuPolicy(Qt::PreventContextMenu); setWindowFlag(Qt::WindowContextHelpButtonHint, false); setWindowTitle("ddcui - NC Feature Values"); setUiSource(state->_ncValuesSource); // setUseLatestNcValueNames(state->_useLatestNcValues); } NcValuesDialog::~NcValuesDialog() { delete ui; free((void*) _cls); } void NcValuesDialog::on_buttonBox_accepted() { // NcValuesSource oldsrc = _state->_ncValuesSource; // bool oldUseLatestNames = _state->_useLatestNcValueNames; #ifdef UNUSED NcValuesSource newsrc; if (ui->capabilitiesNcValuesButton->isChecked() ) newsrc = NcValuesFromCapabilities; else if (ui->bothNcValuesButton->isChecked() ) newsrc = NcValuesFromBoth; else { assert( ui->mccsNcValuesButton->isChecked() ); newsrc = NcValuesFromMccs; } #endif // _state->changeNcValuesSource(newsrc, ui->latestNcValueNamesCheckbox->isChecked()); } void NcValuesDialog::on_buttonBox_helpRequested() { // TRACEC("Starting"); // viewHelp(QString("nc_values.html"), QString("ddcui Help -X Other Options"), this); // HelpBrowser::showPage("qrc:docs/help_nc_values.html", false); HelpDialog* hd = new HelpDialog(this); hd->setSource("qrc:docs/help_nc_values.html"); hd->exec(); } // Reset void NcValuesDialog::on_buttonBox_clicked(QAbstractButton* button) { if(button== (QAbstractButton*) ui->buttonBox->button(QDialogButtonBox::Reset) ){ // TRACE("Reset"); setUiSource(NcValuesState::DefaultNcValuesSource); // setUseLatestNcValueNames(OtherOptionsState::DefaultUseMaximalMccsNcValues); } } ddcui-0.3.0/src/option_dialogs/nc_values_dialog.h000066400000000000000000000017231427175135000220620ustar00rootroot00000000000000/** @file nc_values_dialog.h */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef OTHER_OPTIONS_DIALOG_H #define OTHER_OPTIONS_DIALOG_H #include #include #include "base/nc_values_state.h" namespace Ui { class NcValuesDialog; } class NcValuesDialog : public QDialog { Q_OBJECT public: explicit NcValuesDialog(NcValuesState * state, QWidget *parent = 0); ~NcValuesDialog(); signals: void ncValuesSourceChanged(NcValuesSource valuesSource, bool useLatestNcValueNames); private slots: void on_buttonBox_accepted(); void on_buttonBox_helpRequested(); void on_buttonBox_clicked(QAbstractButton* button); private: void setUiSource(NcValuesSource source); // void setUseLatestNcValueNames(bool newval); const char * _cls; Ui::NcValuesDialog *ui; NcValuesState * _state; }; #endif // OTHER_OPTIONS_DIALOG_H ddcui-0.3.0/src/option_dialogs/nc_values_dialog.ui000066400000000000000000000104361427175135000222510ustar00rootroot00000000000000 NcValuesDialog Qt::ApplicationModal 0 0 477 165 Qt::NoContextMenu Dialog true 20 110 341 32 10 Qt::StrongFocus Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset false 20 30 311 22 10 List of valid values are taken from the MCCS specification &Monitor Control Command Set ncValueSourceButtonGroup 20 50 291 22 10 List of valid values taken from the capabilities string, names of valid values taken from MCCS spec &Capabilities String ncValueSourceButtonGroup 20 10 441 18 Source of Non-Continuous Feature Values: 20 70 261 22 10 Valid values are those either in the MCCS spec or the capabilities string Both &MCCS and Capabilities ncValueSourceButtonGroup buttonBox accepted() NcValuesDialog accept() 248 254 157 274 buttonBox rejected() NcValuesDialog reject() 316 260 286 274 ddcui-0.3.0/src/option_dialogs/user_interface_options_dialog.cpp000066400000000000000000000067211427175135000252120ustar00rootroot00000000000000/** @file user_interface_options_dialog.cpp */ // Copyright (C) 2018-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #include "user_interface_options_dialog.h" // generated by uic from userInterfaceOptions_ui.ui: #include "ui_user_interface_options_dialog.h" #include #include #include "base/core.h" #include "base/user_interface_options_state.h" #include "help/help_dialog.h" #include "help/help_browser.h" void UserInterfaceOptionsDialog::setCkrChanged(bool required) { _ui->ckrCheckBox->setChecked(required); } UserInterfaceOptionsDialog::UserInterfaceOptionsDialog( UserInterfaceOptionsState * state, QWidget *parent) : QDialog(parent) , _ui(new Ui:: UserInterfaceOptionsDialog) , _cls(strdup(metaObject()->className())) , _state(state) { bool debug = false; TRACECF(debug, "Constructor starting"); _ui->setupUi(this); setWindowFlag(Qt::WindowContextHelpButtonHint, false); // setWindowFlag(Qt::WindowMaximizeButtonHint, false); // no effect setWindowTitle("ddcui - User Interface Options"); // setUSource(state->ncValuesSource); TRACECF(debug, "Constructor done"); } UserInterfaceOptionsDialog::~UserInterfaceOptionsDialog() { delete _ui; free((void*) _cls); } void UserInterfaceOptionsDialog::setDialogBoxControlKeyRequired(bool onoff) { Qt::CheckState stateToSet = Qt::Unchecked; if (onoff) stateToSet = Qt::Checked; _ui->ckrCheckBox->setChecked(stateToSet); } void UserInterfaceOptionsDialog::on_actionButtonBox_accepted() { bool debugFunc = false; bool newCtrlKeyRequired = _ui->ckrCheckBox->isChecked(); TRACECF(debugFunc, "Executing. Value read from ckr checkbox; %s", SBOOL(newCtrlKeyRequired)); TRACECF(debugFunc, "Calling _state->setControlKey_Required(%s)", SBOOL(newCtrlKeyRequired)); _state->setControlKeyRequired(newCtrlKeyRequired); // not needed, automatically emitted when dialog accepted, by accept() or done() // emit userInterfaceDialog_accepted(_state); // probably not needed TRACECF(debugFunc, "Before calling accept()"); accept(); // causes accepted() to be emitted } void UserInterfaceOptionsDialog::on_actionButtonBox_helpRequested() { // TRACE(); #ifdef OLD QString fn(":/docs/help_ui_options.html"); QFile f(fn); f.open(QFile::ReadOnly | QFile::Text); QTextStream in(&f); QString htmlText = in.readAll(); // qDebug() << htmlText; // doesn't show dialog box // HelpDialog2("ddcui Help - Other Options", htmlText, this); HelpDialog2* hd = new HelpDialog2(this); hd->setText(htmlText); hd->setWindowTitle("ddcui Help - User Interface Options"); hd->show(); #else // HelpBrowser::showPage(":docs/help_ui_options.html", false); HelpDialog* hd = new HelpDialog(this); hd->setSource("qrc:docs/help_ui_options.html"); hd->exec(); #endif } // Reset void UserInterfaceOptionsDialog::on_actionButtonBox_clicked(QAbstractButton* button) { if(button== (QAbstractButton*) _ui->actionButtonBox->button(QDialogButtonBox::Reset) ){ // TRACEC("Reset"); // Pressing the reset button does not close the dialog box // Reset the state in UserInterfaceOptionsState // Do not emit a changed() message and do not close the dialog _state->_controlKeyRequired = UserInterfaceOptionsState::CkrDefault; setDialogBoxControlKeyRequired(UserInterfaceOptionsState::CkrDefault); } } ddcui-0.3.0/src/option_dialogs/user_interface_options_dialog.h000066400000000000000000000023641427175135000246560ustar00rootroot00000000000000// user_interface_options_dialog.h // Copyright (C) 2019-2022 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef USER_INTERFACE_OPTIONS_DIALOG_H #define USER_INTERFACE_OPTIONS_DIALOG_H #include #include #include "base/user_interface_options_state.h" namespace Ui { class UserInterfaceOptionsDialog; } class UserInterfaceOptionsDialog : public QDialog { Q_OBJECT public: explicit UserInterfaceOptionsDialog(UserInterfaceOptionsState * state, QWidget *parent = 0); ~UserInterfaceOptionsDialog(); void setCkrChanged(bool onoff); void setDialogBoxControlKeyRequired(bool onoff); signals: void ckrChanged(bool onoff); void userInterfaceDialog_accepted(UserInterfaceOptionsState * state); public: Ui::UserInterfaceOptionsDialog * _ui; // why is this pointing to another instance of the same class? private slots: void on_actionButtonBox_accepted(); void on_actionButtonBox_helpRequested(); void on_actionButtonBox_clicked(QAbstractButton* button); private: const char * _cls; // void setUiSource(NcValuesSource source); UserInterfaceOptionsState * _state; }; #endif // USER_INTERFACE_OPTIONS_DIALOG_H ddcui-0.3.0/src/option_dialogs/user_interface_options_dialog.ui000066400000000000000000000043651427175135000250470ustar00rootroot00000000000000 UserInterfaceOptionsDialog Qt::ApplicationModal 0 0 400 108 Dialog true 10 50 341 32 10 Qt::StrongFocus Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset true 20 20 311 22 Require control key to change values actionButtonBox accepted() UserInterfaceOptionsDialog accept() 248 254 157 274 actionButtonBox rejected() UserInterfaceOptionsDialog reject() 316 260 286 274 ddcui-0.3.0/validate_CMAKE_BUILD_TYPE.cmake000066400000000000000000000042311427175135000200620ustar00rootroot00000000000000# Validates CMAKE_BUILD_TYPE message(STATUS "Initial CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") set(valid_build_types Release RelWithDebInfo Debug MinSizeRel) string(TOUPPER "${valid_build_types}" uc_valid_build_types) string(REPLACE ";" ", " pretty_valid_build_types "${valid_build_types}") STRING(TOUPPER "${CMAKE_BUILD_TYPE}" UC_CMAKE_BUILD_TYPE ) # message(STATUS "valid_build_types: |${valid_build_types}|") # message(STATUS "uc_valid_build_types: |${uc_valid_build_types}|") # For some reason, cmake gets called with -DCMAKE_BUILD_TYPE=None by dh_autoconfigure # This hack handles that. if ( "${UC_CMAKE_BUILD_TYPE}" STREQUAL "NONE" ) message(STATUS "Treating CMAKE_BUILD_TYPE == None as CMAKE_BUILD_TYPE == ''") set(CMAKE_BUILD_TYPE "") endif() # https://cmake.org/pipermail/cmake/2008-September/023808.html # If the user specifies -DCMAKE_BUILD_TYPE on the command line, take their # definition and dump it in the cache along with proper documentation, # otherwise set CMAKE_BUILD_TYPE to the default prior to calling project() set(i0 0) if (DEFINED CMAKE_BUILD_TYPE) string(LENGTH "${CMAKE_BUILD_TYPE}" i0) endif() IF( i0 GREATER 0 ) list(FIND uc_valid_build_types "${UC_CMAKE_BUILD_TYPE}" index) if (index EQUAL -1) message(FATAL_ERROR "CMAKE_BUILD_TYPE must be one of ${pretty_valid_build_types}" ) endif() # message(STATUS "index=${index}") list(GET valid_build_types ${index} CMAKE_BUILD_TYPE) # message(STATUS "Setting CMakeCache.txt value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: ${pretty_valid_build_types}." FORCE) else() set(CMAKE_BUILD_TYPE ${cmake_build_type_default}) endif() # Set the possible values of build type for cmake-gui # set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Release" "Debug" "RelWithDebInfo" "MinSizeRel") # see also: https://stackoverflow.com/questions/48754619/what-are-cmake-build-type-debug-release-relwithdebinfo-and-minsizerel # https://blog.feabhas.com/2021/07/cmake-part-2-release-and-debug-builds/ message(STATUS "Final CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")